PageSourceSearch

https://secure.salmamarkets.com/vendor/bootstrap/js/bootstrap-slider.js

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

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.