| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959 | 
							- /*! nouislider - 8.5.1 - 2016-04-24 16:00:29 */
 
- (function (factory) {
 
-     if ( typeof define === 'function' && define.amd ) {
 
-         // AMD. Register as an anonymous module.
 
-         define([], factory);
 
-     } else if ( typeof exports === 'object' ) {
 
-         // Node/CommonJS
 
-         module.exports = factory();
 
-     } else {
 
-         // Browser globals
 
-         window.noUiSlider = factory();
 
-     }
 
- }(function( ){
 
- 	'use strict';
 
- 	// Removes duplicates from an array.
 
- 	function unique(array) {
 
- 		return array.filter(function(a){
 
- 			return !this[a] ? this[a] = true : false;
 
- 		}, {});
 
- 	}
 
- 	// Round a value to the closest 'to'.
 
- 	function closest ( value, to ) {
 
- 		return Math.round(value / to) * to;
 
- 	}
 
- 	// Current position of an element relative to the document.
 
- 	function offset ( elem ) {
 
- 	var rect = elem.getBoundingClientRect(),
 
- 		doc = elem.ownerDocument,
 
- 		docElem = doc.documentElement,
 
- 		pageOffset = getPageOffset();
 
- 		// getBoundingClientRect contains left scroll in Chrome on Android.
 
- 		// I haven't found a feature detection that proves this. Worst case
 
- 		// scenario on mis-match: the 'tap' feature on horizontal sliders breaks.
 
- 		if ( /webkit.*Chrome.*Mobile/i.test(navigator.userAgent) ) {
 
- 			pageOffset.x = 0;
 
- 		}
 
- 		return {
 
- 			top: rect.top + pageOffset.y - docElem.clientTop,
 
- 			left: rect.left + pageOffset.x - docElem.clientLeft
 
- 		};
 
- 	}
 
- 	// Checks whether a value is numerical.
 
- 	function isNumeric ( a ) {
 
- 		return typeof a === 'number' && !isNaN( a ) && isFinite( a );
 
- 	}
 
- 	// Sets a class and removes it after [duration] ms.
 
- 	function addClassFor ( element, className, duration ) {
 
- 		addClass(element, className);
 
- 		setTimeout(function(){
 
- 			removeClass(element, className);
 
- 		}, duration);
 
- 	}
 
- 	// Limits a value to 0 - 100
 
- 	function limit ( a ) {
 
- 		return Math.max(Math.min(a, 100), 0);
 
- 	}
 
- 	// Wraps a variable as an array, if it isn't one yet.
 
- 	function asArray ( a ) {
 
- 		return Array.isArray(a) ? a : [a];
 
- 	}
 
- 	// Counts decimals
 
- 	function countDecimals ( numStr ) {
 
- 		var pieces = numStr.split(".");
 
- 		return pieces.length > 1 ? pieces[1].length : 0;
 
- 	}
 
- 	// http://youmightnotneedjquery.com/#add_class
 
- 	function addClass ( el, className ) {
 
- 		if ( el.classList ) {
 
- 			el.classList.add(className);
 
- 		} else {
 
- 			el.className += ' ' + className;
 
- 		}
 
- 	}
 
- 	// http://youmightnotneedjquery.com/#remove_class
 
- 	function removeClass ( el, className ) {
 
- 		if ( el.classList ) {
 
- 			el.classList.remove(className);
 
- 		} else {
 
- 			el.className = el.className.replace(new RegExp('(^|\\b)' + className.split(' ').join('|') + '(\\b|$)', 'gi'), ' ');
 
- 		}
 
- 	}
 
- 	// https://plainjs.com/javascript/attributes/adding-removing-and-testing-for-classes-9/
 
- 	function hasClass ( el, className ) {
 
- 		return el.classList ? el.classList.contains(className) : new RegExp('\\b' + className + '\\b').test(el.className);
 
- 	}
 
- 	// https://developer.mozilla.org/en-US/docs/Web/API/Window/scrollY#Notes
 
- 	function getPageOffset ( ) {
 
- 		var supportPageOffset = window.pageXOffset !== undefined,
 
- 			isCSS1Compat = ((document.compatMode || "") === "CSS1Compat"),
 
- 			x = supportPageOffset ? window.pageXOffset : isCSS1Compat ? document.documentElement.scrollLeft : document.body.scrollLeft,
 
- 			y = supportPageOffset ? window.pageYOffset : isCSS1Compat ? document.documentElement.scrollTop : document.body.scrollTop;
 
- 		return {
 
- 			x: x,
 
- 			y: y
 
- 		};
 
- 	}
 
- 	// we provide a function to compute constants instead
 
- 	// of accessing window.* as soon as the module needs it
 
- 	// so that we do not compute anything if not needed
 
- 	function getActions ( ) {
 
- 		// Determine the events to bind. IE11 implements pointerEvents without
 
- 		// a prefix, which breaks compatibility with the IE10 implementation.
 
- 		return window.navigator.pointerEnabled ? {
 
- 			start: 'pointerdown',
 
- 			move: 'pointermove',
 
- 			end: 'pointerup'
 
- 		} : window.navigator.msPointerEnabled ? {
 
- 			start: 'MSPointerDown',
 
- 			move: 'MSPointerMove',
 
- 			end: 'MSPointerUp'
 
- 		} : {
 
- 			start: 'mousedown touchstart',
 
- 			move: 'mousemove touchmove',
 
- 			end: 'mouseup touchend'
 
- 		};
 
- 	}
 
- // Value calculation
 
- 	// Determine the size of a sub-range in relation to a full range.
 
- 	function subRangeRatio ( pa, pb ) {
 
- 		return (100 / (pb - pa));
 
- 	}
 
- 	// (percentage) How many percent is this value of this range?
 
- 	function fromPercentage ( range, value ) {
 
- 		return (value * 100) / ( range[1] - range[0] );
 
- 	}
 
- 	// (percentage) Where is this value on this range?
 
- 	function toPercentage ( range, value ) {
 
- 		return fromPercentage( range, range[0] < 0 ?
 
- 			value + Math.abs(range[0]) :
 
- 				value - range[0] );
 
- 	}
 
- 	// (value) How much is this percentage on this range?
 
- 	function isPercentage ( range, value ) {
 
- 		return ((value * ( range[1] - range[0] )) / 100) + range[0];
 
- 	}
 
- // Range conversion
 
- 	function getJ ( value, arr ) {
 
- 		var j = 1;
 
- 		while ( value >= arr[j] ){
 
- 			j += 1;
 
- 		}
 
- 		return j;
 
- 	}
 
- 	// (percentage) Input a value, find where, on a scale of 0-100, it applies.
 
- 	function toStepping ( xVal, xPct, value ) {
 
- 		if ( value >= xVal.slice(-1)[0] ){
 
- 			return 100;
 
- 		}
 
- 		var j = getJ( value, xVal ), va, vb, pa, pb;
 
- 		va = xVal[j-1];
 
- 		vb = xVal[j];
 
- 		pa = xPct[j-1];
 
- 		pb = xPct[j];
 
- 		return pa + (toPercentage([va, vb], value) / subRangeRatio (pa, pb));
 
- 	}
 
- 	// (value) Input a percentage, find where it is on the specified range.
 
- 	function fromStepping ( xVal, xPct, value ) {
 
- 		// There is no range group that fits 100
 
- 		if ( value >= 100 ){
 
- 			return xVal.slice(-1)[0];
 
- 		}
 
- 		var j = getJ( value, xPct ), va, vb, pa, pb;
 
- 		va = xVal[j-1];
 
- 		vb = xVal[j];
 
- 		pa = xPct[j-1];
 
- 		pb = xPct[j];
 
- 		return isPercentage([va, vb], (value - pa) * subRangeRatio (pa, pb));
 
- 	}
 
- 	// (percentage) Get the step that applies at a certain value.
 
- 	function getStep ( xPct, xSteps, snap, value ) {
 
- 		if ( value === 100 ) {
 
- 			return value;
 
- 		}
 
- 		var j = getJ( value, xPct ), a, b;
 
- 		// If 'snap' is set, steps are used as fixed points on the slider.
 
- 		if ( snap ) {
 
- 			a = xPct[j-1];
 
- 			b = xPct[j];
 
- 			// Find the closest position, a or b.
 
- 			if ((value - a) > ((b-a)/2)){
 
- 				return b;
 
- 			}
 
- 			return a;
 
- 		}
 
- 		if ( !xSteps[j-1] ){
 
- 			return value;
 
- 		}
 
- 		return xPct[j-1] + closest(
 
- 			value - xPct[j-1],
 
- 			xSteps[j-1]
 
- 		);
 
- 	}
 
- // Entry parsing
 
- 	function handleEntryPoint ( index, value, that ) {
 
- 		var percentage;
 
- 		// Wrap numerical input in an array.
 
- 		if ( typeof value === "number" ) {
 
- 			value = [value];
 
- 		}
 
- 		// Reject any invalid input, by testing whether value is an array.
 
- 		if ( Object.prototype.toString.call( value ) !== '[object Array]' ){
 
- 			throw new Error("noUiSlider: 'range' contains invalid value.");
 
- 		}
 
- 		// Covert min/max syntax to 0 and 100.
 
- 		if ( index === 'min' ) {
 
- 			percentage = 0;
 
- 		} else if ( index === 'max' ) {
 
- 			percentage = 100;
 
- 		} else {
 
- 			percentage = parseFloat( index );
 
- 		}
 
- 		// Check for correct input.
 
- 		if ( !isNumeric( percentage ) || !isNumeric( value[0] ) ) {
 
- 			throw new Error("noUiSlider: 'range' value isn't numeric.");
 
- 		}
 
- 		// Store values.
 
- 		that.xPct.push( percentage );
 
- 		that.xVal.push( value[0] );
 
- 		// NaN will evaluate to false too, but to keep
 
- 		// logging clear, set step explicitly. Make sure
 
- 		// not to override the 'step' setting with false.
 
- 		if ( !percentage ) {
 
- 			if ( !isNaN( value[1] ) ) {
 
- 				that.xSteps[0] = value[1];
 
- 			}
 
- 		} else {
 
- 			that.xSteps.push( isNaN(value[1]) ? false : value[1] );
 
- 		}
 
- 	}
 
- 	function handleStepPoint ( i, n, that ) {
 
- 		// Ignore 'false' stepping.
 
- 		if ( !n ) {
 
- 			return true;
 
- 		}
 
- 		// Factor to range ratio
 
- 		that.xSteps[i] = fromPercentage([
 
- 			 that.xVal[i]
 
- 			,that.xVal[i+1]
 
- 		], n) / subRangeRatio (
 
- 			that.xPct[i],
 
- 			that.xPct[i+1] );
 
- 	}
 
- // Interface
 
- 	// The interface to Spectrum handles all direction-based
 
- 	// conversions, so the above values are unaware.
 
- 	function Spectrum ( entry, snap, direction, singleStep ) {
 
- 		this.xPct = [];
 
- 		this.xVal = [];
 
- 		this.xSteps = [ singleStep || false ];
 
- 		this.xNumSteps = [ false ];
 
- 		this.snap = snap;
 
- 		this.direction = direction;
 
- 		var index, ordered = [ /* [0, 'min'], [1, '50%'], [2, 'max'] */ ];
 
- 		// Map the object keys to an array.
 
- 		for ( index in entry ) {
 
- 			if ( entry.hasOwnProperty(index) ) {
 
- 				ordered.push([entry[index], index]);
 
- 			}
 
- 		}
 
- 		// Sort all entries by value (numeric sort).
 
- 		if ( ordered.length && typeof ordered[0][0] === "object" ) {
 
- 			ordered.sort(function(a, b) { return a[0][0] - b[0][0]; });
 
- 		} else {
 
- 			ordered.sort(function(a, b) { return a[0] - b[0]; });
 
- 		}
 
- 		// Convert all entries to subranges.
 
- 		for ( index = 0; index < ordered.length; index++ ) {
 
- 			handleEntryPoint(ordered[index][1], ordered[index][0], this);
 
- 		}
 
- 		// Store the actual step values.
 
- 		// xSteps is sorted in the same order as xPct and xVal.
 
- 		this.xNumSteps = this.xSteps.slice(0);
 
- 		// Convert all numeric steps to the percentage of the subrange they represent.
 
- 		for ( index = 0; index < this.xNumSteps.length; index++ ) {
 
- 			handleStepPoint(index, this.xNumSteps[index], this);
 
- 		}
 
- 	}
 
- 	Spectrum.prototype.getMargin = function ( value ) {
 
- 		return this.xPct.length === 2 ? fromPercentage(this.xVal, value) : false;
 
- 	};
 
- 	Spectrum.prototype.toStepping = function ( value ) {
 
- 		value = toStepping( this.xVal, this.xPct, value );
 
- 		// Invert the value if this is a right-to-left slider.
 
- 		if ( this.direction ) {
 
- 			value = 100 - value;
 
- 		}
 
- 		return value;
 
- 	};
 
- 	Spectrum.prototype.fromStepping = function ( value ) {
 
- 		// Invert the value if this is a right-to-left slider.
 
- 		if ( this.direction ) {
 
- 			value = 100 - value;
 
- 		}
 
- 		return fromStepping( this.xVal, this.xPct, value );
 
- 	};
 
- 	Spectrum.prototype.getStep = function ( value ) {
 
- 		// Find the proper step for rtl sliders by search in inverse direction.
 
- 		// Fixes issue #262.
 
- 		if ( this.direction ) {
 
- 			value = 100 - value;
 
- 		}
 
- 		value = getStep(this.xPct, this.xSteps, this.snap, value );
 
- 		if ( this.direction ) {
 
- 			value = 100 - value;
 
- 		}
 
- 		return value;
 
- 	};
 
- 	Spectrum.prototype.getApplicableStep = function ( value ) {
 
- 		// If the value is 100%, return the negative step twice.
 
- 		var j = getJ(value, this.xPct), offset = value === 100 ? 2 : 1;
 
- 		return [this.xNumSteps[j-2], this.xVal[j-offset], this.xNumSteps[j-offset]];
 
- 	};
 
- 	// Outside testing
 
- 	Spectrum.prototype.convert = function ( value ) {
 
- 		return this.getStep(this.toStepping(value));
 
- 	};
 
- /*	Every input option is tested and parsed. This'll prevent
 
- 	endless validation in internal methods. These tests are
 
- 	structured with an item for every option available. An
 
- 	option can be marked as required by setting the 'r' flag.
 
- 	The testing function is provided with three arguments:
 
- 		- The provided value for the option;
 
- 		- A reference to the options object;
 
- 		- The name for the option;
 
- 	The testing function returns false when an error is detected,
 
- 	or true when everything is OK. It can also modify the option
 
- 	object, to make sure all values can be correctly looped elsewhere. */
 
- 	var defaultFormatter = { 'to': function( value ){
 
- 		return value !== undefined && value.toFixed(2);
 
- 	}, 'from': Number };
 
- 	function testStep ( parsed, entry ) {
 
- 		if ( !isNumeric( entry ) ) {
 
- 			throw new Error("noUiSlider: 'step' is not numeric.");
 
- 		}
 
- 		// The step option can still be used to set stepping
 
- 		// for linear sliders. Overwritten if set in 'range'.
 
- 		parsed.singleStep = entry;
 
- 	}
 
- 	function testRange ( parsed, entry ) {
 
- 		// Filter incorrect input.
 
- 		if ( typeof entry !== 'object' || Array.isArray(entry) ) {
 
- 			throw new Error("noUiSlider: 'range' is not an object.");
 
- 		}
 
- 		// Catch missing start or end.
 
- 		if ( entry.min === undefined || entry.max === undefined ) {
 
- 			throw new Error("noUiSlider: Missing 'min' or 'max' in 'range'.");
 
- 		}
 
- 		// Catch equal start or end.
 
- 		if ( entry.min === entry.max ) {
 
- 			throw new Error("noUiSlider: 'range' 'min' and 'max' cannot be equal.");
 
- 		}
 
- 		parsed.spectrum = new Spectrum(entry, parsed.snap, parsed.dir, parsed.singleStep);
 
- 	}
 
- 	function testStart ( parsed, entry ) {
 
- 		entry = asArray(entry);
 
- 		// Validate input. Values aren't tested, as the public .val method
 
- 		// will always provide a valid location.
 
- 		if ( !Array.isArray( entry ) || !entry.length || entry.length > 2 ) {
 
- 			throw new Error("noUiSlider: 'start' option is incorrect.");
 
- 		}
 
- 		// Store the number of handles.
 
- 		parsed.handles = entry.length;
 
- 		// When the slider is initialized, the .val method will
 
- 		// be called with the start options.
 
- 		parsed.start = entry;
 
- 	}
 
- 	function testSnap ( parsed, entry ) {
 
- 		// Enforce 100% stepping within subranges.
 
- 		parsed.snap = entry;
 
- 		if ( typeof entry !== 'boolean' ){
 
- 			throw new Error("noUiSlider: 'snap' option must be a boolean.");
 
- 		}
 
- 	}
 
- 	function testAnimate ( parsed, entry ) {
 
- 		// Enforce 100% stepping within subranges.
 
- 		parsed.animate = entry;
 
- 		if ( typeof entry !== 'boolean' ){
 
- 			throw new Error("noUiSlider: 'animate' option must be a boolean.");
 
- 		}
 
- 	}
 
- 	function testAnimationDuration ( parsed, entry ) {
 
- 		parsed.animationDuration = entry;
 
- 		if ( typeof entry !== 'number' ){
 
- 			throw new Error("noUiSlider: 'animationDuration' option must be a number.");
 
- 		}
 
- 	}
 
- 	function testConnect ( parsed, entry ) {
 
- 		if ( entry === 'lower' && parsed.handles === 1 ) {
 
- 			parsed.connect = 1;
 
- 		} else if ( entry === 'upper' && parsed.handles === 1 ) {
 
- 			parsed.connect = 2;
 
- 		} else if ( entry === true && parsed.handles === 2 ) {
 
- 			parsed.connect = 3;
 
- 		} else if ( entry === false ) {
 
- 			parsed.connect = 0;
 
- 		} else {
 
- 			throw new Error("noUiSlider: 'connect' option doesn't match handle count.");
 
- 		}
 
- 	}
 
- 	function testOrientation ( parsed, entry ) {
 
- 		// Set orientation to an a numerical value for easy
 
- 		// array selection.
 
- 		switch ( entry ){
 
- 		  case 'horizontal':
 
- 			parsed.ort = 0;
 
- 			break;
 
- 		  case 'vertical':
 
- 			parsed.ort = 1;
 
- 			break;
 
- 		  default:
 
- 			throw new Error("noUiSlider: 'orientation' option is invalid.");
 
- 		}
 
- 	}
 
- 	function testMargin ( parsed, entry ) {
 
- 		if ( !isNumeric(entry) ){
 
- 			throw new Error("noUiSlider: 'margin' option must be numeric.");
 
- 		}
 
- 		// Issue #582
 
- 		if ( entry === 0 ) {
 
- 			return;
 
- 		}
 
- 		parsed.margin = parsed.spectrum.getMargin(entry);
 
- 		if ( !parsed.margin ) {
 
- 			throw new Error("noUiSlider: 'margin' option is only supported on linear sliders.");
 
- 		}
 
- 	}
 
- 	function testLimit ( parsed, entry ) {
 
- 		if ( !isNumeric(entry) ){
 
- 			throw new Error("noUiSlider: 'limit' option must be numeric.");
 
- 		}
 
- 		parsed.limit = parsed.spectrum.getMargin(entry);
 
- 		if ( !parsed.limit ) {
 
- 			throw new Error("noUiSlider: 'limit' option is only supported on linear sliders.");
 
- 		}
 
- 	}
 
- 	function testDirection ( parsed, entry ) {
 
- 		// Set direction as a numerical value for easy parsing.
 
- 		// Invert connection for RTL sliders, so that the proper
 
- 		// handles get the connect/background classes.
 
- 		switch ( entry ) {
 
- 		  case 'ltr':
 
- 			parsed.dir = 0;
 
- 			break;
 
- 		  case 'rtl':
 
- 			parsed.dir = 1;
 
- 			parsed.connect = [0,2,1,3][parsed.connect];
 
- 			break;
 
- 		  default:
 
- 			throw new Error("noUiSlider: 'direction' option was not recognized.");
 
- 		}
 
- 	}
 
- 	function testBehaviour ( parsed, entry ) {
 
- 		// Make sure the input is a string.
 
- 		if ( typeof entry !== 'string' ) {
 
- 			throw new Error("noUiSlider: 'behaviour' must be a string containing options.");
 
- 		}
 
- 		// Check if the string contains any keywords.
 
- 		// None are required.
 
- 		var tap = entry.indexOf('tap') >= 0,
 
- 			drag = entry.indexOf('drag') >= 0,
 
- 			fixed = entry.indexOf('fixed') >= 0,
 
- 			snap = entry.indexOf('snap') >= 0,
 
- 			hover = entry.indexOf('hover') >= 0;
 
- 		// Fix #472
 
- 		if ( drag && !parsed.connect ) {
 
- 			throw new Error("noUiSlider: 'drag' behaviour must be used with 'connect': true.");
 
- 		}
 
- 		parsed.events = {
 
- 			tap: tap || snap,
 
- 			drag: drag,
 
- 			fixed: fixed,
 
- 			snap: snap,
 
- 			hover: hover
 
- 		};
 
- 	}
 
- 	function testTooltips ( parsed, entry ) {
 
- 		var i;
 
- 		if ( entry === false ) {
 
- 			return;
 
- 		} else if ( entry === true ) {
 
- 			parsed.tooltips = [];
 
- 			for ( i = 0; i < parsed.handles; i++ ) {
 
- 				parsed.tooltips.push(true);
 
- 			}
 
- 		} else {
 
- 			parsed.tooltips = asArray(entry);
 
- 			if ( parsed.tooltips.length !== parsed.handles ) {
 
- 				throw new Error("noUiSlider: must pass a formatter for all handles.");
 
- 			}
 
- 			parsed.tooltips.forEach(function(formatter){
 
- 				if ( typeof formatter !== 'boolean' && (typeof formatter !== 'object' || typeof formatter.to !== 'function') ) {
 
- 					throw new Error("noUiSlider: 'tooltips' must be passed a formatter or 'false'.");
 
- 				}
 
- 			});
 
- 		}
 
- 	}
 
- 	function testFormat ( parsed, entry ) {
 
- 		parsed.format = entry;
 
- 		// Any object with a to and from method is supported.
 
- 		if ( typeof entry.to === 'function' && typeof entry.from === 'function' ) {
 
- 			return true;
 
- 		}
 
- 		throw new Error("noUiSlider: 'format' requires 'to' and 'from' methods.");
 
- 	}
 
- 	function testCssPrefix ( parsed, entry ) {
 
- 		if ( entry !== undefined && typeof entry !== 'string' && entry !== false ) {
 
- 			throw new Error("noUiSlider: 'cssPrefix' must be a string or `false`.");
 
- 		}
 
- 		parsed.cssPrefix = entry;
 
- 	}
 
- 	function testCssClasses ( parsed, entry ) {
 
- 		if ( entry !== undefined && typeof entry !== 'object' ) {
 
- 			throw new Error("noUiSlider: 'cssClasses' must be an object.");
 
- 		}
 
- 		if ( typeof parsed.cssPrefix === 'string' ) {
 
- 			parsed.cssClasses = {};
 
- 			for ( var key in entry ) {
 
- 				if ( !entry.hasOwnProperty(key) ) { continue; }
 
- 				parsed.cssClasses[key] = parsed.cssPrefix + entry[key];
 
- 			}
 
- 		} else {
 
- 			parsed.cssClasses = entry;
 
- 		}
 
- 	}
 
- 	// Test all developer settings and parse to assumption-safe values.
 
- 	function testOptions ( options ) {
 
- 		// To prove a fix for #537, freeze options here.
 
- 		// If the object is modified, an error will be thrown.
 
- 		// Object.freeze(options);
 
- 		var parsed = {
 
- 			margin: 0,
 
- 			limit: 0,
 
- 			animate: true,
 
- 			animationDuration: 300,
 
- 			format: defaultFormatter
 
- 		}, tests;
 
- 		// Tests are executed in the order they are presented here.
 
- 		tests = {
 
- 			'step': { r: false, t: testStep },
 
- 			'start': { r: true, t: testStart },
 
- 			'connect': { r: true, t: testConnect },
 
- 			'direction': { r: true, t: testDirection },
 
- 			'snap': { r: false, t: testSnap },
 
- 			'animate': { r: false, t: testAnimate },
 
- 			'animationDuration': { r: false, t: testAnimationDuration },
 
- 			'range': { r: true, t: testRange },
 
- 			'orientation': { r: false, t: testOrientation },
 
- 			'margin': { r: false, t: testMargin },
 
- 			'limit': { r: false, t: testLimit },
 
- 			'behaviour': { r: true, t: testBehaviour },
 
- 			'format': { r: false, t: testFormat },
 
- 			'tooltips': { r: false, t: testTooltips },
 
- 			'cssPrefix': { r: false, t: testCssPrefix },
 
- 			'cssClasses': { r: false, t: testCssClasses }
 
- 		};
 
- 		var defaults = {
 
- 			'connect': false,
 
- 			'direction': 'ltr',
 
- 			'behaviour': 'tap',
 
- 			'orientation': 'horizontal',
 
- 			'cssPrefix' : 'noUi-',
 
- 			'cssClasses': {
 
- 				target: 'target',
 
- 				base: 'base',
 
- 				origin: 'origin',
 
- 				handle: 'handle',
 
- 				handleLower: 'handle-lower',
 
- 				handleUpper: 'handle-upper',
 
- 				horizontal: 'horizontal',
 
- 				vertical: 'vertical',
 
- 				background: 'background',
 
- 				connect: 'connect',
 
- 				ltr: 'ltr',
 
- 				rtl: 'rtl',
 
- 				draggable: 'draggable',
 
- 				drag: 'state-drag',
 
- 				tap: 'state-tap',
 
- 				active: 'active',
 
- 				stacking: 'stacking',
 
- 				tooltip: 'tooltip',
 
- 				pips: 'pips',
 
- 				pipsHorizontal: 'pips-horizontal',
 
- 				pipsVertical: 'pips-vertical',
 
- 				marker: 'marker',
 
- 				markerHorizontal: 'marker-horizontal',
 
- 				markerVertical: 'marker-vertical',
 
- 				markerNormal: 'marker-normal',
 
- 				markerLarge: 'marker-large',
 
- 				markerSub: 'marker-sub',
 
- 				value: 'value',
 
- 				valueHorizontal: 'value-horizontal',
 
- 				valueVertical: 'value-vertical',
 
- 				valueNormal: 'value-normal',
 
- 				valueLarge: 'value-large',
 
- 				valueSub: 'value-sub'
 
- 			}
 
- 		};
 
- 		// Run all options through a testing mechanism to ensure correct
 
- 		// input. It should be noted that options might get modified to
 
- 		// be handled properly. E.g. wrapping integers in arrays.
 
- 		Object.keys(tests).forEach(function( name ){
 
- 			// If the option isn't set, but it is required, throw an error.
 
- 			if ( options[name] === undefined && defaults[name] === undefined ) {
 
- 				if ( tests[name].r ) {
 
- 					throw new Error("noUiSlider: '" + name + "' is required.");
 
- 				}
 
- 				return true;
 
- 			}
 
- 			tests[name].t( parsed, options[name] === undefined ? defaults[name] : options[name] );
 
- 		});
 
- 		// Forward pips options
 
- 		parsed.pips = options.pips;
 
- 		// Pre-define the styles.
 
- 		parsed.style = parsed.ort ? 'top' : 'left';
 
- 		return parsed;
 
- 	}
 
- function closure ( target, options, originalOptions ){
 
- 	var
 
- 		actions = getActions( ),
 
- 		// All variables local to 'closure' are prefixed with 'scope_'
 
- 		scope_Target = target,
 
- 		scope_Locations = [-1, -1],
 
- 		scope_Base,
 
- 		scope_Handles,
 
- 		scope_Spectrum = options.spectrum,
 
- 		scope_Values = [],
 
- 		scope_Events = {},
 
- 		scope_Self;
 
- 	// Delimit proposed values for handle positions.
 
- 	function getPositions ( a, b, delimit ) {
 
- 		// Add movement to current position.
 
- 		var c = a + b[0], d = a + b[1];
 
- 		// Only alter the other position on drag,
 
- 		// not on standard sliding.
 
- 		if ( delimit ) {
 
- 			if ( c < 0 ) {
 
- 				d += Math.abs(c);
 
- 			}
 
- 			if ( d > 100 ) {
 
- 				c -= ( d - 100 );
 
- 			}
 
- 			// Limit values to 0 and 100.
 
- 			return [limit(c), limit(d)];
 
- 		}
 
- 		return [c,d];
 
- 	}
 
- 	// Provide a clean event with standardized offset values.
 
- 	function fixEvent ( e, pageOffset ) {
 
- 		// Prevent scrolling and panning on touch events, while
 
- 		// attempting to slide. The tap event also depends on this.
 
- 		e.preventDefault();
 
- 		// Filter the event to register the type, which can be
 
- 		// touch, mouse or pointer. Offset changes need to be
 
- 		// made on an event specific basis.
 
- 		var touch = e.type.indexOf('touch') === 0,
 
- 			mouse = e.type.indexOf('mouse') === 0,
 
- 			pointer = e.type.indexOf('pointer') === 0,
 
- 			x,y, event = e;
 
- 		// IE10 implemented pointer events with a prefix;
 
- 		if ( e.type.indexOf('MSPointer') === 0 ) {
 
- 			pointer = true;
 
- 		}
 
- 		if ( touch ) {
 
- 			// noUiSlider supports one movement at a time,
 
- 			// so we can select the first 'changedTouch'.
 
- 			x = e.changedTouches[0].pageX;
 
- 			y = e.changedTouches[0].pageY;
 
- 		}
 
- 		pageOffset = pageOffset || getPageOffset();
 
- 		if ( mouse || pointer ) {
 
- 			x = e.clientX + pageOffset.x;
 
- 			y = e.clientY + pageOffset.y;
 
- 		}
 
- 		event.pageOffset = pageOffset;
 
- 		event.points = [x, y];
 
- 		event.cursor = mouse || pointer; // Fix #435
 
- 		return event;
 
- 	}
 
- 	// Append a handle to the base.
 
- 	function addHandle ( direction, index ) {
 
- 		var origin = document.createElement('div'),
 
- 			handle = document.createElement('div'),
 
- 			classModifier = [options.cssClasses.handleLower, options.cssClasses.handleUpper];
 
- 		if ( direction ) {
 
- 			classModifier.reverse();
 
- 		}
 
- 		addClass(handle, options.cssClasses.handle);
 
- 		addClass(handle, classModifier[index]);
 
- 		addClass(origin, options.cssClasses.origin);
 
- 		origin.appendChild(handle);
 
- 		return origin;
 
- 	}
 
- 	// Add the proper connection classes.
 
- 	function addConnection ( connect, target, handles ) {
 
- 		// Apply the required connection classes to the elements
 
- 		// that need them. Some classes are made up for several
 
- 		// segments listed in the class list, to allow easy
 
- 		// renaming and provide a minor compression benefit.
 
- 		switch ( connect ) {
 
- 			case 1:	addClass(target, options.cssClasses.connect);
 
- 					addClass(handles[0], options.cssClasses.background);
 
- 					break;
 
- 			case 3: addClass(handles[1], options.cssClasses.background);
 
- 					/* falls through */
 
- 			case 2: addClass(handles[0], options.cssClasses.connect);
 
- 					/* falls through */
 
- 			case 0: addClass(target, options.cssClasses.background);
 
- 					break;
 
- 		}
 
- 	}
 
- 	// Add handles to the slider base.
 
- 	function addHandles ( nrHandles, direction, base ) {
 
- 		var index, handles = [];
 
- 		// Append handles.
 
- 		for ( index = 0; index < nrHandles; index += 1 ) {
 
- 			// Keep a list of all added handles.
 
- 			handles.push( base.appendChild(addHandle( direction, index )) );
 
- 		}
 
- 		return handles;
 
- 	}
 
- 	// Initialize a single slider.
 
- 	function addSlider ( direction, orientation, target ) {
 
- 		// Apply classes and data to the target.
 
- 		addClass(target, options.cssClasses.target);
 
- 		if ( direction === 0 ) {
 
- 			addClass(target, options.cssClasses.ltr);
 
- 		} else {
 
- 			addClass(target, options.cssClasses.rtl);
 
- 		}
 
- 		if ( orientation === 0 ) {
 
- 			addClass(target, options.cssClasses.horizontal);
 
- 		} else {
 
- 			addClass(target, options.cssClasses.vertical);
 
- 		}
 
- 		var div = document.createElement('div');
 
- 		addClass(div, options.cssClasses.base);
 
- 		target.appendChild(div);
 
- 		return div;
 
- 	}
 
- 	function addTooltip ( handle, index ) {
 
- 		if ( !options.tooltips[index] ) {
 
- 			return false;
 
- 		}
 
- 		var element = document.createElement('div');
 
- 		element.className = options.cssClasses.tooltip;
 
- 		return handle.firstChild.appendChild(element);
 
- 	}
 
- 	// The tooltips option is a shorthand for using the 'update' event.
 
- 	function tooltips ( ) {
 
- 		if ( options.dir ) {
 
- 			options.tooltips.reverse();
 
- 		}
 
- 		// Tooltips are added with options.tooltips in original order.
 
- 		var tips = scope_Handles.map(addTooltip);
 
- 		if ( options.dir ) {
 
- 			tips.reverse();
 
- 			options.tooltips.reverse();
 
- 		}
 
- 		bindEvent('update', function(f, o, r) {
 
- 			if ( tips[o] ) {
 
- 				tips[o].innerHTML = options.tooltips[o] === true ? f[o] : options.tooltips[o].to(r[o]);
 
- 			}
 
- 		});
 
- 	}
 
- 	function getGroup ( mode, values, stepped ) {
 
- 		// Use the range.
 
- 		if ( mode === 'range' || mode === 'steps' ) {
 
- 			return scope_Spectrum.xVal;
 
- 		}
 
- 		if ( mode === 'count' ) {
 
- 			// Divide 0 - 100 in 'count' parts.
 
- 			var spread = ( 100 / (values-1) ), v, i = 0;
 
- 			values = [];
 
- 			// List these parts and have them handled as 'positions'.
 
- 			while ((v=i++*spread) <= 100 ) {
 
- 				values.push(v);
 
- 			}
 
- 			mode = 'positions';
 
- 		}
 
- 		if ( mode === 'positions' ) {
 
- 			// Map all percentages to on-range values.
 
- 			return values.map(function( value ){
 
- 				return scope_Spectrum.fromStepping( stepped ? scope_Spectrum.getStep( value ) : value );
 
- 			});
 
- 		}
 
- 		if ( mode === 'values' ) {
 
- 			// If the value must be stepped, it needs to be converted to a percentage first.
 
- 			if ( stepped ) {
 
- 				return values.map(function( value ){
 
- 					// Convert to percentage, apply step, return to value.
 
- 					return scope_Spectrum.fromStepping( scope_Spectrum.getStep( scope_Spectrum.toStepping( value ) ) );
 
- 				});
 
- 			}
 
- 			// Otherwise, we can simply use the values.
 
- 			return values;
 
- 		}
 
- 	}
 
- 	function generateSpread ( density, mode, group ) {
 
- 		function safeIncrement(value, increment) {
 
- 			// Avoid floating point variance by dropping the smallest decimal places.
 
- 			return (value + increment).toFixed(7) / 1;
 
- 		}
 
- 		var originalSpectrumDirection = scope_Spectrum.direction,
 
- 			indexes = {},
 
- 			firstInRange = scope_Spectrum.xVal[0],
 
- 			lastInRange = scope_Spectrum.xVal[scope_Spectrum.xVal.length-1],
 
- 			ignoreFirst = false,
 
- 			ignoreLast = false,
 
- 			prevPct = 0;
 
- 		// This function loops the spectrum in an ltr linear fashion,
 
- 		// while the toStepping method is direction aware. Trick it into
 
- 		// believing it is ltr.
 
- 		scope_Spectrum.direction = 0;
 
- 		// Create a copy of the group, sort it and filter away all duplicates.
 
- 		group = unique(group.slice().sort(function(a, b){ return a - b; }));
 
- 		// Make sure the range starts with the first element.
 
- 		if ( group[0] !== firstInRange ) {
 
- 			group.unshift(firstInRange);
 
- 			ignoreFirst = true;
 
- 		}
 
- 		// Likewise for the last one.
 
- 		if ( group[group.length - 1] !== lastInRange ) {
 
- 			group.push(lastInRange);
 
- 			ignoreLast = true;
 
- 		}
 
- 		group.forEach(function ( current, index ) {
 
- 			// Get the current step and the lower + upper positions.
 
- 			var step, i, q,
 
- 				low = current,
 
- 				high = group[index+1],
 
- 				newPct, pctDifference, pctPos, type,
 
- 				steps, realSteps, stepsize;
 
- 			// When using 'steps' mode, use the provided steps.
 
- 			// Otherwise, we'll step on to the next subrange.
 
- 			if ( mode === 'steps' ) {
 
- 				step = scope_Spectrum.xNumSteps[ index ];
 
- 			}
 
- 			// Default to a 'full' step.
 
- 			if ( !step ) {
 
- 				step = high-low;
 
- 			}
 
- 			// Low can be 0, so test for false. If high is undefined,
 
- 			// we are at the last subrange. Index 0 is already handled.
 
- 			if ( low === false || high === undefined ) {
 
- 				return;
 
- 			}
 
- 			// Find all steps in the subrange.
 
- 			for ( i = low; i <= high; i = safeIncrement(i, step) ) {
 
- 				// Get the percentage value for the current step,
 
- 				// calculate the size for the subrange.
 
- 				newPct = scope_Spectrum.toStepping( i );
 
- 				pctDifference = newPct - prevPct;
 
- 				steps = pctDifference / density;
 
- 				realSteps = Math.round(steps);
 
- 				// This ratio represents the ammount of percentage-space a point indicates.
 
- 				// For a density 1 the points/percentage = 1. For density 2, that percentage needs to be re-devided.
 
- 				// Round the percentage offset to an even number, then divide by two
 
- 				// to spread the offset on both sides of the range.
 
- 				stepsize = pctDifference/realSteps;
 
- 				// Divide all points evenly, adding the correct number to this subrange.
 
- 				// Run up to <= so that 100% gets a point, event if ignoreLast is set.
 
- 				for ( q = 1; q <= realSteps; q += 1 ) {
 
- 					// The ratio between the rounded value and the actual size might be ~1% off.
 
- 					// Correct the percentage offset by the number of points
 
- 					// per subrange. density = 1 will result in 100 points on the
 
- 					// full range, 2 for 50, 4 for 25, etc.
 
- 					pctPos = prevPct + ( q * stepsize );
 
- 					indexes[pctPos.toFixed(5)] = ['x', 0];
 
- 				}
 
- 				// Determine the point type.
 
- 				type = (group.indexOf(i) > -1) ? 1 : ( mode === 'steps' ? 2 : 0 );
 
- 				// Enforce the 'ignoreFirst' option by overwriting the type for 0.
 
- 				if ( !index && ignoreFirst ) {
 
- 					type = 0;
 
- 				}
 
- 				if ( !(i === high && ignoreLast)) {
 
- 					// Mark the 'type' of this point. 0 = plain, 1 = real value, 2 = step value.
 
- 					indexes[newPct.toFixed(5)] = [i, type];
 
- 				}
 
- 				// Update the percentage count.
 
- 				prevPct = newPct;
 
- 			}
 
- 		});
 
- 		// Reset the spectrum.
 
- 		scope_Spectrum.direction = originalSpectrumDirection;
 
- 		return indexes;
 
- 	}
 
- 	function addMarking ( spread, filterFunc, formatter ) {
 
- 		var element = document.createElement('div'),
 
- 			out = '',
 
- 			valueSizeClasses = [
 
- 				options.cssClasses.valueNormal,
 
- 				options.cssClasses.valueLarge,
 
- 				options.cssClasses.valueSub
 
- 			],
 
- 			markerSizeClasses = [
 
- 				options.cssClasses.markerNormal,
 
- 				options.cssClasses.markerLarge,
 
- 				options.cssClasses.markerSub
 
- 			],
 
- 			valueOrientationClasses = [
 
- 				options.cssClasses.valueHorizontal,
 
- 				options.cssClasses.valueVertical
 
- 			],
 
- 			markerOrientationClasses = [
 
- 				options.cssClasses.markerHorizontal,
 
- 				options.cssClasses.markerVertical
 
- 			];
 
- 		addClass(element, options.cssClasses.pips);
 
- 		addClass(element, options.ort === 0 ? options.cssClasses.pipsHorizontal : options.cssClasses.pipsVertical);
 
- 		function getClasses( type, source ){
 
- 			var a = source === options.cssClasses.value,
 
- 				orientationClasses = a ? valueOrientationClasses : markerOrientationClasses,
 
- 				sizeClasses = a ? valueSizeClasses : markerSizeClasses;
 
- 			return source + ' ' + orientationClasses[options.ort] + ' ' + sizeClasses[type];
 
- 		}
 
- 		function getTags( offset, source, values ) {
 
- 			return 'class="' + getClasses(values[1], source) + '" style="' + options.style + ': ' + offset + '%"';
 
- 		}
 
- 		function addSpread ( offset, values ){
 
- 			if ( scope_Spectrum.direction ) {
 
- 				offset = 100 - offset;
 
- 			}
 
- 			// Apply the filter function, if it is set.
 
- 			values[1] = (values[1] && filterFunc) ? filterFunc(values[0], values[1]) : values[1];
 
- 			// Add a marker for every point
 
- 			out += '<div ' + getTags(offset, options.cssClasses.marker, values) + '></div>';
 
- 			// Values are only appended for points marked '1' or '2'.
 
- 			if ( values[1] ) {
 
- 				out += '<div ' + getTags(offset, options.cssClasses.value, values) + '>' + formatter.to(values[0]) + '</div>';
 
- 			}
 
- 		}
 
- 		// Append all points.
 
- 		Object.keys(spread).forEach(function(a){
 
- 			addSpread(a, spread[a]);
 
- 		});
 
- 		element.innerHTML = out;
 
- 		return element;
 
- 	}
 
- 	function pips ( grid ) {
 
- 	var mode = grid.mode,
 
- 		density = grid.density || 1,
 
- 		filter = grid.filter || false,
 
- 		values = grid.values || false,
 
- 		stepped = grid.stepped || false,
 
- 		group = getGroup( mode, values, stepped ),
 
- 		spread = generateSpread( density, mode, group ),
 
- 		format = grid.format || {
 
- 			to: Math.round
 
- 		};
 
- 		return scope_Target.appendChild(addMarking(
 
- 			spread,
 
- 			filter,
 
- 			format
 
- 		));
 
- 	}
 
- 	// Shorthand for base dimensions.
 
- 	function baseSize ( ) {
 
- 		var rect = scope_Base.getBoundingClientRect(), alt = 'offset' + ['Width', 'Height'][options.ort];
 
- 		return options.ort === 0 ? (rect.width||scope_Base[alt]) : (rect.height||scope_Base[alt]);
 
- 	}
 
- 	// External event handling
 
- 	function fireEvent ( event, handleNumber, tap ) {
 
- 		var i;
 
- 		// During initialization, do not fire events.
 
- 		for ( i = 0; i < options.handles; i++ ) {
 
- 			if ( scope_Locations[i] === -1 ) {
 
- 				return;
 
- 			}
 
- 		}
 
- 		if ( handleNumber !== undefined && options.handles !== 1 ) {
 
- 			handleNumber = Math.abs(handleNumber - options.dir);
 
- 		}
 
- 		Object.keys(scope_Events).forEach(function( targetEvent ) {
 
- 			var eventType = targetEvent.split('.')[0];
 
- 			if ( event === eventType ) {
 
- 				scope_Events[targetEvent].forEach(function( callback ) {
 
- 					callback.call(
 
- 						// Use the slider public API as the scope ('this')
 
- 						scope_Self,
 
- 						// Return values as array, so arg_1[arg_2] is always valid.
 
- 						asArray(valueGet()),
 
- 						// Handle index, 0 or 1
 
- 						handleNumber,
 
- 						// Unformatted slider values
 
- 						asArray(inSliderOrder(Array.prototype.slice.call(scope_Values))),
 
- 						// Event is fired by tap, true or false
 
- 						tap || false,
 
- 						// Left offset of the handle, in relation to the slider
 
- 						scope_Locations
 
- 					);
 
- 				});
 
- 			}
 
- 		});
 
- 	}
 
- 	// Returns the input array, respecting the slider direction configuration.
 
- 	function inSliderOrder ( values ) {
 
- 		// If only one handle is used, return a single value.
 
- 		if ( values.length === 1 ){
 
- 			return values[0];
 
- 		}
 
- 		if ( options.dir ) {
 
- 			return values.reverse();
 
- 		}
 
- 		return values;
 
- 	}
 
- 	// Handler for attaching events trough a proxy.
 
- 	function attach ( events, element, callback, data ) {
 
- 		// This function can be used to 'filter' events to the slider.
 
- 		// element is a node, not a nodeList
 
- 		var method = function ( e ){
 
- 			if ( scope_Target.hasAttribute('disabled') ) {
 
- 				return false;
 
- 			}
 
- 			// Stop if an active 'tap' transition is taking place.
 
- 			if ( hasClass(scope_Target, options.cssClasses.tap) ) {
 
- 				return false;
 
- 			}
 
- 			e = fixEvent(e, data.pageOffset);
 
- 			// Ignore right or middle clicks on start #454
 
- 			if ( events === actions.start && e.buttons !== undefined && e.buttons > 1 ) {
 
- 				return false;
 
- 			}
 
- 			// Ignore right or middle clicks on start #454
 
- 			if ( data.hover && e.buttons ) {
 
- 				return false;
 
- 			}
 
- 			e.calcPoint = e.points[ options.ort ];
 
- 			// Call the event handler with the event [ and additional data ].
 
- 			callback ( e, data );
 
- 		}, methods = [];
 
- 		// Bind a closure on the target for every event type.
 
- 		events.split(' ').forEach(function( eventName ){
 
- 			element.addEventListener(eventName, method, false);
 
- 			methods.push([eventName, method]);
 
- 		});
 
- 		return methods;
 
- 	}
 
- 	// Handle movement on document for handle and range drag.
 
- 	function move ( event, data ) {
 
- 		// Fix #498
 
- 		// Check value of .buttons in 'start' to work around a bug in IE10 mobile (data.buttonsProperty).
 
- 		// https://connect.microsoft.com/IE/feedback/details/927005/mobile-ie10-windows-phone-buttons-property-of-pointermove-event-always-zero
 
- 		// IE9 has .buttons and .which zero on mousemove.
 
- 		// Firefox breaks the spec MDN defines.
 
- 		if ( navigator.appVersion.indexOf("MSIE 9") === -1 && event.buttons === 0 && data.buttonsProperty !== 0 ) {
 
- 			return end(event, data);
 
- 		}
 
- 		var handles = data.handles || scope_Handles, positions, state = false,
 
- 			proposal = ((event.calcPoint - data.start) * 100) / data.baseSize,
 
- 			handleNumber = handles[0] === scope_Handles[0] ? 0 : 1, i;
 
- 		// Calculate relative positions for the handles.
 
- 		positions = getPositions( proposal, data.positions, handles.length > 1);
 
- 		state = setHandle ( handles[0], positions[handleNumber], handles.length === 1 );
 
- 		if ( handles.length > 1 ) {
 
- 			state = setHandle ( handles[1], positions[handleNumber?0:1], false ) || state;
 
- 			if ( state ) {
 
- 				// fire for both handles
 
- 				for ( i = 0; i < data.handles.length; i++ ) {
 
- 					fireEvent('slide', i);
 
- 				}
 
- 			}
 
- 		} else if ( state ) {
 
- 			// Fire for a single handle
 
- 			fireEvent('slide', handleNumber);
 
- 		}
 
- 	}
 
- 	// Unbind move events on document, call callbacks.
 
- 	function end ( event, data ) {
 
- 		// The handle is no longer active, so remove the class.
 
- 		var active = scope_Base.querySelector( '.' + options.cssClasses.active ),
 
- 			handleNumber = data.handles[0] === scope_Handles[0] ? 0 : 1;
 
- 		if ( active !== null ) {
 
- 			removeClass(active, options.cssClasses.active);
 
- 		}
 
- 		// Remove cursor styles and text-selection events bound to the body.
 
- 		if ( event.cursor ) {
 
- 			document.body.style.cursor = '';
 
- 			document.body.removeEventListener('selectstart', document.body.noUiListener);
 
- 		}
 
- 		var d = document.documentElement;
 
- 		// Unbind the move and end events, which are added on 'start'.
 
- 		d.noUiListeners.forEach(function( c ) {
 
- 			d.removeEventListener(c[0], c[1]);
 
- 		});
 
- 		// Remove dragging class.
 
- 		removeClass(scope_Target, options.cssClasses.drag);
 
- 		// Fire the change and set events.
 
- 		fireEvent('set', handleNumber);
 
- 		fireEvent('change', handleNumber);
 
- 		// If this is a standard handle movement, fire the end event.
 
- 		if ( data.handleNumber !== undefined ) {
 
- 			fireEvent('end', data.handleNumber);
 
- 		}
 
- 	}
 
- 	// Fire 'end' when a mouse or pen leaves the document.
 
- 	function documentLeave ( event, data ) {
 
- 		if ( event.type === "mouseout" && event.target.nodeName === "HTML" && event.relatedTarget === null ){
 
- 			end ( event, data );
 
- 		}
 
- 	}
 
- 	// Bind move events on document.
 
- 	function start ( event, data ) {
 
- 		var d = document.documentElement;
 
- 		// Mark the handle as 'active' so it can be styled.
 
- 		if ( data.handles.length === 1 ) {
 
- 			// Support 'disabled' handles
 
- 			if ( data.handles[0].hasAttribute('disabled') ) {
 
- 				return false;
 
- 			}
 
- 			addClass(data.handles[0].children[0], options.cssClasses.active);
 
- 		}
 
- 		// Fix #551, where a handle gets selected instead of dragged.
 
- 		event.preventDefault();
 
- 		// A drag should never propagate up to the 'tap' event.
 
- 		event.stopPropagation();
 
- 		// Attach the move and end events.
 
- 		var moveEvent = attach(actions.move, d, move, {
 
- 			start: event.calcPoint,
 
- 			baseSize: baseSize(),
 
- 			pageOffset: event.pageOffset,
 
- 			handles: data.handles,
 
- 			handleNumber: data.handleNumber,
 
- 			buttonsProperty: event.buttons,
 
- 			positions: [
 
- 				scope_Locations[0],
 
- 				scope_Locations[scope_Handles.length - 1]
 
- 			]
 
- 		}), endEvent = attach(actions.end, d, end, {
 
- 			handles: data.handles,
 
- 			handleNumber: data.handleNumber
 
- 		});
 
- 		var outEvent = attach("mouseout", d, documentLeave, {
 
- 			handles: data.handles,
 
- 			handleNumber: data.handleNumber
 
- 		});
 
- 		d.noUiListeners = moveEvent.concat(endEvent, outEvent);
 
- 		// Text selection isn't an issue on touch devices,
 
- 		// so adding cursor styles can be skipped.
 
- 		if ( event.cursor ) {
 
- 			// Prevent the 'I' cursor and extend the range-drag cursor.
 
- 			document.body.style.cursor = getComputedStyle(event.target).cursor;
 
- 			// Mark the target with a dragging state.
 
- 			if ( scope_Handles.length > 1 ) {
 
- 				addClass(scope_Target, options.cssClasses.drag);
 
- 			}
 
- 			var f = function(){
 
- 				return false;
 
- 			};
 
- 			document.body.noUiListener = f;
 
- 			// Prevent text selection when dragging the handles.
 
- 			document.body.addEventListener('selectstart', f, false);
 
- 		}
 
- 		if ( data.handleNumber !== undefined ) {
 
- 			fireEvent('start', data.handleNumber);
 
- 		}
 
- 	}
 
- 	// Move closest handle to tapped location.
 
- 	function tap ( event ) {
 
- 		var location = event.calcPoint, total = 0, handleNumber, to;
 
- 		// The tap event shouldn't propagate up and cause 'edge' to run.
 
- 		event.stopPropagation();
 
- 		// Add up the handle offsets.
 
- 		scope_Handles.forEach(function(a){
 
- 			total += offset(a)[ options.style ];
 
- 		});
 
- 		// Find the handle closest to the tapped position.
 
- 		handleNumber = ( location < total/2 || scope_Handles.length === 1 ) ? 0 : 1;
 
- 		// Check if handler is not disablet if yes set number to the next handler
 
- 		if (scope_Handles[handleNumber].hasAttribute('disabled')) {
 
- 			handleNumber = handleNumber ? 0 : 1;
 
- 		}
 
- 		location -= offset(scope_Base)[ options.style ];
 
- 		// Calculate the new position.
 
- 		to = ( location * 100 ) / baseSize();
 
- 		if ( !options.events.snap ) {
 
- 			// Flag the slider as it is now in a transitional state.
 
- 			// Transition takes a configurable amount of ms (default 300). Re-enable the slider after that.
 
- 			addClassFor( scope_Target, options.cssClasses.tap, options.animationDuration );
 
- 		}
 
- 		// Support 'disabled' handles
 
- 		if ( scope_Handles[handleNumber].hasAttribute('disabled') ) {
 
- 			return false;
 
- 		}
 
- 		// Find the closest handle and calculate the tapped point.
 
- 		// The set handle to the new position.
 
- 		setHandle( scope_Handles[handleNumber], to );
 
- 		fireEvent('slide', handleNumber, true);
 
- 		fireEvent('set', handleNumber, true);
 
- 		fireEvent('change', handleNumber, true);
 
- 		if ( options.events.snap ) {
 
- 			start(event, { handles: [scope_Handles[handleNumber]] });
 
- 		}
 
- 	}
 
- 	// Fires a 'hover' event for a hovered mouse/pen position.
 
- 	function hover ( event ) {
 
- 		var location = event.calcPoint - offset(scope_Base)[ options.style ],
 
- 			to = scope_Spectrum.getStep(( location * 100 ) / baseSize()),
 
- 			value = scope_Spectrum.fromStepping( to );
 
- 		Object.keys(scope_Events).forEach(function( targetEvent ) {
 
- 			if ( 'hover' === targetEvent.split('.')[0] ) {
 
- 				scope_Events[targetEvent].forEach(function( callback ) {
 
- 					callback.call( scope_Self, value );
 
- 				});
 
- 			}
 
- 		});
 
- 	}
 
- 	// Attach events to several slider parts.
 
- 	function events ( behaviour ) {
 
- 		// Attach the standard drag event to the handles.
 
- 		if ( !behaviour.fixed ) {
 
- 			scope_Handles.forEach(function( handle, index ){
 
- 				// These events are only bound to the visual handle
 
- 				// element, not the 'real' origin element.
 
- 				attach ( actions.start, handle.children[0], start, {
 
- 					handles: [ handle ],
 
- 					handleNumber: index
 
- 				});
 
- 			});
 
- 		}
 
- 		// Attach the tap event to the slider base.
 
- 		if ( behaviour.tap ) {
 
- 			attach ( actions.start, scope_Base, tap, {
 
- 				handles: scope_Handles
 
- 			});
 
- 		}
 
- 		// Fire hover events
 
- 		if ( behaviour.hover ) {
 
- 			attach ( actions.move, scope_Base, hover, { hover: true } );
 
- 		}
 
- 		// Make the range draggable.
 
- 		if ( behaviour.drag ){
 
- 			var drag = [scope_Base.querySelector( '.' + options.cssClasses.connect )];
 
- 			addClass(drag[0], options.cssClasses.draggable);
 
- 			// When the range is fixed, the entire range can
 
- 			// be dragged by the handles. The handle in the first
 
- 			// origin will propagate the start event upward,
 
- 			// but it needs to be bound manually on the other.
 
- 			if ( behaviour.fixed ) {
 
- 				drag.push(scope_Handles[(drag[0] === scope_Handles[0] ? 1 : 0)].children[0]);
 
- 			}
 
- 			drag.forEach(function( element ) {
 
- 				attach ( actions.start, element, start, {
 
- 					handles: scope_Handles
 
- 				});
 
- 			});
 
- 		}
 
- 	}
 
- 	// Test suggested values and apply margin, step.
 
- 	function setHandle ( handle, to, noLimitOption ) {
 
- 		var trigger = handle !== scope_Handles[0] ? 1 : 0,
 
- 			lowerMargin = scope_Locations[0] + options.margin,
 
- 			upperMargin = scope_Locations[1] - options.margin,
 
- 			lowerLimit = scope_Locations[0] + options.limit,
 
- 			upperLimit = scope_Locations[1] - options.limit;
 
- 		// For sliders with multiple handles,
 
- 		// limit movement to the other handle.
 
- 		// Apply the margin option by adding it to the handle positions.
 
- 		if ( scope_Handles.length > 1 ) {
 
- 			to = trigger ? Math.max( to, lowerMargin ) : Math.min( to, upperMargin );
 
- 		}
 
- 		// The limit option has the opposite effect, limiting handles to a
 
- 		// maximum distance from another. Limit must be > 0, as otherwise
 
- 		// handles would be unmoveable. 'noLimitOption' is set to 'false'
 
- 		// for the .val() method, except for pass 4/4.
 
- 		if ( noLimitOption !== false && options.limit && scope_Handles.length > 1 ) {
 
- 			to = trigger ? Math.min ( to, lowerLimit ) : Math.max( to, upperLimit );
 
- 		}
 
- 		// Handle the step option.
 
- 		to = scope_Spectrum.getStep( to );
 
- 		// Limit percentage to the 0 - 100 range
 
- 		to = limit(to);
 
- 		// Return false if handle can't move
 
- 		if ( to === scope_Locations[trigger] ) {
 
- 			return false;
 
- 		}
 
- 		// Set the handle to the new position.
 
- 		// Use requestAnimationFrame for efficient painting.
 
- 		// No significant effect in Chrome, Edge sees dramatic
 
- 		// performace improvements.
 
- 		if ( window.requestAnimationFrame ) {
 
- 			window.requestAnimationFrame(function(){
 
- 				handle.style[options.style] = to + '%';
 
- 			});
 
- 		} else {
 
- 			handle.style[options.style] = to + '%';
 
- 		}
 
- 		// Force proper handle stacking
 
- 		if ( !handle.previousSibling ) {
 
- 			removeClass(handle, options.cssClasses.stacking);
 
- 			if ( to > 50 ) {
 
- 				addClass(handle, options.cssClasses.stacking);
 
- 			}
 
- 		}
 
- 		// Update locations.
 
- 		scope_Locations[trigger] = to;
 
- 		// Convert the value to the slider stepping/range.
 
- 		scope_Values[trigger] = scope_Spectrum.fromStepping( to );
 
- 		fireEvent('update', trigger);
 
- 		return true;
 
- 	}
 
- 	// Loop values from value method and apply them.
 
- 	function setValues ( count, values ) {
 
- 		var i, trigger, to;
 
- 		// With the limit option, we'll need another limiting pass.
 
- 		if ( options.limit ) {
 
- 			count += 1;
 
- 		}
 
- 		// If there are multiple handles to be set run the setting
 
- 		// mechanism twice for the first handle, to make sure it
 
- 		// can be bounced of the second one properly.
 
- 		for ( i = 0; i < count; i += 1 ) {
 
- 			trigger = i%2;
 
- 			// Get the current argument from the array.
 
- 			to = values[trigger];
 
- 			// Setting with null indicates an 'ignore'.
 
- 			// Inputting 'false' is invalid.
 
- 			if ( to !== null && to !== false ) {
 
- 				// If a formatted number was passed, attemt to decode it.
 
- 				if ( typeof to === 'number' ) {
 
- 					to = String(to);
 
- 				}
 
- 				to = options.format.from( to );
 
- 				// Request an update for all links if the value was invalid.
 
- 				// Do so too if setting the handle fails.
 
- 				if ( to === false || isNaN(to) || setHandle( scope_Handles[trigger], scope_Spectrum.toStepping( to ), i === (3 - options.dir) ) === false ) {
 
- 					fireEvent('update', trigger);
 
- 				}
 
- 			}
 
- 		}
 
- 	}
 
- 	// Set the slider value.
 
- 	function valueSet ( input, fireSetEvent ) {
 
- 		var count, values = asArray( input ), i;
 
- 		// Event fires by default
 
- 		fireSetEvent = (fireSetEvent === undefined ? true : !!fireSetEvent);
 
- 		// The RTL settings is implemented by reversing the front-end,
 
- 		// internal mechanisms are the same.
 
- 		if ( options.dir && options.handles > 1 ) {
 
- 			values.reverse();
 
- 		}
 
- 		// Animation is optional.
 
- 		// Make sure the initial values where set before using animated placement.
 
- 		if ( options.animate && scope_Locations[0] !== -1 ) {
 
- 			addClassFor( scope_Target, options.cssClasses.tap, options.animationDuration );
 
- 		}
 
- 		// Determine how often to set the handles.
 
- 		count = scope_Handles.length > 1 ? 3 : 1;
 
- 		if ( values.length === 1 ) {
 
- 			count = 1;
 
- 		}
 
- 		setValues ( count, values );
 
- 		// Fire the 'set' event for both handles.
 
- 		for ( i = 0; i < scope_Handles.length; i++ ) {
 
- 			// Fire the event only for handles that received a new value, as per #579
 
- 			if ( values[i] !== null && fireSetEvent ) {
 
- 				fireEvent('set', i);
 
- 			}
 
- 		}
 
- 	}
 
- 	// Get the slider value.
 
- 	function valueGet ( ) {
 
- 		var i, retour = [];
 
- 		// Get the value from all handles.
 
- 		for ( i = 0; i < options.handles; i += 1 ){
 
- 			retour[i] = options.format.to( scope_Values[i] );
 
- 		}
 
- 		return inSliderOrder( retour );
 
- 	}
 
- 	// Removes classes from the root and empties it.
 
- 	function destroy ( ) {
 
- 		for ( var key in options.cssClasses ) {
 
- 			if ( !options.cssClasses.hasOwnProperty(key) ) { continue; }
 
- 			removeClass(scope_Target, options.cssClasses[key]);
 
- 		}
 
- 		while (scope_Target.firstChild) {
 
- 			scope_Target.removeChild(scope_Target.firstChild);
 
- 		}
 
- 		delete scope_Target.noUiSlider;
 
- 	}
 
- 	// Get the current step size for the slider.
 
- 	function getCurrentStep ( ) {
 
- 		// Check all locations, map them to their stepping point.
 
- 		// Get the step point, then find it in the input list.
 
- 		var retour = scope_Locations.map(function( location, index ){
 
- 			var step = scope_Spectrum.getApplicableStep( location ),
 
- 				// As per #391, the comparison for the decrement step can have some rounding issues.
 
- 				// Round the value to the precision used in the step.
 
- 				stepDecimals = countDecimals(String(step[2])),
 
- 				// Get the current numeric value
 
- 				value = scope_Values[index],
 
- 				// To move the slider 'one step up', the current step value needs to be added.
 
- 				// Use null if we are at the maximum slider value.
 
- 				increment = location === 100 ? null : step[2],
 
- 				// Going 'one step down' might put the slider in a different sub-range, so we
 
- 				// need to switch between the current or the previous step.
 
- 				prev = Number((value - step[2]).toFixed(stepDecimals)),
 
- 				// If the value fits the step, return the current step value. Otherwise, use the
 
- 				// previous step. Return null if the slider is at its minimum value.
 
- 				decrement = location === 0 ? null : (prev >= step[1]) ? step[2] : (step[0] || false);
 
- 			return [decrement, increment];
 
- 		});
 
- 		// Return values in the proper order.
 
- 		return inSliderOrder( retour );
 
- 	}
 
- 	// Attach an event to this slider, possibly including a namespace
 
- 	function bindEvent ( namespacedEvent, callback ) {
 
- 		scope_Events[namespacedEvent] = scope_Events[namespacedEvent] || [];
 
- 		scope_Events[namespacedEvent].push(callback);
 
- 		// If the event bound is 'update,' fire it immediately for all handles.
 
- 		if ( namespacedEvent.split('.')[0] === 'update' ) {
 
- 			scope_Handles.forEach(function(a, index){
 
- 				fireEvent('update', index);
 
- 			});
 
- 		}
 
- 	}
 
- 	// Undo attachment of event
 
- 	function removeEvent ( namespacedEvent ) {
 
- 		var event = namespacedEvent && namespacedEvent.split('.')[0],
 
- 			namespace = event && namespacedEvent.substring(event.length);
 
- 		Object.keys(scope_Events).forEach(function( bind ){
 
- 			var tEvent = bind.split('.')[0],
 
- 				tNamespace = bind.substring(tEvent.length);
 
- 			if ( (!event || event === tEvent) && (!namespace || namespace === tNamespace) ) {
 
- 				delete scope_Events[bind];
 
- 			}
 
- 		});
 
- 	}
 
- 	// Updateable: margin, limit, step, range, animate, snap
 
- 	function updateOptions ( optionsToUpdate, fireSetEvent ) {
 
- 		// Spectrum is created using the range, snap, direction and step options.
 
- 		// 'snap' and 'step' can be updated, 'direction' cannot, due to event binding.
 
- 		// If 'snap' and 'step' are not passed, they should remain unchanged.
 
- 		var v = valueGet(), newOptions = testOptions({
 
- 			start: [0, 0],
 
- 			margin: optionsToUpdate.margin,
 
- 			limit: optionsToUpdate.limit,
 
- 			step: optionsToUpdate.step === undefined ? options.singleStep : optionsToUpdate.step,
 
- 			range: optionsToUpdate.range,
 
- 			animate: optionsToUpdate.animate,
 
- 			snap: optionsToUpdate.snap === undefined ? options.snap : optionsToUpdate.snap
 
- 		});
 
- 		['margin', 'limit', 'range', 'animate'].forEach(function(name){
 
- 			// Only change options that we're actually passed to update.
 
- 			if ( optionsToUpdate[name] !== undefined ) {
 
- 				options[name] = optionsToUpdate[name];
 
- 			}
 
- 		});
 
- 		// Save current spectrum direction as testOptions in testRange call
 
- 		// doesn't rely on current direction
 
- 		newOptions.spectrum.direction = scope_Spectrum.direction;
 
- 		scope_Spectrum = newOptions.spectrum;
 
- 		// Invalidate the current positioning so valueSet forces an update.
 
- 		scope_Locations = [-1, -1];
 
- 		valueSet(optionsToUpdate.start || v, fireSetEvent);
 
- 	}
 
- 	// Throw an error if the slider was already initialized.
 
- 	if ( scope_Target.noUiSlider ) {
 
- 		throw new Error('Slider was already initialized.');
 
- 	}
 
- 	// Create the base element, initialise HTML and set classes.
 
- 	// Add handles and links.
 
- 	scope_Base = addSlider( options.dir, options.ort, scope_Target );
 
- 	scope_Handles = addHandles( options.handles, options.dir, scope_Base );
 
- 	// Set the connect classes.
 
- 	addConnection ( options.connect, scope_Target, scope_Handles );
 
- 	if ( options.pips ) {
 
- 		pips(options.pips);
 
- 	}
 
- 	if ( options.tooltips ) {
 
- 		tooltips();
 
- 	}
 
- 	scope_Self = {
 
- 		destroy: destroy,
 
- 		steps: getCurrentStep,
 
- 		on: bindEvent,
 
- 		off: removeEvent,
 
- 		get: valueGet,
 
- 		set: valueSet,
 
- 		updateOptions: updateOptions,
 
- 		options: originalOptions, // Issue #600
 
- 		target: scope_Target, // Issue #597
 
- 		pips: pips // Issue #594
 
- 	};
 
- 	// Attach user events.
 
- 	events( options.events );
 
- 	return scope_Self;
 
- }
 
- 	// Run the standard initializer
 
- 	function initialize ( target, originalOptions ) {
 
- 		if ( !target.nodeName ) {
 
- 			throw new Error('noUiSlider.create requires a single element.');
 
- 		}
 
- 		// Test the options and create the slider environment;
 
- 		var options = testOptions( originalOptions, target ),
 
- 			slider = closure( target, options, originalOptions );
 
- 		// Use the public value method to set the start values.
 
- 		slider.set(options.start);
 
- 		target.noUiSlider = slider;
 
- 		return slider;
 
- 	}
 
- 	// Use an object instead of a function for future expansibility;
 
- 	return {
 
- 		create: initialize
 
- 	};
 
- }));
 
 
  |