PageSourceSearch

https://enquete.ndl.go.jp/tmp/assets/e7d0ed65/scripts/bootstrap-slider.js

js ndl.go.jp collected 2026-09-24 06:42:01 UTC 52,291 bytes, 1,605 lines download raw bytes

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 * Licensed under the Apache License, Version 2.0 (the "License");
15 * you may not use this file except in compliance with the License.
16 * You may obtain a copy of the License at
17 *
18 * http://www.apache.org/licenses/LICENSE-2.0
19 *
20 * Unless required by applicable law or agreed to in writing, software
21 * distributed under the License is distributed on an "AS IS" BASIS,
22 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
23 * See the License for the specific language governing permissions and
24 * limitations under the License.
25 * ========================================================= */
26
27
28/**
29 * Bridget makes jQuery widgets
30 * v1.0.1
31 * MIT license
32 */
33
34(function(factory) {
35	if(typeof define === "function" && define.amd) {
36		define(["jquery"], factory);
37	}
38	else if(typeof module === "object" && module.exports) {
39		var jQuery;
40		try {
41			jQuery = require("jquery");
42		}
43		catch (err) {
44			jQuery = null;
45		}
46		module.exports = factory(jQuery);
47	}
48	else if(window) {
49		window.Slider = factory(window.jQuery);
50	}
51}(function($) {
52	// Reference to Slider constructor
53	var Slider;
54
55
56	(function( $ ) {
57
58		'use strict';
59
60		// -------------------------- utils -------------------------- //
61
62		var slice = Array.prototype.slice;
63
64		function noop() {}
65
66		// -------------------------- definition -------------------------- //
67
68		function defineBridget( $ ) {
69
70			// bail if no jQuery
71			if ( !$ ) {
72				return;
73			}
74
75			// -------------------------- addOptionMethod -------------------------- //
76
77			/**
78			 * adds option method -> $().plugin('option', {...})
79			 * @param {Function} PluginClass - constructor class
80			 */
81			function addOptionMethod( PluginClass ) {
82				// don't overwrite original option method
83				if ( PluginClass.prototype.option ) {
84					return;
85				}
86
87			  // option setter
88			  PluginClass.prototype.option = function( opts ) {
89			    // bail out if not an object
90			    if ( !$.isPlainObject( opts ) ){
91			      return;
92			    }
93			    this.options = $.extend( true, this.options, opts );
94			  };
95			}
96
97
98			// -------------------------- plugin bridge -------------------------- //
99
100			// helper function for logging errors
101			// $.error breaks jQuery chaining
102			var logError = typeof console === 'undefined' ? noop :
103			  function( message ) {
104			    console.error( message );
105			  };
106
107			/**
108			 * jQuery plugin bridge, access methods like $elem.plugin('method')
109			 * @param {String} namespace - plugin name
110			 * @param {Function} PluginClass - constructor class
111			 */
112			function bridge( namespace, PluginClass ) {
113			  // add to jQuery fn namespace
114			  $.fn[ namespace ] = function( options ) {
115			    if ( typeof options === 'string' ) {
116			      // call plugin method when first argument is a string
117			      // get arguments for method
118			      var args = slice.call( arguments, 1 );
119
120			      for ( var i=0, len = this.length; i < len; i++ ) {
121			        var elem = this[i];
122			        var instance = $.data( elem, namespace );
123			        if ( !instance ) {
124			          logError( "cannot call methods on " + namespace + " prior to initialization; " +
125			            "attempted to call '" + options + "'" );
126			          continue;
127			        }
128			        if ( !$.isFunction( instance[options] ) || options.charAt(0) === '_' ) {
129			          logError( "no such method '" + options + "' for " + namespace + " instance" );
130			          continue;
131			        }
132
133			        // trigger method with arguments
134			        var returnValue = instance[ options ].apply( instance, args);
135
136			        // break look and return first value if provided
137			        if ( returnValue !== undefined && returnValue !== instance) {
138			          return returnValue;
139			        }
140			      }
141			      // return this if no return value
142			      return this;
143			    } else {
144			      var objects = this.map( function() {
145			        var instance = $.data( this, namespace );
146			        if ( instance ) {
147			          // apply options & init
148			          instance.option( options );
149			          instance._init();
150			        } else {
151			          // initialize new instance
152			          instance = new PluginClass( this, options );
153			          $.data( this, namespace, instance );
154			        }
155			        return $(this);
156			      });
157
158			      if(!objects || objects.length > 1) {
159			      	return objects;
160			      } else {
161			      	return objects[0];
162			      }
163			    }
164			  };
165
166			}
167
168			// -------------------------- bridget -------------------------- //
169
170			/**
171			 * converts a Prototypical class into a proper jQuery plugin
172			 *   the class must have a ._init method
173			 * @param {String} namespace - plugin name, used in $().pluginName
174			 * @param {Function} PluginClass - constructor class
175			 */
176			$.bridget = function( namespace, PluginClass ) {
177			  addOptionMethod( PluginClass );
178			  bridge( namespace, PluginClass );
179			};
180
181			return $.bridget;
182
183		}
184
185	  	// get jquery from browser global
186	  	defineBridget( $ );
187
188	})( $ );
189
190
191	/*************************************************
192
193			BOOTSTRAP-SLIDER SOURCE CODE
194
195	**************************************************/
196
197	(function($) {
198
199		var ErrorMsgs = {
200			formatInvalidInputErrorMsg : function(input) {
201				return "Invalid input value '" + input + "' passed in";
202			},
203			callingContextNotSliderInstance : "Calling context element does not have instance of Slider bound to it. Check your code to make sure the JQuery object returned from the call to the slider() initializer is calling the method"
204		};
205
206		var SliderScale = {
207			linear: {
208				toValue: function(percentage) {
209					var rawValue = percentage/100 * (this.options.max - this.options.min);
210					var shouldAdjustWithBase = true;
211					if (this.options.ticks_positions.length > 0) {
212						var minv, maxv, minp, maxp = 0;
213						for (var i = 1; i < this.options.ticks_positions.length; i++) {
214							if (percentage <= this.options.ticks_positions[i]) {
215								minv = this.options.ticks[i-1];
216								minp = this.options.ticks_positions[i-1];
217								maxv = this.options.ticks[i];
218								maxp = this.options.ticks_positions[i];
219
220								break;
221							}
222						}
223						var partialPercentage = (percentage - minp) / (maxp - minp);
224						rawValue = minv + partialPercentage * (maxv - minv);
225						shouldAdjustWithBase = false;
226					}
227
228					var adjustment = shouldAdjustWithBase ? this.options.min : 0;
229					var value = adjustment + Math.round(rawValue / this.options.step) * this.options.step;
230					if (value < this.options.min) {
231						return this.options.min;
232					} else if (value > this.options.max) {
233						return this.options.max;
234					} else {
235						return value;
236					}
237				},
238				toPercentage: function(value) {
239					if (this.options.max === this.options.min) {
240						return 0;
241					}
242
243					if (this.options.ticks_positions.length > 0) {
244						var minv, maxv, minp, maxp = 0;
245						for (var i = 0; i < this.options.ticks.length; i++) {
246							if (value  <= this.options.ticks[i]) {
247								minv = (i > 0) ? this.options.ticks[i-1] : 0;
248								minp = (i > 0) ? this.options.ticks_positions[i-1] : 0;
249								maxv = this.options.ticks[i];
250								maxp = this.options.ticks_positions[i];
251
252								break;
253							}
254						}
255						if (i > 0) {
256							var partialPercentage = (value - minv) / (maxv - minv);
257							return minp + partialPercentage * (maxp - minp);
258						}
259					}
260
261					return 100 * (value - this.options.min) / (this.options.max - this.options.min);
262				}
263			},
264
265			logarithmic: {
266				/* Based on http://stackoverflow.com/questions/846221/logarithmic-slider */
267				toValue: function(percentage) {
268					var min = (this.options.min === 0) ? 0 : Math.log(this.options.min);
269					var max = Math.log(this.options.max);
270					var value = Math.exp(min + (max - min) * percentage / 100);
271					value = this.options.min + Math.round((value - this.options.min) / this.options.step) * this.options.step;
272					/* Rounding to the nearest step could exceed the min or
273					 * max, so clip to those values. */
274					if (value < this.options.min) {
275						return this.options.min;
276					} else if (value > this.options.max) {
277						return this.options.max;
278					} else {
279						return value;
280					}
281				},
282				toPercentage: function(value) {
283					if (this.options.max === this.options.min) {
284						return 0;
285					} else {
286						var max = Math.log(this.options.max);
287						var min = this.options.min === 0 ? 0 : Math.log(this.options.min);
288						var v = value === 0 ? 0 : Math.log(value);
289						return 100 * (v - min) / (max - min);
290					}
291				}
292			}
293		};
294
295
296		/*************************************************
297
298							CONSTRUCTOR
299
300		**************************************************/
301		Slider = function(element, options) {
302			createNewSlider.call(this, element, options);
303			return this;
304		};
305
306		function createNewSlider(element, options) {
307
308			/*
309				The internal state object is used to store data about the current 'state' of slider.
310
311				This includes values such as the `value`, `enabled`, etc...
312			*/
313			this._state = {
314				value: null,
315				enabled: null,
316				offset: null,
317				size: null,
318				percentage: null,
319				inDrag: false,
320				over: false
321			};
322
323
324			if(typeof element === "string") {
325				this.element = document.querySelector(element);
326			} else if(element instanceof HTMLElement) {
327				this.element = element;
328			}
329
330			/*************************************************
331
332							Process Options
333
334			**************************************************/
335			options = options ? options : {};
336			var optionTypes = Object.keys(this.defaultOptions);
337
338			for(var i = 0; i < optionTypes.length; i++) {
339				var optName = optionTypes[i];
340
341				// First check if an option was passed in via the constructor
342				var val = options[optName];
343				// If no data attrib, then check data atrributes
344				val = (typeof val !== 'undefined') ? val : getDataAttrib(this.element, optName);
345				// Finally, if nothing was specified, use the defaults
346				val = (val !== null) ? val : this.defaultOptions[optName];
347
348				// Set all options on the instance of the Slider
349				if(!this.options) {
350					this.options = {};
351				}
352				this.options[optName] = val;
353			}
354
355			/*
356				Validate `tooltip_position` against 'orientation`
357				- if `tooltip_position` is incompatible with orientation, swith it to a default compatible with specified `orientation`
358					-- default for "vertical" -> "right"
359					-- default for "horizontal" -> "left"
360			*/
361			if(this.options.orientation === "vertical" && (this.options.tooltip_position === "top" || this.options.tooltip_position === "bottom")) {
362
363				this.options.tooltip_position	= "right";
364
365			}
366			else if(this.options.orientation === "horizontal" && (this.options.tooltip_position === "left" || this.options.tooltip_position === "right")) {
367
368				this.options.tooltip_position	= "top";
369
370			}
371
372			function getDataAttrib(element, optName) {
373				var dataName = "data-slider-" + optName.replace(/_/g, '-');
374				var dataValString = element.getAttribute(dataName);
375
376				try {
377					return JSON.parse(dataValString);
378				}
379				catch(err) {
380					return dataValString;
381				}
382			}
383
384			/*************************************************
385
386							Create Markup
387
388			**************************************************/
389
390			var origWidth = this.element.style.width;
391			var updateSlider = false;
392			var parent = this.element.parentNode;
393			var sliderTrackSelection;
394			var sliderTrackLow, sliderTrackHigh;
395			var sliderMinHandle;
396			var sliderMaxHandle;
397
398			if (this.sliderElem) {
399				updateSlider = true;
400			} else {
401				/* Create elements needed for slider */
402				this.sliderElem = document.createElement("div");
403				this.sliderElem.className = "slider";
404
405				/* Create slider track elements */
406				var sliderTrack = document.createElement("div");
407				sliderTrack.className = "slider-track";
408
409				sliderTrackLow = document.createElement("div");
410				sliderTrackLow.className = "slider-track-low";
411
412				sliderTrackSelection = document.createElement("div");
413				sliderTrackSelection.className = "slider-selection";
414
415				sliderTrackHigh = document.createElement("div");
416				sliderTrackHigh.className = "slider-track-high";
417
418				sliderMinHandle = document.createElement("div");
419				sliderMinHandle.className = "slider-handle min-slider-handle";
420				sliderMinHandle.setAttribute('role', 'slider');
421				sliderMinHandle.setAttribute('aria-valuemin', this.options.min);
422				sliderMinHandle.setAttribute('aria-valuemax', this.options.max);
423
424				sliderMaxHandle = document.createElement("div");
425				sliderMaxHandle.className = "slider-handle max-slider-handle";
426				sliderMaxHandle.setAttribute('role', 'slider');
427				sliderMaxHandle.setAttribute('aria-valuemin', this.options.min);
428				sliderMaxHandle.setAttribute('aria-valuemax', this.options.max);
429
430				sliderTrack.appendChild(sliderTrackLow);
431				sliderTrack.appendChild(sliderTrackSelection);
432				sliderTrack.appendChild(sliderTrackHigh);
433
434				/* Add aria-labelledby to handle's */
435				var isLabelledbyArray = Array.isArray(this.options.labelledby);
436				if (isLabelledbyArray && this.options.labelledby[0]) {
437					sliderMinHandle.setAttribute('aria-labelledby', this.options.labelledby[0]);
438				}
439				if (isLabelledbyArray && this.options.labelledby[1]) {
440					sliderMaxHandle.setAttribute('aria-labelledby', this.options.labelledby[1]);
441				}
442				if (!isLabelledbyArray && this.options.labelledby) {
443					sliderMinHandle.setAttribute('aria-labelledby', this.options.labelledby);
444					sliderMaxHandle.setAttribute('aria-labelledby', this.options.labelledby);
445				}
446
447				/* Create ticks */
448				this.ticks = [];
449				if (Array.isArray(this.options.ticks) && this.options.ticks.length > 0) {
450					for (i = 0; i < this.options.ticks.length; i++) {
451						var tick = document.createElement('div');
452						tick.className = 'slider-tick';
453
454						this.ticks.push(tick);
455						sliderTrack.appendChild(tick);
456					}
457
458					sliderTrackSelection.className += " tick-slider-selection";
459				}
460
461				sliderTrack.appendChild(sliderMinHandle);
462				sliderTrack.appendChild(sliderMaxHandle);
463
464				this.tickLabels = [];
465				if (Array.isArray(this.options.ticks_labels) && this.options.ticks_labels.length > 0) {
466					this.tickLabelContainer = document.createElement('div');
467					this.tickLabelContainer.className = 'slider-tick-label-container';
468
469					for (i = 0; i < this.options.ticks_labels.length; i++) {
470						var label = document.createElement('div');
471						var noTickPositionsSpecified = this.options.ticks_positions.length === 0;
472						var tickLabelsIndex = (this.options.reversed && noTickPositionsSpecified) ? (this.options.ticks_labels.length - (i + 1)) : i;
473						label.className = 'slider-tick-label';
474						label.innerHTML = this.options.ticks_labels[tickLabelsIndex];
475
476						this.tickLabels.push(label);
477						this.tickLabelContainer.appendChild(label);
478					}
479				}
480
481
482				var createAndAppendTooltipSubElements = function(tooltipElem) {
483					var arrow = document.createElement("div");
484					arrow.className = "tooltip-arrow";
485
486					var inner = document.createElement("div");
487					inner.className = "tooltip-inner";
488
489					tooltipElem.appendChild(arrow);
490					tooltipElem.appendChild(inner);
491
492				};
493
494				/* Create tooltip elements */
495				var sliderTooltip = document.createElement("div");
496				sliderTooltip.className = "tooltip tooltip-main";
497				sliderTooltip.setAttribute('role', 'presentation');
498				createAndAppendTooltipSubElements(sliderTooltip);
499
500				var sliderTooltipMin = document.createElement("div");
501				sliderTooltipMin.className = "tooltip tooltip-min";
502				sliderTooltipMin.setAttribute('role', 'presentation');
503				createAndAppendTooltipSubElements(sliderTooltipMin);
504
505				var sliderTooltipMax = document.createElement("div");
506				sliderTooltipMax.className = "tooltip tooltip-max";
507				sliderTooltipMax.setAttribute('role', 'presentation');
508				createAndAppendTooltipSubElements(sliderTooltipMax);
509
510
511				/* Append components to sliderElem */
512				this.sliderElem.appendChild(sliderTrack);
513				this.sliderElem.appendChild(sliderTooltip);
514				this.sliderElem.appendChild(sliderTooltipMin);
515				this.sliderElem.appendChild(sliderTooltipMax);
516
517				if (this.tickLabelContainer) {
518					this.sliderElem.appendChild(this.tickLabelContainer);
519				}
520
521				/* Append slider element to parent container, right before the original <input> element */
522				parent.insertBefore(this.sliderElem, this.element);
523
524				/* Hide original <input> element */
525				this.element.style.display = "none";
526			}
527			/* If JQuery exists, cache JQ references */
528			if($) {
529				this.$element = $(this.element);
530				this.$sliderElem = $(this.sliderElem);
531			}
532
533			/*************************************************
534
535								Setup
536
537			**************************************************/
538			this.eventToCallbackMap = {};
539			this.sliderElem.id = this.options.id;
540
541			this.touchCapable = 'ontouchstart' in window || (window.DocumentTouch && document instanceof window.DocumentTouch);
542
543			this.tooltip = this.sliderElem.querySelector('.tooltip-main');
544			this.tooltipInner = this.tooltip.querySelector('.tooltip-inner');
545
546			this.tooltip_min = this.sliderElem.querySelector('.tooltip-min');
547			this.tooltipInner_min = this.tooltip_min.querySelector('.tooltip-inner');
548
549			this.tooltip_max = this.sliderElem.querySelector('.tooltip-max');
550			this.tooltipInner_max= this.tooltip_max.querySelector('.tooltip-inner');
551
552			if (SliderScale[this.options.scale]) {
553				this.options.scale = SliderScale[this.options.scale];
554			}
555
556			if (updateSlider === true) {
557				// Reset classes
558				this._removeClass(this.sliderElem, 'slider-horizontal');
559				this._removeClass(this.sliderElem, 'slider-vertical');
560				this._removeClass(this.tooltip, 'hide');
561				this._removeClass(this.tooltip_min, 'hide');
562				this._removeClass(this.tooltip_max, 'hide');
563
564				// Undo existing inline styles for track
565				["left", "top", "width", "height"].forEach(function(prop) {
566					this._removeProperty(this.trackLow, prop);
567					this._removeProperty(this.trackSelection, prop);
568					this._removeProperty(this.trackHigh, prop);
569				}, this);
570
571				// Undo inline styles on handles
572				[this.handle1, this.handle2].forEach(function(handle) {
573					this._removeProperty(handle, 'left');
574					this._removeProperty(handle, 'top');
575				}, this);
576
577				// Undo inline styles and classes on tooltips
578				[this.tooltip, this.tooltip_min, this.tooltip_max].forEach(function(tooltip) {
579					this._removeProperty(tooltip, 'left');
580					this._removeProperty(tooltip, 'top');
581					this._removeProperty(tooltip, 'margin-left');
582					this._removeProperty(tooltip, 'margin-top');
583
584					this._removeClass(tooltip, 'right');
585					this._removeClass(tooltip, 'top');
586				}, this);
587			}
588
589			if(this.options.orientation === 'vertical') {
590				this._addClass(this.sliderElem,'slider-vertical');
591				this.stylePos = 'top';
592				this.mousePos = 'pageY';
593				this.sizePos = 'offsetHeight';
594			} else {
595				this._addClass(this.sliderElem, 'slider-horizontal');
596				this.sliderElem.style.width = origWidth;
597				this.options.orientation = 'horizontal';
598				this.stylePos = 'left';
599				this.mousePos = 'pageX';
600				this.sizePos = 'offsetWidth';
601
602			}
603			this._setTooltipPosition();
604			/* In case ticks are specified, overwrite the min and max bounds */
605			if (Array.isArray(this.options.ticks) && this.options.ticks.length > 0) {
606					this.options.max = Math.max.apply(Math, this.options.ticks);
607					this.options.min = Math.min.apply(Math, this.options.ticks);
608			}
609
610			if (Array.isArray(this.options.value)) {
611				this.options.range = true;
612				this._state.value = this.options.value;
613			}
614			else if (this.options.range) {
615				// User wants a range, but value is not an array
616				this._state.value = [this.options.value, this.options.max];
617			}
618			else {
619				this._state.value = this.options.value;
620			}
621
622			this.trackLow = sliderTrackLow || this.trackLow;
623			this.trackSelection = sliderTrackSelection || this.trackSelection;
624			this.trackHigh = sliderTrackHigh || this.trackHigh;
625
626			if (this.options.selection === 'none') {
627				this._addClass(this.trackLow, 'hide');
628				this._addClass(this.trackSelection, 'hide');
629				this._addClass(this.trackHigh, 'hide');
630			}
631
632			this.handle1 = sliderMinHandle || this.handle1;
633			this.handle2 = sliderMaxHandle || this.handle2;
634
635			if (updateSlider === true) {
636				// Reset classes
637				this._removeClass(this.handle1, 'round triangle');
638				this._removeClass(this.handle2, 'round triangle hide');
639
640				for (i = 0; i < this.ticks.length; i++) {
641					this._removeClass(this.ticks[i], 'round triangle hide');
642				}
643			}
644
645			var availableHandleModifiers = ['round', 'triangle', 'custom'];
646			var isValidHandleType = availableHandleModifiers.indexOf(this.options.handle) !== -1;
647			if (isValidHandleType) {
648				this._addClass(this.handle1, this.options.handle);
649				this._addClass(this.handle2, this.options.handle);
650
651				for (i = 0; i < this.ticks.length; i++) {
652					this._addClass(this.ticks[i], this.options.handle);
653				}
654			}
655
656			this._state.offset = this._offset(this.sliderElem);
657			this._state.size = this.sliderElem[this.sizePos];
658			this.setValue(this._state.value);
659
660			/******************************************
661
662						Bind Event Listeners
663
664			******************************************/
665
666			// Bind keyboard handlers
667			this.handle1Keydown = this._keydown.bind(this, 0);
668			this.handle1.addEventListener("keydown", this.handle1Keydown, false);
669
670			this.handle2Keydown = this._keydown.bind(this, 1);
671			this.handle2.addEventListener("keydown", this.handle2Keydown, false);
672
673			this.mousedown = this._mousedown.bind(this);
674			if (this.touchCapable) {
675				// Bind touch handlers
676				this.sliderElem.addEventListener("touchstart", this.mousedown, false);
677			}
678			this.sliderElem.addEventListener("mousedown", this.mousedown, false);
679
680			// Bind window handlers
681			this.resize = this._resize.bind(this);
682			window.addEventListener("resize", this.resize, false);
683
684
685			// Bind tooltip-related handlers
686			if(this.options.tooltip === 'hide') {
687				this._addClass(this.tooltip, 'hide');
688				this._addClass(this.tooltip_min, 'hide');
689				this._addClass(this.tooltip_max, 'hide');
690			}
691			else if(this.options.tooltip === 'always') {
692				this._showTooltip();
693				this._alwaysShowTooltip = true;
694			}
695			else {
696				this.showTooltip = this._showTooltip.bind(this);
697				this.hideTooltip = this._hideTooltip.bind(this);
698
699				this.sliderElem.addEventListener("mouseenter", this.showTooltip, false);
700				this.sliderElem.addEventListener("mouseleave", this.hideTooltip, false);
701
702				this.handle1.addEventListener("focus", this.showTooltip, false);
703				this.handle1.addEventListener("blur", this.hideTooltip, false);
704
705				this.handle2.addEventListener("focus", this.showTooltip, false);
706				this.handle2.addEventListener("blur", this.hideTooltip, false);
707			}
708
709			if(this.options.enabled) {
710				this.enable();
711			} else {
712				this.disable();
713			}
714
715		}
716
717
718
719		/*************************************************
720
721					INSTANCE PROPERTIES/METHODS
722
723		- Any methods bound to the prototype are considered
724		part of the plugin's `public` interface
725
726		**************************************************/
727		Slider.prototype = {
728			_init: function() {}
728, // NOTE: Must exist to support bridget
729
730			constructor: Slider,
731
732			defaultOptions: {
733				id: "",
734			  min: 0,
735				max: 10,
736				step: 1,
737				precision: 0,
738				orientation: 'horizontal',
739				value: 5,
740				range: false,
741				selection: 'before',
742				tooltip: 'show',
743				tooltip_split: false,
744				handle: 'round',
745				reversed: false,
746				enabled: true,
747				formatter: function(val) {
748					if (Array.isArray(val)) {
749						return val[0] + " : " + val[1];
750					} else {
751						return val;
752					}
753				},
754				natural_arrow_keys: false,
755				ticks: [],
756				ticks_positions: [],
757				ticks_labels: [],
758				ticks_snap_bounds: 0,
759				scale: 'linear',
760				focus: false,
761				tooltip_position: null,
762				labelledby: null
763			},
764
765			getElement: function() {
766				return this.sliderElem;
767			},
768
769			getValue: function() {
770				if (this.options.range) {
771					return this._state.value;
772				}
773				else {
774					return this._state.value[0];
775				}
776			},
777
778			setValue: function(val, triggerSlideEvent, triggerChangeEvent) {
779				if (!val) {
780					val = 0;
781				}
782				var oldValue = this.getValue();
783				this._state.value = this._validateInputValue(val);
784				var applyPrecision = this._applyPrecision.bind(this);
785
786				if (this.options.range) {
787					this._state.value[0] = applyPrecision(this._state.value[0]);
788					this._state.value[1] = applyPrecision(this._state.value[1]);
789
790					this._state.value[0] = Math.max(this.options.min, Math.min(this.options.max, this._state.value[0]));
791					this._state.value[1] = Math.max(this.options.min, Math.min(this.options.max, this._state.value[1]));
792				}
793				else {
794					this._state.value = applyPrecision(this._state.value);
795					this._state.value = [ Math.max(this.options.min, Math.min(this.options.max, this._state.value))];
796					this._addClass(this.handle2, 'hide');
797					if (this.options.selection === 'after') {
798						this._state.value[1] = this.options.max;
799					} else {
800						this._state.value[1] = this.options.min;
801					}
802				}
803
804				if (this.options.max > this.options.min) {
805					this._state.percentage = [
806						this._toPercentage(this._state.value[0]),
807						this._toPercentage(this._state.value[1]),
808						this.options.step * 100 / (this.options.max - this.options.min)
809					];
810				} else {
811					this._state.percentage = [0, 0, 100];
812				}
813
814				this._layout();
815				var newValue = this.options.range ? this._state.value : this._state.value[0];
816
817				this._setDataVal(newValue);
818				if(triggerSlideEvent === true) {
819					this._trigger('slide', newValue);
820				}
821				if( (oldValue !== newValue) && (triggerChangeEvent === true) ) {
822					this._trigger('change', {
823						oldValue: oldValue,
824						newValue: newValue
825					});
826				}
827
828				return this;
829			},
830
831			destroy: function(){
832				// Remove event handlers on slider elements
833				this._removeSliderEventHandlers();
834
835				// Remove the slider from the DOM
836				this.sliderElem.parentNode.removeChild(this.sliderElem);
837				/* Show original <input> element */
838				this.element.style.display = "";
839
840				// Clear out custom event bindings
841				this._cleanUpEventCallbacksMap();
842
843				// Remove data values
844				this.element.removeAttribute("data");
845
846				// Remove JQuery handlers/data
847				if($) {
848					this._unbindJQueryEventHandlers();
849					this.$element.removeData('slider');
850				}
851			},
852
853			disable: function() {
854				this._state.enabled = false;
855				this.handle1.removeAttribute("tabindex");
856				this.handle2.removeAttribute("tabindex");
857				this._addClass(this.sliderElem, 'slider-disabled');
858				this._trigger('slideDisabled');
859
860				return this;
861			},
862
863			enable: function() {
864				this._state.enabled = true;
865				this.handle1.setAttribute("tabindex", 0);
866				this.handle2.setAttribute("tabindex", 0);
867				this._removeClass(this.sliderElem, 'slider-disabled');
868				this._trigger('slideEnabled');
869
870				return this;
871			},
872
873			toggle: function() {
874				if(this._state.enabled) {
875					this.disable();
876				} else {
877					this.enable();
878				}
879				return this;
880			},
881
882			isEnabled: function() {
883				return this._state.enabled;
884			},
885
886			on: function(evt, callback) {
887				this._bindNonQueryEventHandler(evt, callback);
888				return this;
889			},
890
891      off: function(evt, callback) {
892          if($) {
893              this.$element.off(evt, callback);
894              this.$sliderElem.off(evt, callback);
895          } else {
896              this._unbindNonQueryEventHandler(evt, callback);
897          }
898      },
899
900			getAttribute: function(attribute) {
901				if(attribute) {
902					return this.options[attribute];
903				} else {
904					return this.options;
905				}
906			},
907
908			setAttribute: function(attribute, value) {
909				this.options[attribute] = value;
910				return this;
911			},
912
913			refresh: function() {
914				this._removeSliderEventHandlers();
915				createNewSlider.call(this, this.element, this.options);
916				if($) {
917					// Bind new instance of slider to the element
918					$.data(this.element, 'slider', this);
919				}
920				return this;
921			},
922
923			relayout: function() {
924				this._layout();
925				return this;
926			},
927
928			/******************************+
929
930						HELPERS
931
932			- Any method that is not part of the public interface.
933			- Place it underneath this comment block and write its signature like so:
934
935			  					_fnName : function() {...}
936
937			********************************/
938			_removeSliderEventHandlers: function() {
939				// Remove keydown event listeners
940				this.handle1.removeEventListener("keydown", this.handle1Keydown, false);
941				this.handle2.removeEventListener("keydown", this.handle2Keydown, false);
942
943				if (this.showTooltip) {
944					this.handle1.removeEventListener("focus", this.showTooltip, false);
945					this.handle2.removeEventListener("focus", this.showTooltip, false);
946				}
947				if (this.hideTooltip) {
948					this.handle1.removeEventListener("blur", this.hideTooltip, false);
949					this.handle2.removeEventListener("blur", this.hideTooltip, false);
950				}
951
952				// Remove event listeners from sliderElem
953				if (this.showTooltip) {
954					this.sliderElem.removeEventListener("mouseenter", this.showTooltip, false);
955				}
956				if (this.hideTooltip) {
957					this.sliderElem.removeEventListener("mouseleave", this.hideTooltip, false);
958				}
959				this.sliderElem.removeEventListener("touchstart", this.mousedown, false);
960				this.sliderElem.removeEventListener("mousedown", this.mousedown, false);
961
962				// Remove window event listener
963				window.removeEventListener("resize", this.resize, false);
964			},
965			_bindNonQueryEventHandler: function(evt, callback) {
966				if(this.eventToCallbackMap[evt] === undefined) {
967					this.eventToCallbackMap[evt] = [];
968				}
969				this.eventToCallbackMap[evt].push(callback);
970			},
971      _unbindNonQueryEventHandler: function(evt, callback) {
972          var callbacks = this.eventToCallbackMap[evt];
973          if(callbacks !== undefined) {
974              for (var i = 0; i < callbacks.length; i++) {
975                  if (callbacks[i] === callback) {
976                      callbacks.splice(i, 1);
977                      break;
978                  }
979              }
980          }
981      },
982			_cleanUpEventCallbacksMap: function() {
983				var eventNames = Object.keys(this.eventToCallbackMap);
984				for(var i = 0; i < eventNames.length; i++) {
985					var eventName = eventNames[i];
986					this.eventToCallbackMap[eventName] = null;
987				}
988			},
989			_showTooltip: function() {
990				if (this.options.tooltip_split === false ){
991        	this._addClass(this.tooltip, 'in');
992        	this.tooltip_min.style.display = 'none';
993        	this.tooltip_max.style.display = 'none';
994		    } else {
995          this._addClass(this.tooltip_min, 'in');
996          this._addClass(this.tooltip_max, 'in');
997          this.tooltip.style.display = 'none';
998		    }
999				this._state.over = true;
1000			},
1001			_hideTooltip: function() {
1002				if (this._state.inDrag === false && this.alwaysShowTooltip !== true) {
1003					this._removeClass(this.tooltip, 'in');
1004					this._removeClass(this.tooltip_min, 'in');
1005					this._removeClass(this.tooltip_max, 'in');
1006				}
1007				this._state.over = false;
1008			},
1009			_layout: function() {
1010				var positionPercentages;
1011
1012				if(this.options.reversed) {
1013					positionPercentages = [ 100 - this._state.percentage[0], this.options.range ? 100 - this._state.percentage[1] : this._state.percentage[1]];
1014				}
1015				else {
1016					positionPercentages = [ this._state.percentage[0], this._state.percentage[1] ];
1017				}
1018
1019				this.handle1.style[this.stylePos] = positionPercentages[0]+'%';
1020				this.handle1.setAttribute('aria-valuenow', this._state.value[0]);
1021
1022				this.handle2.style[this.stylePos] = positionPercentages[1]+'%';
1023				this.handle2.setAttribute('aria-valuenow', this._state.value[1]);
1024
1025				/* Position ticks and labels */
1026				if (Array.isArray(this.options.ticks) && this.options.ticks.length > 0) {
1027
1028					var styleSize = this.options.orientation === 'vertical' ? 'height' : 'width';
1029					var styleMargin = this.options.orientation === 'vertical' ? 'marginTop' : 'marginLeft';
1030					var labelSize = this._state.size / (this.options.ticks.length - 1);
1031
1032					if (this.tickLabelContainer) {
1033						var extraMargin = 0;
1034						if (this.options.ticks_positions.length === 0) {
1035							if (this.options.orientation !== 'vertical') {
1036								this.tickLabelContainer.style[styleMargin] = -labelSize/2 + 'px';
1037							}
1038
1039							extraMargin = this.tickLabelContainer.offsetHeight;
1040						} else {
1041							/* Chidren are position absolute, calculate height by finding the max offsetHeight of a child */
1042							for (i = 0 ; i < this.tickLabelContainer.childNodes.length; i++) {
1043								if (this.tickLabelContainer.childNodes[i].offsetHeight > extraMargin) {
1044									extraMargin = this.tickLabelContainer.childNodes[i].offsetHeight;
1045								}
1046							}
1047						}
1048						if (this.options.orientation === 'horizontal') {
1049							this.sliderElem.style.marginBottom = extraMargin + 'px';
1050						}
1051					}
1052					for (var i = 0; i < this.options.ticks.length; i++) {
1053
1054						var percentage = this.options.ticks_positions[i] || this._toPercentage(this.options.ticks[i]);
1055
1056						if (this.options.reversed) {
1057							percentage = 100 - percentage;
1058						}
1059
1060						this.ticks[i].style[this.stylePos] = percentage + '%';
1061
1062						/* Set class labels to denote whether ticks are in the selection */
1063						this._removeClass(this.ticks[i], 'in-selection');
1064						if (!this.options.range) {
1065							if (this.options.selection === 'after' && percentage >= positionPercentages[0]){
1066								this._addClass(this.ticks[i], 'in-selection');
1067							} else if (this.options.selection === 'before' && percentage <= positionPercentages[0]) {
1068								this._addClass(this.ticks[i], 'in-selection');
1069							}
1070						} else if (percentage >= positionPercentages[0] && percentage <= positionPercentages[1]) {
1071							this._addClass(this.ticks[i], 'in-selection');
1072						}
1073
1074						if (this.tickLabels[i]) {
1075							this.tickLabels[i].style[styleSize] = labelSize + 'px';
1076
1077							if (this.options.orientation !== 'vertical' && this.options.ticks_positions[i] !== undefined) {
1078								this.tickLabels[i].style.position = 'absolute';
1079								this.tickLabels[i].style[this.stylePos] = percentage + '%';
1080								this.tickLabels[i].style[styleMargin] = -labelSize/2 + 'px';
1081							} else if (this.options.orientation === 'vertical') {
1082								this.tickLabels[i].style['marginLeft'] =  this.sliderElem.offsetWidth + 'px';
1083								this.tickLabelContainer.style['marginTop'] = this.sliderElem.offsetWidth / 2 * -1 + 'px';
1084							}
1085						}
1086					}
1087				}
1088
1089				var formattedTooltipVal;
1090
1091				if (this.options.range) {
1092					formattedTooltipVal = this.options.formatter(this._state.value);
1093					this._setText(this.tooltipInner, formattedTooltipVal);
1094					this.tooltip.style[this.stylePos] = (positionPercentages[1] + positionPercentages[0])/2 + '%';
1095
1096					if (this.options.orientation === 'vertical') {
1097						this._css(this.tooltip, 'margin-top', -this.tooltip.offsetHeight / 2 + 'px');
1098					} else {
1099						this._css(this.tooltip, 'margin-left', -this.tooltip.offsetWidth / 2 + 'px');
1100					}
1101
1102					if (this.options.orientation === 'vertical') {
1103						this._css(this.tooltip, 'margin-top', -this.tooltip.offsetHeight / 2 + 'px');
1104					} else {
1105						this._css(this.tooltip, 'margin-left', -this.tooltip.offsetWidth / 2 + 'px');
1106					}
1107
1108					var innerTooltipMinText = this.options.formatter(this._state.value[0]);
1109					this._setText(this.tooltipInner_min, innerTooltipMinText);
1110
1111					var innerTooltipMaxText = this.options.formatter(this._state.value[1]);
1112					this._setText(this.tooltipInner_max, innerTooltipMaxText);
1113
1114					this.tooltip_min.style[this.stylePos] = positionPercentages[0] + '%';
1115
1116					if (this.options.orientation === 'vertical') {
1117						this._css(this.tooltip_min, 'margin-top', -this.tooltip_min.offsetHeight / 2 + 'px');
1118					} else {
1119						this._css(this.tooltip_min, 'margin-left', -this.tooltip_min.offsetWidth / 2 + 'px');
1120					}
1121
1122					this.tooltip_max.style[this.stylePos] = positionPercentages[1] + '%';
1123
1124					if (this.options.orientation === 'vertical') {
1125						this._css(this.tooltip_max, 'margin-top', -this.tooltip_max.offsetHeight / 2 + 'px');
1126					} else {
1127						this._css(this.tooltip_max, 'margin-left', -this.tooltip_max.offsetWidth / 2 + 'px');
1128					}
1129				} else {
1130					formattedTooltipVal = this.options.formatter(this._state.value[0]);
1131					this._setText(this.tooltipInner, formattedTooltipVal);
1132
1133					this.tooltip.style[this.stylePos] = positionPercentages[0] + '%';
1134					if (this.options.orientation === 'vertical') {
1135						this._css(this.tooltip, 'margin-top', -this.tooltip.offsetHeight / 2 + 'px');
1136					} else {
1137						this._css(this.tooltip, 'margin-left', -this.tooltip.offsetWidth / 2 + 'px');
1138					}
1139				}
1140
1141				if (this.options.orientation === 'vertical') {
1142					this.trackLow.style.top = '0';
1143					this.trackLow.style.height = Math.min(positionPercentages[0], positionPercentages[1]) +'%';
1144
1145					this.trackSelection.style.top = Math.min(positionPercentages[0], positionPercentages[1]) +'%';
1146					this.trackSelection.style.height = Math.abs(positionPercentages[0] - positionPercentages[1]) +'%';
1147
1148					this.trackHigh.style.bottom = '0';
1149					this.trackHigh.style.height = (100 - Math.min(positionPercentages[0], positionPercentages[1]) - Math.abs(positionPercentages[0] - positionPercentages[1])) +'%';
1150				}
1151				else {
1152					this.trackLow.style.left = '0';
1153					this.trackLow.style.width = Math.min(positionPercentages[0], positionPercentages[1]) +'%';
1154
1155					this.trackSelection.style.left = Math.min(positionPercentages[0], positionPercentages[1]) +'%';
1156					this.trackSelection.style.width = Math.abs(positionPercentages[0] - positionPercentages[1]) +'%';
1157
1158					this.trackHigh.style.right = '0';
1159					this.trackHigh.style.width = (100 - Math.min(positionPercentages[0], positionPercentages[1]) - Math.abs(positionPercentages[0] - positionPercentages[1])) +'%';
1160
1161			        var offset_min = this.tooltip_min.getBoundingClientRect();
1162			        var offset_max = this.tooltip_max.getBoundingClientRect();
1163
1164			        if (this.options.tooltip_position === 'bottom') {
1165			        	if (offset_min.right > offset_max.left) {
1166			        		this._removeClass(this.tooltip_max, 'bottom');
1167			        		this._addClass(this.tooltip_max, 'top');
1168			        		this.tooltip_max.style.top = '';
1169                            this.tooltip_max.style.bottom = 22 + 'px';
1170                        } else {
1171                            this._removeClass(this.tooltip_max, 'top');
1172                            this._addClass(this.tooltip_max, 'bottom');
1173                            this.tooltip_max.style.top = this.tooltip_min.style.top;
1174                            this.tooltip_max.style.bottom = '';
1175			        	}
1176			        } else {
1177				        if (offset_min.right > offset_max.left) {
1178				            this._removeClass(this.tooltip_max, 'top');
1179				            this._addClass(this.tooltip_max, 'bottom');
1180				            this.tooltip_max.style.top = 18 + 'px';
1181				        } else {
1182				            this._removeClass(this.tooltip_max, 'bottom');
1183				            this._addClass(this.tooltip_max, 'top');
1184				            this.tooltip_max.style.top = this.tooltip_min.style.top;
1185				        }
1186			        }
1187				}
1188			},
1189			_resize: function (ev) {
1190				/*jshint unused:false*/
1191				this._state.offset = this._offset(this.sliderElem);
1192				this._state.size = this.sliderElem[this.sizePos];
1193				this._layout();
1194			},
1195			_removeProperty: function(element, prop) {
1196				if (element.style.removeProperty) {
1197				    element.style.removeProperty(prop);
1198				} else {
1199				    element.style.removeAttribute(prop);
1200				}
1201			},
1202			_mousedown: function(ev) {
1203				if(!this._state.enabled) {
1204					return false;
1205				}
1206
1207				this._state.offset = this._offset(this.sliderElem);
1208				this._state.size = this.sliderElem[this.sizePos];
1209
1210				var percentage = this._getPercentage(ev);
1211
1212				if (this.options.range) {
1213					var diff1 = Math.abs(this._state.percentage[0] - percentage);
1214					var diff2 = Math.abs(this._state.percentage[1] - percentage);
1215					this._state.dragged = (diff1 < diff2) ? 0 : 1;
1216				} else {
1217					this._state.dragged = 0;
1218				}
1219
1220				this._state.percentage[this._state.dragged] = percentage;
1221				this._layout();
1222
1223				if (this.touchCapable) {
1224					document.removeEventListener("touchmove", this.mousemove, false);
1225					document.removeEventListener("touchend", this.mouseup, false);
1226				}
1227
1228				if(this.mousemove){
1229					document.removeEventListener("mousemove", this.mousemove, false);
1230				}
1231				if(this.mouseup){
1232					document.removeEventListener("mouseup", this.mouseup, false);
1233				}
1234
1235				this.mousemove = this._mousemove.bind(this);
1236				this.mouseup = this._mouseup.bind(this);
1237
1238				if (this.touchCapable) {
1239					// Touch: Bind touch events:
1240					document.addEventListener("touchmove", this.mousemove, false);
1241					document.addEventListener("touchend", this.mouseup, false);
1242				}
1243				// Bind mouse events:
1244				document.addEventListener("mousemove", this.mousemove, false);
1245				document.addEventListener("mouseup", this.mouseup, false);
1246
1247				this._state.inDrag = true;
1248				var newValue = this._calculateValue();
1249
1250				this._trigger('slideStart', newValue);
1251
1252				this._setDataVal(newValue);
1253				this.setValue(newValue, false, true);
1254
1255				this._pauseEvent(ev);
1256
1257				if (this.options.focus) {
1258					this._triggerFocusOnHandle(this._state.dragged);
1259				}
1260
1261				return true;
1262			},
1263			_triggerFocusOnHandle: function(handleIdx) {
1264				if(handleIdx === 0) {
1265					this.handle1.focus();
1266				}
1267				if(handleIdx === 1) {
1268					this.handle2.focus();
1269				}
1270			},
1271			_keydown: function(handleIdx, ev) {
1272				if(!this._state.enabled) {
1273					return false;
1274				}
1275
1276				var dir;
1277				switch (ev.keyCode) {
1278					case 37: // left
1279					case 40: // down
1280						dir = -1;
1281						break;
1282					case 39: // right
1283					case 38: // up
1284						dir = 1;
1285						break;
1286				}
1287				if (!dir) {
1288					return;
1289				}
1290
1291				// use natural arrow keys instead of from min to max
1292				if (this.options.natural_arrow_keys) {
1293					var ifVerticalAndNotReversed = (this.options.orientation === 'vertical' && !this.options.reversed);
1294					var ifHorizontalAndReversed = (this.options.orientation === 'horizontal' && this.options.reversed);
1295
1296					if (ifVerticalAndNotReversed || ifHorizontalAndReversed) {
1297						dir = -dir;
1298					}
1299				}
1300
1301				var val = this._state.value[handleIdx] + dir * this.options.step;
1302				if (this.options.range) {
1303					val = [ (!handleIdx) ? val : this._state.value[0],
1304						    ( handleIdx) ? val : this._state.value[1]];
1305				}
1306
1307				this._trigger('slideStart', val);
1308				this._setDataVal(val);
1309				this.setValue(val, true, true);
1310
1311				this._setDataVal(val);
1312				this._trigger('slideStop', val);
1313				this._layout();
1314
1315				this._pauseEvent(ev);
1316
1317				return false;
1318			},
1319			_pauseEvent: function(ev) {
1320				if(ev.stopPropagation) {
1321					ev.stopPropagation();
1322				}
1323			    if(ev.preventDefault) {
1324			    	ev.preventDefault();
1325			    }
1326			    ev.cancelBubble=true;
1327			    ev.returnValue=false;
1328			},
1329			_mousemove: function(ev) {
1330				if(!this._state.enabled) {
1331					return false;
1332				}
1333
1334				var percentage = this._getPercentage(ev);
1335				this._adjustPercentageForRangeSliders(percentage);
1336				this._state.percentage[this._state.dragged] = percentage;
1337				this._layout();
1338
1339				var val = this._calculateValue(true);
1340				this.setValue(val, true, true);
1341
1342				return false;
1343			},
1344			_adjustPercentageForRangeSliders: function(percentage) {
1345				if (this.options.range) {
1346					var precision = this._getNumDigitsAfterDecimalPlace(percentage);
1347					precision = precision ? precision - 1 : 0;
1348					var percentageWithAdjustedPrecision = this._applyToFixedAndParseFloat(percentage, precision);
1349					if (this._state.dragged === 0 && this._applyToFixedAndParseFloat(this._state.percentage[1], precision) < percentageWithAdjustedPrecision) {
1350						this._state.percentage[0] = this._state.percentage[1];
1351						this._state.dragged = 1;
1352					} else if (this._state.dragged === 1 && this._applyToFixedAndParseFloat(this._state.percentage[0], precision) > percentageWithAdjustedPrecision) {
1353						this._state.percentage[1] = this._state.percentage[0];
1354						this._state.dragged = 0;
1355					}
1356				}
1357			},
1358			_mouseup: function() {
1359				if(!this._state.enabled) {
1360					return false;
1361				}
1362				if (this.touchCapable) {
1363					// Touch: Unbind touch event handlers:
1364					document.removeEventListener("touchmove", this.mousemove, false);
1365					document.removeEventListener("touchend", this.mouseup, false);
1366				}
1367                // Unbind mouse event handlers:
1368                document.removeEventListener("mousemove", this.mousemove, false);
1369                document.removeEventListener("mouseup", this.mouseup, false);
1370
1371				this._state.inDrag = false;
1372				if (this._state.over === false) {
1373					this._hideTooltip();
1374				}
1375				var val = this._calculateValue(true);
1376
1377				this._layout();
1378				this._setDataVal(val);
1379				this._trigger('slideStop', val);
1380
1381				return false;
1382			},
1383			_calculateValue: function(snapToClosestTick) {
1384				var val;
1385				if (this.options.range) {
1386					val = [this.options.min,this.options.max];
1387			        if (this._state.percentage[0] !== 0){
1388			            val[0] = this._toValue(this._state.percentage[0]);
1389			            val[0] = this._applyPrecision(val[0]);
1390			        }
1391			        if (this._state.percentage[1] !== 100){
1392			            val[1] = this._toValue(this._state.percentage[1]);
1393			            val[1] = this._applyPrecision(val[1]);
1394			        }
1395				} else {
1396		            val = this._toValue(this._state.percentage[0]);
1397					val = parseFloat(val);
1398					val = this._applyPrecision(val);
1399				}
1400
1401				if (snapToClosestTick) {
1402					var min = [val, Infinity];
1403					for (var i = 0; i < this.options.ticks.length; i++) {
1404						var diff = Math.abs(this.options.ticks[i] - val);
1405						if (diff <= min[1]) {
1406							min = [this.options.ticks[i], diff];
1407						}
1408					}
1409					if (min[1] <= this.options.ticks_snap_bounds) {
1410						return min[0];
1411					}
1412				}
1413
1414				return val;
1415			},
1416			_applyPrecision: function(val) {
1417				var precision = this.options.precision || this._getNumDigitsAfterDecimalPlace(this.options.step);
1418				return this._applyToFixedAndParseFloat(val, precision);
1419			},
1420			_getNumDigitsAfterDecimalPlace: function(num) {
1421				var match = (''+num).match(/(?:\.(\d+))?(?:[eE]([+-]?\d+))?$/);
1422				if (!match) { return 0; }
1423				return Math.max(0, (match[1] ? match[1].length : 0) - (match[2] ? +match[2] : 0));
1424			},
1425			_applyToFixedAndParseFloat: function(num, toFixedInput) {
1426				var truncatedNum = num.toFixed(toFixedInput);
1427				return parseFloat(truncatedNum);
1428			},
1429			/*
1430				Credits to Mike Samuel for the following method!
1431				Source: http://stackoverflow.com/questions/10454518/javascript-how-to-retrieve-the-number-of-decimals-of-a-string-number
1432			*/
1433			_getPercentage: function(ev) {
1434				if (this.touchCapable && (ev.type === 'touchstart' || ev.type === 'touchmove')) {
1435					ev = ev.touches[0];
1436				}
1437
1438				var eventPosition = ev[this.mousePos];
1439				var sliderOffset = this._state.offset[this.stylePos];
1440				var distanceToSlide = eventPosition - sliderOffset;
1441				// Calculate what percent of the length the slider handle has slid
1442				var percentage = (distanceToSlide / this._state.size) * 100;
1443				percentage = Math.round(percentage / this._state.percentage[2]) * this._state.percentage[2];
1444				if (this.options.reversed) {
1445					percentage = 100 - percentage;
1446				}
1447
1448				// Make sure the percent is within the bounds of the slider.
1449				// 0% corresponds to the 'min' value of the slide
1450				// 100% corresponds to the 'max' value of the slide
1451				return Math.max(0, Math.min(100, percentage));
1452			},
1453			_validateInputValue: function(val) {
1454				if (typeof val === 'number') {
1455					return val;
1456				} else if (Array.isArray(val)) {
1457					this._validateArray(val);
1458					return val;
1459				} else {
1460					throw new Error( ErrorMsgs.formatInvalidInputErrorMsg(val) );
1461				}
1462			},
1463			_validateArray: function(val) {
1464				for(var i = 0; i < val.length; i++) {
1465					var input =  val[i];
1466					if (typeof input !== 'number') { throw new Error( ErrorMsgs.formatInvalidInputErrorMsg(input) ); }
1467				}
1468			},
1469			_setDataVal: function(val) {
1470				this.element.setAttribute('data-value', val);
1471				this.element.setAttribute('value', val);
1472        this.element.value = val;
1473			},
1474			_trigger: function(evt, val) {
1475				val = (val || val === 0) ? val : undefined;
1476
1477				var callbackFnArray = this.eventToCallbackMap[evt];
1478				if(callbackFnArray && callbackFnArray.length) {
1479					for(var i = 0; i < callbackFnArray.length; i++) {
1480						var callbackFn = callbackFnArray[i];
1481						callbackFn(val);
1482					}
1483				}
1484
1485				/* If JQuery exists, trigger JQuery events */
1486				if($) {
1487					this._triggerJQueryEvent(evt, val);
1488				}
1489			},
1490			_triggerJQueryEvent: function(evt, val) {
1491				var eventData = {
1492					type: evt,
1493					value: val
1494				};
1495				this.$element.trigger(eventData);
1496				this.$sliderElem.trigger(eventData);
1497			},
1498			_unbindJQueryEventHandlers: function() {
1499				this.$element.off();
1500				this.$sliderElem.off();
1501			},
1502			_setText: function(element, text) {
1503				if(typeof element.innerText !== "undefined") {
1504			 		element.innerText = text;
1505			 	} else if(typeof element.textContent !== "undefined") {
1506			 		element.textContent = text;
1507			 	}
1508			},
1509			_removeClass: function(element, classString) {
1510				var classes = classString.split(" ");
1511				var newClasses = element.className;
1512
1513				for(var i = 0; i < classes.length; i++) {
1514					var classTag = classes[i];
1515					var regex = new RegExp("(?:\\s|^)" + classTag + "(?:\\s|$)");
1516					newClasses = newClasses.replace(regex, " ");
1517				}
1518
1519				element.className = newClasses.trim();
1520			},
1521			_addClass: function(element, classString) {
1522				var classes = classString.split(" ");
1523				var newClasses = element.className;
1524
1525				for(var i = 0; i < classes.length; i++) {
1526					var classTag = classes[i];
1527					var regex = new RegExp("(?:\\s|^)" + classTag + "(?:\\s|$)");
1528					var ifClassExists = regex.test(newClasses);
1529
1530					if(!ifClassExists) {
1531						newClasses += " " + classTag;
1532					}
1533				}
1534
1535				element.className = newClasses.trim();
1536			},
1537			_offsetLeft: function(obj){
1538				return obj.getBoundingClientRect().left;
1539			},
1540			_offsetTop: function(obj){
1541				var offsetTop = obj.offsetTop;
1542				while((obj = obj.offsetParent) && !isNaN(obj.offsetTop)){
1543					offsetTop += obj.offsetTop;
1544				}
1545				return offsetTop;
1546			},
1547		    _offset: function (obj) {
1548				return {
1549					left: this._offsetLeft(obj),
1550					top: this._offsetTop(obj)
1551				};
1552		    },
1553			_css: function(elementRef, styleName, value) {
1554                if ($) {
1555                    $.style(elementRef, styleName, value);
1556                } else {
1557                    var style = styleName.replace(/^-ms-/, "ms-").replace(/-([\da-z])/gi, function (all, letter) {
1558                        return letter.toUpperCase();
1559                    });
1560                    elementRef.style[style] = value;
1561                }
1562			},
1563			_toValue: function(percentage) {
1564				return this.options.scale.toValue.apply(this, [percentage]);
1565			},
1566			_toPercentage: function(value) {
1567				return this.options.scale.toPercentage.apply(this, [value]);
1568			},
1569			_setTooltipPosition: function(){
1570				var tooltips = [this.tooltip, this.tooltip_min, this.tooltip_max];
1571				if (this.options.orientation === 'vertical'){
1572					var tooltipPos = this.options.tooltip_position || 'right';
1573					var oppositeSide = (tooltipPos === 'left') ? 'right' : 'left';
1574					tooltips.forEach(function(tooltip){
1575						this._addClass(tooltip, tooltipPos);
1576						tooltip.style[oppositeSide] = '100%';
1577					}.bind(this));
1578				} else if(this.options.tooltip_position === 'bottom') {
1579					tooltips.forEach(function(tooltip){
1580						this._addClass(tooltip, 'bottom');
1581						tooltip.style.top = 22 + 'px';
1582					}.bind(this));
1583				} else {
1584					tooltips.forEach(function(tooltip){
1585						this._addClass(tooltip, 'top');
1586						tooltip.style.top = -this.tooltip.outerHeight - 14 + 'px';
1587					}.bind(this));
1588				}
1589			}
1590		};
1591
1592		/*********************************
1593
1594			Attach to global namespace
1595
1596		*********************************/
1597		if($) {
1598			var namespace = $.fn.slider ? 'bootstrapSlider' : 'slider';
1599			$.bridget(namespace, Slider);
1600		}
1601
1602	})( $ );
1603
1604	return Slider;
1605}));

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.