PageSourceSearch

https://www.paly61.com/templates/100/vendor/bootstrap-slider/js/bootstrap-slider.js

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

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.