diff --git a/.gitignore b/.gitignore
new file mode 100644
index 00000000..c954da8d
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1 @@
+/compiler
\ No newline at end of file
diff --git a/.gitmodules b/.gitmodules
new file mode 100644
index 00000000..c95f97b5
--- /dev/null
+++ b/.gitmodules
@@ -0,0 +1,6 @@
+[submodule "libLink"]
+ path = libLink
+ url = https://github.com/leongersen/libLink
+[submodule "wnumb"]
+ path = wnumb
+ url = https://github.com/leongersen/wnumb
diff --git a/Link.js b/Link.js
deleted file mode 100644
index 66752ca2..00000000
--- a/Link.js
+++ /dev/null
@@ -1,389 +0,0 @@
-/**@preserve
-$.Link (part of noUiSlider) - WTFPL */
-
-/*jslint browser: true */
-/*jslint sub: true */
-/*jslint white: true */
-
-(function( $ ){
-
- 'use strict';
-
- // Throw an error if formatting options are incompatible.
- function throwEqualError( F, a, b ) {
- if ( (F[a] || F[b]) && (F[a] === F[b]) ) {
- throw new Error("(Link) '"+a+"' can't match '"+b+"'.'");
- }
- }
-
- // Test in an object is an instance of jQuery or Zepto.
- function isInstance ( a ) {
- return a instanceof $ || ( $['zepto'] && $['zepto']['isZ'](a) );
- }
-
-var
-/** @const */ Formatting = [
-/* 0 */ 'decimals'
-/* 1 */ ,'mark'
-/* 2 */ ,'thousand'
-/* 3 */ ,'prefix'
-/* 4 */ ,'postfix'
-/* 5 */ ,'encoder'
-/* 6 */ ,'decoder'
-/* 7 */ ,'negative'
-/* 8 */ ,'negativeBefore'
-/* 9 */ ,'to'
-/* 10 */ ,'from'
- ],
-/** @const */ FormatDefaults = [
-/* 0 */ 2
-/* 1 */ ,'.'
-/* 2 */ ,''
-/* 3 */ ,''
-/* 4 */ ,''
-/* 5 */ ,function(a){ return a; }
-/* 6 */ ,function(a){ return a; }
-/* 7 */ ,'-'
-/* 8 */ ,''
-/* 9 */ ,function(a){ return a; }
-/* 10 */ ,function(a){ return a; }
- ];
-
-
- /** @constructor */
- function Format( options ){
-
- // If no settings where provided, the defaults will be loaded.
- if ( options === undefined ){
- options = {};
- }
-
- if ( typeof options !== 'object' ){
- throw new Error("(Format) 'format' option must be an object.");
- }
-
- var settings = {};
-
- // Copy all values into a new object.
- $(Formatting).each(function(i, val){
-
- if ( options[val] === undefined ){
-
- settings[val] = FormatDefaults[i];
-
- // When we aren't loading defaults, validate the entry.
- } else if ( (typeof options[val]) === (typeof FormatDefaults[i]) ) {
-
- // Support for up to 7 decimals.
- // More can't be guaranteed due to floating point issues.
- if ( val === 'decimals' ){
- if ( options[val] < 0 || options[val] > 7 ){
- throw new Error("(Format) 'format.decimals' option must be between 0 and 7.");
- }
- }
-
- settings[val] = options[val];
-
- // If the value isn't valid, emit an error.
- } else {
- throw new Error("(Format) 'format."+val+"' must be a " + typeof FormatDefaults[i] + ".");
- }
- });
-
- // Some values can't be extracted from a
- // string if certain combinations are present.
- throwEqualError(settings, 'mark', 'thousand');
- throwEqualError(settings, 'prefix', 'negative');
- throwEqualError(settings, 'prefix', 'negativeBefore');
-
- this.settings = settings;
- }
-
- // Shorthand for internal value get
- Format.prototype.v = function ( a ) {
- return this.settings[a];
- };
-
- Format.prototype.to = function ( number ) {
-
- function reverse ( a ) {
- return a.split('').reverse().join('');
- }
-
- number = this.v('encoder')( number );
-
- var decimals = this.v('decimals'),
- negative = '', preNegative = '', base = '', mark = '';
-
- // Rounding away decimals might cause a value of -0
- // when using very small ranges. Remove those cases.
- if ( parseFloat(number.toFixed(decimals)) === 0 ) {
- number = '0';
- }
-
- if ( number < 0 ) {
- negative = this.v('negative');
- preNegative = this.v('negativeBefore');
- }
-
- // Round to proper decimal count
- number = Math.abs(number).toFixed(decimals).toString();
- number = number.split('.');
-
- // Group numbers in sets of three.
- if ( this.v('thousand') ) {
- base = reverse(number[0]).match(/.{1,3}/g);
- base = reverse(base.join(reverse( this.v('thousand') )));
- } else {
- base = number[0];
- }
-
- // Ignore the decimal separator if decimals are set to 0.
- if ( this.v('mark') && number.length > 1 ) {
- mark = this.v('mark') + number[1];
- }
-
- // Return the finalized formatted number.
- return this.v('to')(preNegative +
- this.v('prefix') +
- negative +
- base +
- mark +
- this.v('postfix'));
- };
-
- Format.prototype.from = function ( input ) {
-
- function esc(s){
- return s.replace(/[\-\/\\\^$*+?.()|\[\]{}]/g, '\\$&');
- }
-
- var isNeg;
- // The set request might want to ignore this handle.
- // Test for 'undefined' too, as a two-handle slider
- // can still be set with an integer.
- if ( input === null || input === undefined ) {
- return false;
- }
-
- input = this.v('from')(input);
-
- // Remove formatting and set period for float parsing.
- input = input.toString();
-
- // Replace the preNegative indicator.
- isNeg = input.replace(new RegExp('^' + esc( this.v('negativeBefore') )), '');
-
- // Check if the value changed by removing the negativeBefore symbol.
- if( input !== isNeg ) {
- input = isNeg;
- isNeg = '-';
- } else {
- isNeg = '';
- }
-
- // If prefix is set and the number is actually prefixed.
- input = input.replace(new RegExp('^'+esc( this.v('prefix') )), '');
-
- // Only replace if a negative sign is set.
- if ( this.v('negative') ) {
-
- // Reset isNeg to prevent double '-' insertion.
- isNeg = '';
-
- // Reset the negative sign to '-'
- input = input.replace(new RegExp('^'+esc( this.v('negative') )), '-');
- }
-
- // Clean the input string
- input = input
- // If postfix is set and the number is postfixed.
- .replace( new RegExp(esc( this.v('postfix') ) + '$'), '')
- // Remove the separator every three digits.
- .replace( new RegExp(esc( this.v('thousand') ), 'g'), '')
- // Set the decimal separator back to period.
- .replace( this.v('mark'), '.');
-
- // Run the user defined decoder. Returns input by default.
- input = this.v('decoder')( parseFloat( isNeg + input ) );
-
- // Ignore invalid input
- if (isNaN( input )) {
- return false;
- }
-
- return input;
- };
-
-
-/** @expose */
-/** @constructor */
- function Link ( entry, update ) {
-
- if ( typeof entry !== "object" ) {
- $.error("(Link) Initialize with an object.");
- }
-
- // Make sure Link isn't called as a function, in which case
- // the 'this' scope would be the window.
- return new Link.prototype.init( entry['target']||function(){}, entry['method'], entry['format']||{}, update );
- }
-
- Link.prototype.setTooltip = function ( target, method ) {
-
- // By default, use the 'html' method.
- this.method = method || 'html';
-
- // Use jQuery to create the element
- this.el = $( target.replace('-tooltip-', '') || '
' )[0];
- };
-
- Link.prototype.setHidden = function ( target ) {
-
- this.method = 'val';
-
- this.el = document.createElement('input');
- this.el.name = target;
- this.el.type = 'hidden';
- };
-
- Link.prototype.setField = function ( target ) {
-
- // Returns nulled array.
- function at(a,b,c){
- return [c?a:b, c?b:a];
- }
-
- // In IE < 9, .bind() isn't available, need this link in .change().
- var that = this;
-
- // Default to .val if this is an input element.
- this.method = 'val';
- // Set the slider to a new value on change.
- this.target = target.on('change', function( e ){
- that.obj.val(
- at(null, $(e.target).val(), that.N),
- { 'link': that, 'set': true }
- );
- });
- };
-
-
- // Initialisor
- /** @constructor */
- Link.prototype.init = function ( target, method, format, update ) {
-
- // Write all formatting to this object.
- // No validation needed, as we'll merge these with the parent
- // format options first.
- this.formatting = format;
-
- // Store the update option.
- this.update = !update;
-
- // If target is a string, a new hidden input will be created.
- if ( typeof target === 'string' && target.indexOf('-tooltip-') === 0 ) {
- this.setTooltip( target, method );
- return;
- }
-
- // If the string doesn't begin with '-', which is reserved, add a new hidden input.
- if ( typeof target === 'string' && target.indexOf('-') !== 0 ) {
- this.setHidden( target );
- return;
- }
-
- // The target can also be a function, which will be called.
- if ( typeof target === 'function' ) {
- this.target = false;
- this.method = target;
- return;
- }
-
- if ( isInstance(target) ) {
- // If a jQuery/Zepto input element is provided, but no method is set,
- // the element can assume it needs to respond to 'change'...
-
- if ( !method ) {
-
- if ( target.is('input, select, textarea') ) {
- this.setField( target );
- return;
- }
-
- // If no method is set, and we are not auto-binding an input, default to 'html'.
- method = 'html';
- }
-
- // The method must exist on the element.
- if ( typeof method === 'function' || (typeof method === 'string' && target[method]) ) {
- this.method = method;
- this.target = target;
- return;
- }
- }
-
- // Nothing matched, throw error.
- throw new RangeError("(Link) Invalid Link.");
- };
-
- // Provides external items with the slider value.
- Link.prototype.write = function ( value, handle, slider, update ) {
-
- // Don't synchronize this Link.
- if ( this.update && update === false ) {
- return;
- }
-
- this.actual = value;
-
- // Format values for display.
- value = this.format( value );
-
- // Store the numerical value.
- this.saved = value;
-
- // Branch between serialization to a function or an object.
- if ( typeof this.method === 'function' ) {
- // When target is undefined, the target was a function.
- // In that case, provided the slider as the calling scope.
- // Use [0] to get the DOM element, not the $ instance.
- this.method.call( this.target[0] || slider[0], value, handle, slider );
- } else {
- this.target[ this.method ]( value, handle, slider );
- }
- };
-
- // Set formatting options.
- Link.prototype.setFormatting = function ( options ) {
- this.formatting = new Format($.extend({},
- options,
- this.formatting instanceof Format ? this.formatting.settings : this.formatting
- ));
- };
-
- Link.prototype.setObject = function ( obj ) {
- this.obj = obj;
- };
-
- Link.prototype.setIndex = function ( index ) {
- this.N = index;
- };
-
- // Parses slider value to user defined display.
- Link.prototype.format = function ( a ) {
- return this.formatting.to(a);
- };
-
- // Converts a formatted value back to a real number.
- Link.prototype.getValue = function ( a ) {
- return this.formatting.from(a);
- };
-
- // We can now test for Link.init to be an instance of Link.
- Link.prototype.init.prototype = Link.prototype;
-
- /** @expose */
- $.Link = Link;
-
-}( window['jQuery'] || window['Zepto'] ));
diff --git a/README.md b/README.md
index 82453318..c2777591 100644
--- a/README.md
+++ b/README.md
@@ -7,30 +7,9 @@ Documentation
An extensive documentation, including **examples**, **options** and **configuration details**, is available here: [noUiSlider documentation](http://refreshless.com/nouislider/).
-Changes
--------
-
-**Changelog for version 6.2.0:**
-*(Compatible with 6.0.0)*
-
-+ Removed the previously added `.classVal` and replaced it with a lightweight solution.
-+ Fixed a bug in non-linear stepping for RTL sliders. (#262)
-+ Added checks for `min` and `max` in `range`. (#255)
-+ Added the minified version in the source, so it can be managed with Bower. (#252)
-
-**Changelog for version 6.0.0:**
-
-**Please note:** noUiSlider 6 is a *major* revision, which means it isn't compatible with version 5. Your stylesheet will keep working, but the JavaScript API has changed, and your current implementation will no longer work.
-
-+ Added optional **non-linear** ranges, including stepping.
-+ Added new behaviour settings.
-+ Added object-oriented serialization.
-+ Change events to use jQuery's/Zepto's `.on` and `.off`.
-+ Removed `block` event.
-
Unit Testing
------------
-Unit tests where added with noUiSlider 6. Coverage of `$.Link` and value handling is near complete, but due to the sensitivity of events across browsers, event testing is a little lacking.
+Unit tests where overhauled for noUiSlider 7. Most code is now covered, with events testing being slightly lacking due to it's browser dependant nature.
Version numbering
------------------------------
@@ -41,34 +20,4 @@ Compression and Error checking
------------------------------
The plugin code is checked using ([JsLint](http://jslint.com/)). Any remaining errors and warnings are intentional.
-The plugin is compressed using the ([Google Closure Compiler](http://closure-compiler.appspot.com/home)). The source was adapted to facilitate the `ADVANCED_OPTIMIZATIONS` level. `$.Link` is merged into the file. On Windows, the following BAT script can be used to run the compiler. On OS X or Linux enviroments, simply run the `java -jar` command from the command line.
-
-```bat
-@echo off
-
-:: Set all paths as variables
-set "jquery=.\externs\jquery-1.8.js"
-set "link=..\source\Link.js"
-set "source=..\source\jquery.nouislider.js"
-set "result=..\source\jquery.nouislider.min.js"
-
-:: Remove the existing file so we can be sure a new one is generated.
-if exist %result% (
- del %result%
-)
-
-echo "Removed %result%, ready."
-
-PAUSE
-
-java -jar .\compiler\compiler.jar --compilation_level ADVANCED_OPTIMIZATIONS --externs %jquery% --warning_level VERBOSE --js %link% --js %source% --js_output_file %result%
-
-echo "Done."
-PAUSE
-```
-
-Known issues
-------------
-There are some minor issues remaining in noUiSlider. It is a priority to fix these issues, but they may be fixed by browser updates in the future.
-
-+ Firefox and Safari on Windows will emulate mouse-events on touch screens, but prefer scrolling to dragging the slider.
+The plugin is compressed using the ([Google Closure Compiler](http://closure-compiler.appspot.com/home)). The source was initialy adapted to facilitate the `ADVANCED_OPTIMIZATIONS` level, but the risks this poses regarding to unintented renaming proved problematic. On Windows, the BAT script in this repository can be used to run the compiler. On OS X or Linux enviroments, simply run the `java -jar` command from the command line.
diff --git a/compile.bat b/compile.bat
new file mode 100644
index 00000000..a033f66c
--- /dev/null
+++ b/compile.bat
@@ -0,0 +1,42 @@
+@echo off
+
+:: Set all paths as variables
+set "wnumb=wnumb\wNumb.js"
+set "wnumbMin=wnumb\wNumb.min.js"
+set "link=libLink\jquery.liblink.js"
+
+set "jquery=compiler\jquery-1.9.js"
+set "zepto=compiler\zepto.js"
+
+set "range=src\module.range.js"
+set "options=src\module.options.js"
+set "source=src\module.base.js"
+set "pips=src\optional.pips.js"
+
+set "nouislidermin=jquery.nouislider.min.js"
+set "nouisliderfull=jquery.nouislider.full.min.js"
+
+set "compiler=compiler\compiler.jar"
+set "level=--compilation_level SIMPLE_OPTIMIZATIONS"
+set "verbose=--warning_level VERBOSE"
+
+:: Remove the existing file so we can be sure a new one is generated.
+if exist %nouislidermin% (
+ del %nouislidermin%
+ echo "Removed %nouislidermin%."
+)
+if exist %nouisliderfull% (
+ del %nouisliderfull%
+ echo "Removed %nouisliderfull%,"
+)
+
+echo "Ready."
+
+PAUSE
+
+java -jar %compiler% %level% %verbose% --js %wnumb% --js_output_file %wnumbMin%
+java -jar %compiler% %level% %verbose% --externs %jquery% --externs %zepto% --js %range% --js %options% --js %source% --js_output_file %nouislidermin%
+java -jar %compiler% %level% %verbose% --externs %jquery% --externs %zepto% --js %wnumb% --js %link% --js %range% --js %options% --js %source% --js %pips% --js_output_file %nouisliderfull%
+
+echo "Done."
+PAUSE
diff --git a/jquery.nouislider.css b/jquery.nouislider.css
index 8bcf94cf..1e34ac94 100644
--- a/jquery.nouislider.css
+++ b/jquery.nouislider.css
@@ -13,6 +13,9 @@
-moz-box-sizing: border-box;
box-sizing: border-box;
}
+.noUi-target {
+ position: relative;
+}
.noUi-base {
width: 100%;
height: 100%;
@@ -47,6 +50,15 @@
cursor: inherit !important;
}
+/* Painting and performance;
+ * Browsers can paint handles in their own layer.
+ */
+.noUi-origin,
+.noUi-handle {
+ -webkit-transform: translate3d(0,0,0);
+ transform: translate3d(0,0,0);
+}
+
/* Slider size and handle placement;
*/
.noUi-horizontal {
@@ -58,12 +70,6 @@
left: -17px;
top: -6px;
}
-.noUi-horizontal.noUi-extended {
- padding: 0 15px;
-}
-.noUi-horizontal.noUi-extended .noUi-origin {
- right: -15px;
-}
.noUi-vertical {
width: 18px;
}
@@ -73,12 +79,6 @@
left: -6px;
top: -17px;
}
-.noUi-vertical.noUi-extended {
- padding: 15px 0;
-}
-.noUi-vertical.noUi-extended .noUi-origin {
- bottom: -15px;
-}
/* Styling;
*/
diff --git a/jquery.nouislider.full.min.js b/jquery.nouislider.full.min.js
new file mode 100644
index 00000000..215ac05a
--- /dev/null
+++ b/jquery.nouislider.full.min.js
@@ -0,0 +1,33 @@
+(function(){function c(a){return a.split("").reverse().join("")}function l(a,b){return a.substring(0,b.length)===b}function q(a,b,d){if((a[b]||a[d])&&a[b]===a[d])throw Error(b);}function m(a,b,d,e,n,h,w,k,A,H,D,g){w=g;var l,s=D="";h&&(g=h(g));if("number"!==typeof g||!isFinite(g))return!1;a&&0===parseFloat(g.toFixed(a))&&(g=0);0>g&&(l=!0,g=Math.abs(g));!1!==a&&(h=g,g=Math.pow(10,a),g=(Math.round(h*g)/g).toFixed(a));g=g.toString();-1!==g.indexOf(".")?(a=g.split("."),h=a[0],d&&(D=d+a[1])):h=g;b&&(h=
+c(h).match(/.{1,3}/g),h=c(h.join(c(b))));l&&k&&(s+=k);e&&(s+=e);l&&A&&(s+=A);s=s+h+D;n&&(s+=n);H&&(s=H(s,w));return s}function u(a,b,d,c,e,h,w,k,A,H,D,g){var m;a="";D&&(g=D(g));if(!g||"string"!==typeof g)return!1;k&&l(g,k)&&(g=g.replace(k,""),m=!0);c&&l(g,c)&&(g=g.replace(c,""));A&&l(g,A)&&(g=g.replace(A,""),m=!0);if(c=e)c=g.slice(-1*e.length)===e;c&&(g=g.slice(0,-1*e.length));b&&(g=g.split(b).join(""));d&&(g=g.replace(d,"."));m&&(a+="-");a=(a+g).replace(/[^0-9\.\-.]/g,"");if(""===a)return!1;a=Number(a);
+w&&(a=w(a));return"number"===typeof a&&isFinite(a)?a:!1}function a(a){var b,d,c,n={};for(b=0;bc)n[d]=c;else throw Error(d);else if("encoder"===d||"decoder"===d||"edit"===d||"undo"===d)if("function"===typeof c)n[d]=c;else throw Error(d);else if("string"===typeof c)n[d]=c;else throw Error(d);q(n,"mark","thousand");q(n,"prefix","negative");q(n,"prefix",
+"negativeBefore");return n}function b(a,b,d){var c,n=[];for(c=0;c"),!0},function(a){if("string"===typeof a&&0!==a.indexOf("-")){this.method="val";var b=document.createElement("input");b.name=a;b.type="hidden";this.target=this.el=c(b);return!0}},function(a){if("function"===typeof a)return this.target=!1,this.method=a,!0},function(a,b){if(l(a)&&!b)return a.is("input, select, textarea")?(this.method="val",this.target=a.on("change.liblink",this.changeHandler)):
+(this.target=a,this.method="html"),!0},function(a,b){if(l(a)&&("function"===typeof b||"string"===typeof b&&a[b]))return this.method=b,this.target=a,!0}];q.prototype.set=function(a){var b=Array.prototype.slice.call(arguments).slice(1);this.lastSetValue=this.formatInstance.to(a);b.unshift(this.lastSetValue);("function"===typeof this.method?this.method:this.target[this.method]).apply(this.target,b)};m.prototype.push=function(a,b){this.items.push(a);b&&this.elements.push(b)};m.prototype.reconfirm=function(a){var b;
+for(b=0;b=b[d];)d+=1;return d}function u(a,b,d,c){this.xPct=[];this.xVal=[];this.xSteps=[c||!1];this.xNumSteps=[!1];this.snap=b;this.direction=d;for(var f in a)if(a.hasOwnProperty(f)){b=f;d=a[f];c=void 0;"number"===typeof d&&(d=[d]);if("[object Array]"!==Object.prototype.toString.call(d))throw Error("noUiSlider: 'range' contains invalid value.");c="min"===b?0:
+"max"===b?100:parseFloat(b);if(!l(c)||!l(d[0]))throw Error("noUiSlider: 'range' value isn't numeric.");this.xPct.push(c);this.xVal.push(d[0]);c?this.xSteps.push(isNaN(d[1])?!1:d[1]):isNaN(d[1])||(this.xSteps[0]=d[1])}this.xNumSteps=this.xSteps.slice(0);for(f in this.xNumSteps)this.xNumSteps.hasOwnProperty(f)&&(a=Number(f),(b=this.xNumSteps[f])&&(this.xSteps[a]=q([this.xVal[a],this.xVal[a+1]],b)/(100/(this.xPct[a+1]-this.xPct[a]))))}u.prototype.getMargin=function(a){return 2===this.xPct.length?q(this.xVal,
+a):!1};u.prototype.toStepping=function(a){var b=this.xVal,c=this.xPct;if(a>=b.slice(-1)[0])a=100;else{var e=m(a,b),f,l;f=b[e-1];l=b[e];b=c[e-1];c=c[e];f=[f,l];a=q(f,0>f[0]?a+Math.abs(f[0]):a-f[0]);a=b+a/(100/(c-b))}this.direction&&(a=100-a);return a};u.prototype.fromStepping=function(a){this.direction&&(a=100-a);var b;var c=this.xVal;b=this.xPct;if(100<=a)b=c.slice(-1)[0];else{var e=m(a,b),f,l;f=c[e-1];l=c[e];c=b[e-1];f=[f,l];b=100/(b[e]-c)*(a-c)*(f[1]-f[0])/100+f[0]}a=Math.pow(10,7);return Number((Math.round(b*
+a)/a).toFixed(7))};u.prototype.getStep=function(a){this.direction&&(a=100-a);var b=this.xPct,c=this.xSteps,e=this.snap;if(100!==a){var f=m(a,b);e?(c=b[f-1],b=b[f],a=a-c>(b-c)/2?b:c):(c[f-1]?(e=b[f-1],c=c[f-1],b=Math.round((a-b[f-1])/c)*c,b=e+b):b=a,a=b)}this.direction&&(a=100-a);return a};u.prototype.getApplicableStep=function(a){var b=m(a,this.xPct);a=100===a?2:1;return[this.xNumSteps[b-2],this.xVal[b-a],this.xNumSteps[b-a]]};u.prototype.convert=function(a){return this.getStep(this.toStepping(a))};
+c.noUiSlider={Spectrum:u}})(window.jQuery||window.Zepto);(function(c){function l(a){return"number"===typeof a&&!isNaN(a)&&isFinite(a)}function q(a,b){if(!l(b))throw Error("noUiSlider: 'step' is not numeric.");a.singleStep=b}function m(a,b){if("object"!==typeof b||c.isArray(b))throw Error("noUiSlider: 'range' is not an object.");if(void 0===b.min||void 0===b.max)throw Error("noUiSlider: Missing 'min' or 'max' in 'range'.");a.spectrum=new c.noUiSlider.Spectrum(b,a.snap,a.dir,a.singleStep)}function u(a,b){var d=b;b=c.isArray(d)?d:[d];if(!c.isArray(b)||!b.length||
+2").addClass(h[2]),e=["-lower","-upper"];a&&e.reverse();d.children().addClass(h[3]+" "+h[3]+e[b]);return d}function u(a,b,c){switch(a){case 1:b.addClass(h[7]);c[0].addClass(h[6]);break;case 3:c[1].addClass(h[6]);case 2:c[0].addClass(h[7]);case 0:b.addClass(h[6])}}function a(a,b,c){var d,e=[];for(d=0;d").appendTo(d).addClass(h[1])}function d(d,k,e){function f(){return B[["width","height"][k.ort]]()}function m(a){var b,c=[v.val()];for(b=0;bd&&(e+=Math.abs(d)),100=c[1]?c[2]:c[0],c[2]]]});return g(a)};d.getInfo=function(){return[E,k.style,k.ort]};v.val(k.start)}function e(a){if(!this.length)throw Error("noUiSlider: Can't initialize slider on empty selection.");var b=c.noUiSlider.testOptions(a,this);return this.each(function(){d(this,
+b,a)})}function f(a){return this.each(function(){if(this.destroy){var b=c(this).val(),d=this.destroy(),e=c.extend({},d,a);c(this).noUiSlider(e);this.reappend();d.start===e.start&&c(this).val(b)}else c(this).noUiSlider(a)})}function z(){return this[0][arguments.length?"vSet":"vGet"].apply(this[0],arguments)}var p=c(document),r=c.fn.val,n=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"},h="noUi-target noUi-base noUi-origin noUi-handle noUi-horizontal noUi-vertical noUi-background noUi-connect noUi-ltr noUi-rtl noUi-dragable noUi-state-drag noUi-state-tap noUi-active noUi-stacking".split(" ");c.fn.val=function(){var a=arguments,b=c(this[0]);return arguments.length?this.each(function(){(c(this).hasClass(h[0])?z:r).apply(c(this),a)}):(b.hasClass(h[0])?z:r).call(b)};c.fn.noUiSlider=
+function(a,b){return(b?f:e).call(this,a)}})(window.jQuery||window.Zepto);(function(c){function l(a){return c.grep(a,function(b,d){return d===c.inArray(b,a)})}function q(a,b,d,e){if("range"===b||"steps"===b)return a.xVal;if("count"===b){b=100/(d-1);var f,l=0;for(d=[];100>=(f=l++*b);)d.push(f);b="positions"}if("positions"===b)return c.map(d,function(b){return a.fromStepping(e?a.getStep(b):b)});if("values"===b)return e?c.map(d,function(b){return a.fromStepping(a.getStep(a.toStepping(b)))}):d}function m(a,b,d,e){var f=a.direction,m={},p=a.xVal[0],r=a.xVal[a.xVal.length-1],
+n=!1,h=!1,w=0;a.direction=0;e=l(e.slice().sort(function(a,b){return a-b}));e[0]!==p&&(e.unshift(p),n=!0);e[e.length-1]!==r&&(e.push(r),h=!0);c.each(e,function(f){var l,p,r,g=e[f],q=e[f+1],s,u,x,G;"steps"===d&&(l=a.xNumSteps[f]);l||(l=q-g);if(!1!==g&&void 0!==q)for(p=g;p<=q;p+=l){s=a.toStepping(p);r=s-w;x=r/b;x=Math.round(x);G=r/x;for(r=1;r<=x;r+=1)u=w+r*G,m[u.toFixed(5)]=["x",0];x=-1");m.addClass("noUi-pips noUi-pips-"+p);c.each(e,function(a,b){d&&(a=100-a);m.append("");b[1]&&m.append("
"+Math.round(b[0])+"
")});return m}c.fn.noUiSlider_pips=function(a){var b=a.mode,d=a.density||1,e=a.filter||!1,f=a.values||!1,
+l=a.stepped||!1;return this.each(function(){var a=this.getInfo(),r=q(a[0],b,f,l),r=m(a[0],d,b,r);return c(this).append(u(a[1],a[2],a[0].direction,r,e))})}})(window.jQuery||window.Zepto);
diff --git a/jquery.nouislider.js b/jquery.nouislider.js
deleted file mode 100644
index 1b55831d..00000000
--- a/jquery.nouislider.js
+++ /dev/null
@@ -1,1291 +0,0 @@
-/**@preserve
-$.fn.noUiSlider - WTFPL - refreshless.com/nouislider/ */
-
-/*jslint browser: true */
-/*jslint sub: true */
-/*jslint white: true */
-/*jslint continue: true */
-/*jslint plusplus: true */
-
-(function( $ ){
-
- 'use strict';
-
- var
- // Cache the document selector;
- /** @const */
- doc = $(document),
- // Make a backup of the original jQuery/Zepto .val() method.
- /** @const */
- $val = $.fn.val,
- // Namespace for binding and unbinding slider events;
- /** @const */
- namespace = '.nui',
- // Determine the events to bind. IE11 implements pointerEvents without
- // a prefix, which breaks compatibility with the IE10 implementation.
- /** @const */
- actions = 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'
- },
- // Re-usable list of classes;
- /** @const */
- Classes = [
-/* 0 */ 'noUi-target'
-/* 1 */ ,'noUi-base'
-/* 2 */ ,'noUi-origin'
-/* 3 */ ,'noUi-handle'
-/* 4 */ ,'noUi-horizontal'
-/* 5 */ ,'noUi-vertical'
-/* 6 */ ,'noUi-background'
-/* 7 */ ,'noUi-connect'
-/* 8 */ ,'noUi-ltr'
-/* 9 */ ,'noUi-rtl'
-/* 10 */ ,'noUi-dragable'
-/* 11 */ ,''
-/* 12 */ ,'noUi-state-drag'
-/* 13 */ ,''
-/* 14 */ ,'noUi-state-tap'
-/* 15 */ ,'noUi-active'
-/* 16 */ ,'noUi-extended'
-/* 17 */ ,'noUi-stacking'
- ];
-
-
-// General helpers
-
- // Limits a value to 0 - 100
- function limit ( a ) {
- return Math.max(Math.min(a, 100), 0);
- }
-
- // Round a value to the closest 'to'.
- function closest ( value, to ) {
- return Math.round(value / to) * to;
- }
-
- // Determine the size of a sub-range in relation to a full range.
- function subRangeRatio ( pa, pb ) {
- return (100 / (pb - pa));
- }
-
-
-// Type validation
-
- // Checks whether a value is numerical.
- function isNumeric ( a ) {
- return typeof a === 'number' && !isNaN( a ) && isFinite( a );
- }
-
- // Wraps a variable as an array, if it isn't one yet.
- function asArray ( a ) {
- return $.isArray(a) ? a : [a];
- }
-
-
-// Class handling
-
- // Sets a class and removes it after [duration] ms.
- function addClassFor ( element, className, duration ) {
- element.addClass(className);
- setTimeout(function(){
- element.removeClass(className);
- }, duration);
- }
-
-
-// Value calculation
-
- // (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];
- }
-
- // (percentage)
- function toStepping ( options, value ) {
-
- if ( value >= options.xVal.slice(-1)[0] ){
- return 100;
- }
-
- var j = 1, va, vb, pa, pb;
- while ( value >= options.xVal[j] ){
- j++;
- }
-
- va = options.xVal[j-1];
- vb = options.xVal[j];
- pa = options.xPct[j-1];
- pb = options.xPct[j];
-
- return pa + (toPercentage([va, vb], value) / subRangeRatio (pa, pb));
- }
-
- // (value)
- function fromStepping ( options, value ) {
-
- // There is no range group that fits 100
- if ( value >= 100 ){
- return options.xVal.slice(-1)[0];
- }
-
- var j = 1, va, vb, pa, pb;
- while ( value >= options.xPct[j] ){
- j++;
- }
-
- va = options.xVal[j-1];
- vb = options.xVal[j];
- pa = options.xPct[j-1];
- pb = options.xPct[j];
-
- return isPercentage([va, vb], (value - pa) * subRangeRatio (pa, pb));
- }
-
- // (percentage) Get the step that applies at a certain value.
- function getStep ( options, value ){
-
- var j = 1, a, b;
-
- // Find the proper step for rtl sliders by search in inverse direction.
- // Fixes issue #262.
- while ( (options.dir ? (100 - value) : value) >= options.xPct[j] ){
- j++;
- }
-
- if ( options.snap ) {
-
- a = options.xPct[j-1];
- b = options.xPct[j];
-
- if ((value - a) > ((b-a)/2)){
- return b;
- }
-
- return a;
- }
-
- if ( !options.xSteps[j-1] ){
- return value;
- }
-
- return options.xPct[j-1] + closest(
- value - options.xPct[j-1],
- options.xSteps[j-1]
- );
- }
-
-
-// Event handling
-
- // Provide a clean event with standardized offset values.
- function fixEvent ( e ) {
-
- // 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;
- }
-
- // Get the originalEvent, if the event has been wrapped
- // by jQuery. Zepto doesn't wrap the event.
- if ( e.originalEvent ) {
- e = e.originalEvent;
- }
-
- 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;
- }
-
- if ( mouse || pointer ) {
-
- // Polyfill the pageXOffset and pageYOffset
- // variables for IE7 and IE8;
- if( !pointer && window.pageXOffset === undefined ){
- window.pageXOffset = document.documentElement.scrollLeft;
- window.pageYOffset = document.documentElement.scrollTop;
- }
-
- x = e.clientX + window.pageXOffset;
- y = e.clientY + window.pageYOffset;
- }
-
- event.points = [x, y];
- event.cursor = mouse;
-
- return event;
- }
-
-
-// Input validation
-
- 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.xSteps[0] = entry;
- }
-
- function testRange ( parsed, entry ) {
-
- // Filter incorrect input.
- if ( typeof entry !== 'object' || $.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'.");
- }
-
- // Loop all entries.
- $.each( entry, function ( index, value ) {
-
- var percentage;
-
- // Wrap numerical input in an array.
- if ( typeof value === "number" ) {
- value = [value];
- }
-
- // Reject any invalid input.
- if ( !$.isArray( value ) ){
- 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.
- parsed.xPct.push( percentage );
- parsed.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] ) ) {
- parsed.xSteps[0] = value[1];
- }
- } else {
- parsed.xSteps.push( isNaN(value[1]) ? false : value[1] );
- }
- });
-
- $.each(parsed.xSteps, function(i,n){
-
- // Ignore 'false' stepping.
- if ( !n ) {
- return true;
- }
-
- // Check if step fits. Not required, but this might serve some goal.
- // !((parsed.xVal[i+1] - parsed.xVal[i]) % n);
-
- // Factor to range ratio
- parsed.xSteps[i] = fromPercentage([
- parsed.xVal[i]
- ,parsed.xVal[i+1]
- ], n) / subRangeRatio (
- parsed.xPct[i],
- parsed.xPct[i+1] );
- });
- }
-
- function testStart ( parsed, entry ) {
-
- if ( typeof entry === "number" ) {
- entry = [entry];
- }
-
- // Validate input. Values aren't tested, the internal Link will do
- // that and provide a valid location.
- if ( !$.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 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 ( parsed.xPct.length > 2 ) {
- throw new Error("noUiSlider: 'margin' option is only supported on linear sliders.");
- }
-
- // Parse value to range and store. As xVal is checked
- // to be no bigger than 2, use it as range.
- parsed.margin = fromPercentage(parsed.xVal, entry);
-
- if ( !isNumeric(entry) ){
- throw new Error("noUiSlider: 'margin' option must be numeric.");
- }
- }
-
- 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,
- extend = entry.indexOf('extend') >= 0,
- drag = entry.indexOf('drag') >= 0,
- fixed = entry.indexOf('fixed') >= 0,
- snap = entry.indexOf('snap') >= 0;
-
- parsed.events = {
- tap: tap || snap,
- extend: extend,
- drag: drag,
- fixed: fixed,
- snap: snap
- };
- }
-
- function testSerialization ( parsed, entry, sliders ) {
-
- parsed.ser = [ entry['lower'], entry['upper'] ];
- parsed.formatting = entry['format'];
-
- $.each( parsed.ser, function( index, linkInstances ){
-
- // Check if the provided option is an array.
- if ( !$.isArray(linkInstances) ) {
- throw new Error("noUiSlider: 'serialization."+(!index ? 'lower' : 'upper')+"' must be an array.");
- }
-
- $.each(linkInstances, function(){
-
- // Check if entry is a Link.
- if ( !(this instanceof $.Link) ) {
- throw new Error("noUiSlider: 'serialization."+(!index ? 'lower' : 'upper')+"' can only contain Link instances.");
- }
-
- // Assign properties.
- this.setIndex ( index );
- this.setObject( sliders );
- this.setFormatting( entry['format'] );
- });
- });
-
- // If the slider has two handles and is RTL,
- // reverse the serialization input. For one handle,
- // lower is still lower.
- if ( parsed.dir && parsed.handles > 1 ) {
- parsed.ser.reverse();
- }
- }
-
- // Test all developer settings and parse to assumption-safe values.
- function test ( options, sliders ){
-
- /* 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 parsed = {
- xPct: []
- ,xVal: []
- ,xSteps: [ false ]
- ,margin: 0
- }, 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 },
- 'range': { r: true, t: testRange },
- 'snap': { r: false, t: testSnap },
- 'orientation': { r: false, t: testOrientation },
- 'margin': { r: false, t: testMargin },
- 'behaviour': { r: true, t: testBehaviour },
- 'serialization': { r: true, t: testSerialization }
- };
-
- // Set defaults where applicable.
- options = $.extend({
- 'connect': false,
- 'direction': 'ltr',
- 'behaviour': 'tap',
- 'orientation': 'horizontal'
- }, options);
-
- // Make sure the test for serialization runs.
- options['serialization'] = $.extend({
- 'lower': []
- ,'upper': []
- ,'format': {}
- }, options['serialization']);
-
- // 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.
- $.each( tests, function( name, test ){
-
- if ( options[name] === undefined ) {
-
- if ( test.r ) {
- throw new Error("noUiSlider: '" + name + "' is required.");
- }
-
- return true;
- }
-
- test.t( parsed, options[name], sliders );
- });
-
- // Pre-define the styles.
- parsed.style = parsed.ort ? 'top' : 'left';
-
- return parsed;
- }
-
-
-// DOM additions
-
- // Append a handle to the base.
- function addHandle ( options, index ) {
-
- var handle = $('
').addClass( Classes[2] ),
- additions = [ '-lower', '-upper' ];
-
- if ( options.dir ) {
- additions.reverse();
- }
-
- handle.children().addClass(
- Classes[3] + " " + Classes[3]+additions[index]
- );
-
- return handle;
- }
-
- // Create a copy of an element-creating Link.
- function addElement ( handle, link ) {
-
- // If the Link requires creation of a new element,
- // create this element and return a new Link instance.
- if ( link.el ) {
-
- link = new $.Link({
- 'target': $(link.el).clone().appendTo( handle ),
- 'method': link.method,
- 'format': link.formatting
- }, true);
- }
-
- // Otherwise, return the reference.
- return link;
- }
-
- // Loop all links for a handle.
- function addElements ( elements, handle, formatting ) {
-
- var index, list = [], standard = new $.Link({}, true);
-
- // Use the Link interface to provide unified
- // formatting for the .val() method.
- standard.setFormatting(formatting);
-
- // The list now contains at least one element.
- list.push( standard );
-
- // Loop all links in either 'lower' or 'upper'.
- for ( index = 0; index < elements.length; index++ ) {
- list.push(addElement(handle, elements[index]));
- }
-
- return list;
- }
-
- // Go over all Links and assign them to a handle.
- function addLinks ( options, handles ) {
-
- var index, links = [];
-
- // Copy the links into a new array, instead of modifying
- // the 'options.ser' list. This allows replacement of the invalid
- // '.el' Links, while the others are still passed by reference.
- for ( index = 0; index < options.handles; index++ ) {
-
- // Append a new array.
- links[index] = addElements(
- options.ser[index],
- handles[index].children(),
- options.formatting
- );
- }
-
- return links;
- }
-
- // 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: target.addClass( Classes[7] );
- handles[0].addClass( Classes[6] );
- break;
- case 3: handles[1].addClass( Classes[6] );
- /* falls through */
- case 2: handles[0].addClass( Classes[7] );
- /* falls through */
- case 0: target.addClass(Classes[6]);
- break;
- }
- }
-
- // Add handles and loop Link elements.
- function addHandles ( options, base ) {
-
- var index, handles = [];
-
- // Append handles.
- for ( index = 0; index < options.handles; index++ ) {
-
- // Keep a list of all added handles.
- handles.push( addHandle( options, index ).appendTo(base) );
- }
-
- return handles;
- }
-
- // Initialize a single slider.
- function addSlider ( options, target ) {
-
- // Apply classes and data to the target.
- target.addClass([
- Classes[0],
- Classes[8 + options.dir],
- Classes[4 + options.ort]
- ].join(' '));
-
- return $('').appendTo(target).addClass( Classes[1] );
- }
-
-
-// Slider scope
-
-function closure ( target, options, originalOptions ){
-
-// Internal variables
-
- // All variables local to 'closure' are marked $.
- var $Target = $(target),
- $Locations = [-1, -1],
- $Base,
- $Serialization,
- $Handles;
-
- // Shorthand for base dimensions.
- function baseSize ( ) {
- return $Base[['width', 'height'][options.ort]]();
- }
-
-
-// External event handling
-
- function fireEvents ( events ) {
-
- // Use the external api to get the values.
- // Wrap the values in an array, as .trigger takes
- // only one additional argument.
- var index, values = [ $Target.val() ];
-
- for ( index = 0; index < events.length; index++ ){
- $Target.trigger(events[index], values);
- }
- }
-
-
-// Handle placement
-
- // Test suggested values and apply margin, step.
- function setHandle ( handle, to, delimit ) {
-
- var n = handle[0] !== $Handles[0][0] ? 1 : 0,
- lower = $Locations[0] + options.margin,
- upper = $Locations[1] - options.margin;
-
- // Don't delimit range dragging.
- if ( delimit && $Handles.length > 1 ) {
- to = n ? Math.max( to, lower ) : Math.min( to, upper );
- }
-
- // Handle the step option.
- if ( to < 100 ){
- to = getStep(options, to);
- }
-
- // Limit to 0/100 for .val input, trim anything beyond 7 digits, as
- // JavaScript has some issues in its floating point implementation.
- to = limit(parseFloat(to.toFixed(7)));
-
- // Return falsy if handle can't move. False for 0 or 100 limit,
- // '0' for limiting by another handle.
- if ( to === $Locations[n] ) {
- if ( $Handles.length === 1 ) {
- return false;
- }
- return ( to === lower || to === upper ) ? 0 : false;
- }
-
- // Set the handle to the new position.
- handle.css( options.style, to + '%' );
-
- // Force proper handle stacking
- if ( handle.is(':first-child') ) {
- handle.toggleClass(Classes[17], to > 50 );
- }
-
- // Update locations.
- $Locations[n] = to;
-
- // Invert the value if this is a right-to-left slider.
- if ( options.dir ) {
- to = 100 - to;
- }
-
- // Write values to serialization Links.
- // Convert the value to the correct relative representation.
- // Convert the value to the slider stepping/range.
- $($Serialization[n]).each(function(){
- this.write( fromStepping( options, to ), handle.children(), $Target );
- });
-
- return true;
- }
-
- // 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];
- }
-
- // Handles movement by tapping.
- function jump ( handle, to, instant ) {
-
- if ( !instant ) {
- // Flag the slider as it is now in a transitional state.
- // Transition takes 300 ms, so re-enable the slider afterwards.
- addClassFor( $Target, Classes[14], 300 );
- }
-
- // Move the handle to the new position.
- setHandle( handle, to, false );
-
- fireEvents(['slide', 'set', 'change']);
- }
-
-
-// Events
-
- // Handler for attaching events trough a proxy.
- function attach ( events, element, callback, data ) {
-
- // Add the noUiSlider namespace to all events.
- events = events.replace( /\s/g, namespace + ' ' ) + namespace;
-
- // Bind a closure on the target.
- return element.on( events, function( e ){
-
- // jQuery and Zepto handle unset attributes differently.
- var disabled = $Target.attr('disabled');
- disabled = !( disabled === undefined || disabled === null );
-
- // Test if there is anything that should prevent an event
- // from being handled, such as a disabled state or an active
- // 'tap' transition.
- if( $Target.hasClass( Classes[14] ) || disabled ) {
- return false;
- }
-
- e = fixEvent(e);
- e.calcPoint = e.points[ options.ort ];
-
- // Call the event handler with the event [ and additional data ].
- callback ( e, data );
- });
- }
-
- // Handle movement on document for handle and range drag.
- function move ( event, data ) {
-
- var handles = data.handles || $Handles, positions, state = false,
- proposal = ((event.calcPoint - data.start) * 100) / baseSize(),
- h = handles[0][0] !== $Handles[0][0] ? 1 : 0;
-
- // Calculate relative positions for the handles.
- positions = getPositions( proposal, data.positions, handles.length > 1);
-
- state = setHandle ( handles[0], positions[h], handles.length === 1 );
-
- if ( handles.length > 1 ) {
- state = setHandle ( handles[1], positions[h?0:1], false ) || state;
- }
-
- // Fire the 'slide' event if any handle moved.
- if ( state ) {
- fireEvents(['slide']);
- }
- }
-
- // Unbind move events on document, call callbacks.
- function end ( event ) {
-
- // The handle is no longer active, so remove the class.
- $('.' + Classes[15]).removeClass(Classes[15]);
-
- // Remove cursor styles and text-selection events bound to the body.
- if ( event.cursor ) {
- $('body').css('cursor', '').off( namespace );
- }
-
- // Unbind the move and end events, which are added on 'start'.
- doc.off( namespace );
-
- // Remove dragging class.
- $Target.removeClass(Classes[12]);
-
- // Fire the change and set events.
- fireEvents(['set', 'change']);
- }
-
- // Bind move events on document.
- function start ( event, data ) {
-
- // Mark the handle as 'active' so it can be styled.
- if( data.handles.length === 1 ) {
- data.handles[0].children().addClass(Classes[15]);
- }
-
- // A drag should never propagate up to the 'tap' event.
- event.stopPropagation();
-
- // Attach the move event.
- attach ( actions.move, doc, move, {
- start: event.calcPoint,
- handles: data.handles,
- positions: [
- $Locations[0],
- $Locations[$Handles.length - 1]
- ]
- });
-
- // Unbind all movement when the drag ends.
- attach ( actions.end, doc, end, null );
-
- // 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.
- $('body').css('cursor', $(event.target).css('cursor'));
-
- // Mark the target with a dragging state.
- if ( $Handles.length > 1 ) {
- $Target.addClass(Classes[12]);
- }
-
- // Prevent text selection when dragging the handles.
- $('body').on('selectstart' + namespace, false);
- }
- }
-
- // Move closest handle to tapped location.
- function tap ( event ) {
-
- var location = event.calcPoint, total = 0, to;
-
- // The tap event shouldn't propagate up and cause 'edge' to run.
- event.stopPropagation();
-
- // Add up the handle offsets.
- $.each( $Handles, function(){
- total += this.offset()[ options.style ];
- });
-
- // Find the handle closest to the tapped position.
- total = ( location < total/2 || $Handles.length === 1 ) ? 0 : 1;
-
- location -= $Base.offset()[ options.style ];
-
- // Calculate the new position.
- to = ( location * 100 ) / baseSize();
-
- // Find the closest handle and calculate the tapped point.
- // The set handle to the new position.
- jump( $Handles[total], to, options.events.snap );
-
- if ( options.events.snap ) {
- start(event, { handles: [$Handles[total]] });
- }
- }
-
- // Move handle to edges when target gets tapped.
- function edge ( event ) {
-
- var i = event.calcPoint < $Base.offset()[ options.style ],
- to = i ? 0 : 100;
-
- i = i ? 0 : $Handles.length - 1;
-
- jump( $Handles[i], to, false );
- }
-
- // Attach events to several slider parts.
- function events ( behaviour ) {
-
- var i, drag;
-
- // Attach the standard drag event to the handles.
- if ( !behaviour.fixed ) {
-
- for ( i = 0; i < $Handles.length; i++ ) {
-
- // These events are only bound to the visual handle
- // element, not the 'real' origin element.
- attach ( actions.start, $Handles[i].children(), start, {
- handles: [ $Handles[i] ]
- });
- }
- }
-
- // Attach the tap event to the slider base.
- if ( behaviour.tap ) {
- attach ( actions.start, $Base, tap, {
- handles: $Handles
- });
- }
-
- // Extend tapping behaviour to target
- if ( behaviour.extend ) {
-
- $Target.addClass( Classes[16] );
-
- if ( behaviour.tap ) {
- attach ( actions.start, $Target, edge, {
- handles: $Handles
- });
- }
- }
-
- // Make the range dragable.
- if ( behaviour.drag ){
-
- drag = $Base.find( '.' + Classes[7] ).addClass( Classes[10] );
-
- // 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 = drag.add($Base.children().not( drag ).children());
- }
-
- attach ( actions.start, drag, start, {
- handles: $Handles
- });
- }
- }
-
-
-// Initialize slider
-
- // Throw an error if the slider was already initialized.
- if ( $Target.hasClass(Classes[0]) ) {
- throw new Error('Slider was already initialized.');
- }
-
- // Create the base element, initialise HTML and set classes.
- // Add handles and links.
- $Base = addSlider( options, $Target );
- $Handles = addHandles( options, $Base );
- $Serialization = addLinks( options, $Handles );
-
- // Set the connect classes.
- addConnection ( options.connect, $Target, $Handles );
-
- // Attach user events.
- events( options.events );
-
-
-// Methods
-
- // Set the slider value.
- /** @expose */
- target.vSet = function ( ) {
-
- var args = Array.prototype.slice.call( arguments, 0 ),
- callback, link, update, animate,
- i, count, actual, to, values = asArray( args[0] );
-
- // Extract modifiers for value method.
- if ( typeof args[1] === 'object' ) {
- callback = args[1]['set'];
- link = args[1]['link'];
- update = args[1]['update'];
- animate = args[1]['animate'];
-
- // Support the 'true' option.
- } else if ( args[1] === true ) {
- callback = true;
- }
-
- // 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.
- if ( animate ) {
- addClassFor( $Target, Classes[14], 300 );
- }
-
- // Determine how often to set the handles.
- count = $Handles.length > 1 ? 3 : 1;
- if ( values.length === 1 ) {
- 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++ ) {
-
- to = link || $Serialization[i%2][0];
- to = to.getValue( values[i%2] );
-
- if ( to === false ) {
- continue;
- }
-
- // Calculate the new handle position
- to = toStepping( options, to );
-
- // Invert the value if this is a right-to-left slider.
- if ( options.dir ) {
- to = 100 - to;
- }
-
- // Force delimitation.
- if ( setHandle( $Handles[i%2], to, true ) === true ) {
- continue;
- }
-
- // Reset the input if it doesn't match the slider.
- $($Serialization[i%2]).each(function(index){
-
- if (!index) {
- actual = this.actual;
- return true;
- }
-
- this.write(
- actual,
- $Handles[i%2].children(),
- $Target,
- update
- );
- });
- }
-
- // Optionally fire the 'set' event.
- if( callback === true ) {
- fireEvents(['set']);
- }
-
- return this;
- };
-
- // Get the slider value.
- /** @expose */
- target.vGet = function ( ) {
-
- var i, retour = [];
-
- // Get the value from all handles.
- for ( i = 0; i < options.handles; i++ ){
- retour[i] = $Serialization[i][0].saved;
- }
-
- // If only one handle is used, return a single value.
- if ( retour.length === 1 ){
- return retour[0];
- }
-
- if ( options.dir ) {
- return retour.reverse();
- }
-
- return retour;
- };
-
- // Destroy the slider and unbind all events.
- /** @expose */
- target.destroy = function ( ) {
-
- // Loop all linked serialization objects and unbind all
- // events in the noUiSlider namespace.
- $.each($Serialization, function(){
- $.each(this, function(){
- // Won't remove 'change' when bound implicitly.
- if ( this.target ) {
- this.target.off( namespace );
- }
- });
- });
-
- // Unbind events on the slider, remove all classes and child elements.
- $(this).off(namespace)
- .removeClass(Classes.join(' '))
- .empty();
-
- // Return the original options from the closure.
- return originalOptions;
- };
-
-
-// Value setting
-
- // Use the public value method to set the start values.
- $Target.val( options.start );
-}
-
-
-// Access points
-
- // Run the standard initializer
- function initialize ( originalOptions ) {
-
- // Throw error if group is empty.
- if ( !this.length ){
- throw new Error("noUiSlider: Can't initialize slider on empty selection.");
- }
-
- // Test the options once, not for every slider.
- var options = test( originalOptions, this );
-
- // Loop all items, and provide a new closed-scope environment.
- return this.each(function(){
- closure(this, options, originalOptions);
- });
- }
-
- // Destroy the slider, then re-enter initialization.
- function rebuild ( options ) {
-
- return this.each(function(){
-
- // Get the current values from the slider,
- // including the initialization options.
- var values = $(this).val(),
- originalOptions = this.destroy(),
-
- // Extend the previous options with the newly provided ones.
- newOptions = $.extend( {}, originalOptions, options );
-
- // Run the standard initializer.
- $(this).noUiSlider( newOptions );
-
- // If the start option hasn't changed,
- // reset the previous values.
- if ( originalOptions.start === newOptions.start ) {
- $(this).val(values);
- }
- });
- }
-
- // Access the internal getting and setting methods based on argument count.
- function value ( ) {
- return this[0][ !arguments.length ? 'vGet' : 'vSet' ].apply(this[0], arguments);
- }
-
- // Override the .val() method. Test every element. Is it a slider? Go to
- // the slider value handling. No? Use the standard method.
- // Note how $.fn.val extects 'this' to be an instance of $. For convenience,
- // the above 'value' function does too.
- $.fn.val = function ( ) {
-
- // this === instanceof $
-
- function valMethod( a ){
- return a.hasClass(Classes[0]) ? value : $val;
- }
-
- var args = arguments,
- first = $(this[0]);
-
- if ( !arguments.length ) {
- return valMethod(first).call(first);
- }
-
- // Return the set so it remains chainable
- return this.each(function(){
- valMethod($(this)).apply($(this), args);
- });
- };
-
-// Remap the serialization constructor for legacy support.
- /** @expose */
- $.noUiSlider = { 'Link': $.Link };
-
-// Extend jQuery/Zepto with the noUiSlider method.
- /** @expose */
- $.fn.noUiSlider = function ( options, re ) {
- return ( re ? rebuild : initialize ).call(this, options);
- };
-
-}( window['jQuery'] || window['Zepto'] ));
diff --git a/jquery.nouislider.min.js b/jquery.nouislider.min.js
index b9a63edd..850b0b32 100644
--- a/jquery.nouislider.min.js
+++ b/jquery.nouislider.min.js
@@ -1,31 +1,22 @@
-/*
-
-$.Link (part of noUiSlider) - WTFPL */
-(function(c){function m(a,c,d){if((a[c]||a[d])&&a[c]===a[d])throw Error("(Link) '"+c+"' can't match '"+d+"'.'");}function r(a){void 0===a&&(a={});if("object"!==typeof a)throw Error("(Format) 'format' option must be an object.");var h={};c(u).each(function(c,n){if(void 0===a[n])h[n]=A[c];else if(typeof a[n]===typeof A[c]){if("decimals"===n&&(0>a[n]||7a&&(n=this.a("negative"),k=this.a("negativeBefore"));a=Math.abs(a).toFixed(d).toString();a=a.split(".");this.a("thousand")?(m=c(a[0]).match(/.{1,3}/g),m=c(m.join(c(this.a("thousand"))))):m=a[0];this.a("mark")&&1")[0]};k.prototype.H=function(a){this.method="val";this.j=document.createElement("input");this.j.name=a;this.j.type="hidden"};k.prototype.G=function(a){function h(a,c){return[c?null:a,c?a:null]}var d=this;this.method="val";this.target=a.on("change",function(a){d.B.val(h(c(a.target).val(),d.t),{link:d,set:!0})})};k.prototype.p=function(a,h,d,k){this.g=d;this.update=!k;if("string"===
-typeof a&&0===a.indexOf("-tooltip-"))this.K(a,h);else if("string"===typeof a&&0!==a.indexOf("-"))this.H(a);else if("function"===typeof a)this.target=!1,this.method=a;else{if(a instanceof c||c.zepto&&c.zepto.isZ(a)){if(!h){if(a.is("input, select, textarea")){this.G(a);return}h="html"}if("function"===typeof h||"string"===typeof h&&a[h]){this.method=h;this.target=a;return}}throw new RangeError("(Link) Invalid Link.");}};k.prototype.write=function(a,c,d,k){if(!this.update||!1!==k)if(this.u=a,this.F=a=
-this.format(a),"function"===typeof this.method)this.method.call(this.target[0]||d[0],a,c,d);else this.target[this.method](a,c,d)};k.prototype.q=function(a){this.g=new r(c.extend({},a,this.g instanceof r?this.g.r:this.g))};k.prototype.J=function(a){this.B=a};k.prototype.I=function(a){this.t=a};k.prototype.format=function(a){return this.g.L(a)};k.prototype.A=function(a){return this.g.w(a)};k.prototype.p.prototype=k.prototype;c.Link=k})(window.jQuery||window.Zepto);/*
-
-$.fn.noUiSlider - WTFPL - refreshless.com/nouislider/ */
-(function(c){function m(e){return"number"===typeof e&&!isNaN(e)&&isFinite(e)}function r(e){return c.isArray(e)?e:[e]}function k(e,b){e.addClass(b);setTimeout(function(){e.removeClass(b)},300)}function u(e,b){return 100*b/(e[1]-e[0])}function A(e,b){if(b>=e.d.slice(-1)[0])return 100;for(var a=1,c,f,d;b>=e.d[a];)a++;c=e.d[a-1];f=e.d[a];d=e.c[a-1];c=[c,f];return d+u(c,0>c[0]?b+Math.abs(c[0]):b-c[0])/(100/(e.c[a]-d))}function a(e,b){if(100<=b)return e.d.slice(-1)[0];for(var a=1,c,f,d;b>=e.c[a];)a++;c=
-e.d[a-1];f=e.d[a];d=e.c[a-1];c=[c,f];return 100/(e.c[a]-d)*(b-d)*(c[1]-c[0])/100+c[0]}function h(a,b){for(var c=1,g;(a.dir?100-b:b)>=a.c[c];)c++;if(a.m)return g=a.c[c-1],c=a.c[c],b-g>(c-g)/2?c:g;a.h[c-1]?(g=a.h[c-1],c=a.c[c-1]+Math.round((b-a.c[c-1])/g)*g):c=b;return c}function d(a,b){if(!m(b))throw Error("noUiSlider: 'step' is not numeric.");a.h[0]=b}function n(a,b){if("object"!==typeof b||c.isArray(b))throw Error("noUiSlider: 'range' is not an object.");if(void 0===b.min||void 0===b.max)throw Error("noUiSlider: Missing 'min' or 'max' in 'range'.");
-c.each(b,function(b,g){var d;"number"===typeof g&&(g=[g]);if(!c.isArray(g))throw Error("noUiSlider: 'range' contains invalid value.");d="min"===b?0:"max"===b?100:parseFloat(b);if(!m(d)||!m(g[0]))throw Error("noUiSlider: 'range' value isn't numeric.");a.c.push(d);a.d.push(g[0]);d?a.h.push(isNaN(g[1])?!1:g[1]):isNaN(g[1])||(a.h[0]=g[1])});c.each(a.h,function(b,c){if(!c)return!0;a.h[b]=u([a.d[b],a.d[b+1]],c)/(100/(a.c[b+1]-a.c[b]))})}function E(a,b){"number"===typeof b&&(b=[b]);if(!c.isArray(b)||!b.length||
-2").addClass(f[2]),g=["-lower","-upper"];a.dir&&g.reverse();d.children().addClass(f[3]+" "+f[3]+g[b]);return d}function Q(a,b){b.j&&(b=new c.Link({target:c(b.j).clone().appendTo(a),method:b.method,format:b.g},!0));return b}function R(a,b){var d,f=[];for(d=0;d").appendTo(b).addClass(f[1])}function V(d,b,m){function g(){return t[["width","height"][b.k]]()}function n(a){var b,c=[q.val()];for(b=0;bp&&(p=h(b,p));p=Math.max(Math.min(parseFloat(p.toFixed(7)),100),0);if(p===x[g])return 1===l.length?!1:p===H||p===k?0:!1;d.css(b.style,p+"%");d.is(":first-child")&&d.toggleClass(f[17],50
d&&(e+=Math.abs(d)),100=g[e];)e+=1;return e}function k(d,g,e,a){this.xPct=[];this.xVal=[];this.xSteps=[a||!1];this.xNumSteps=[!1];this.snap=g;this.direction=e;for(var f in d)if(d.hasOwnProperty(f)){g=f;e=d[f];a=void 0;"number"===typeof e&&(e=[e]);if("[object Array]"!==Object.prototype.toString.call(e))throw Error("noUiSlider: 'range' contains invalid value.");a="min"===g?0:
+"max"===g?100:parseFloat(g);if(!q(a)||!q(e[0]))throw Error("noUiSlider: 'range' value isn't numeric.");this.xPct.push(a);this.xVal.push(e[0]);a?this.xSteps.push(isNaN(e[1])?!1:e[1]):isNaN(e[1])||(this.xSteps[0]=e[1])}this.xNumSteps=this.xSteps.slice(0);for(f in this.xNumSteps)this.xNumSteps.hasOwnProperty(f)&&(d=Number(f),(g=this.xNumSteps[f])&&(this.xSteps[d]=s([this.xVal[d],this.xVal[d+1]],g)/(100/(this.xPct[d+1]-this.xPct[d]))))}k.prototype.getMargin=function(d){return 2===this.xPct.length?s(this.xVal,
+d):!1};k.prototype.toStepping=function(d){var g=this.xVal,a=this.xPct;if(d>=g.slice(-1)[0])d=100;else{var m=p(d,g),f,k;f=g[m-1];k=g[m];g=a[m-1];a=a[m];f=[f,k];d=s(f,0>f[0]?d+Math.abs(f[0]):d-f[0]);d=g+d/(100/(a-g))}this.direction&&(d=100-d);return d};k.prototype.fromStepping=function(d){this.direction&&(d=100-d);var a;var e=this.xVal;a=this.xPct;if(100<=d)a=e.slice(-1)[0];else{var m=p(d,a),f,k;f=e[m-1];k=e[m];e=a[m-1];f=[f,k];a=100/(a[m]-e)*(d-e)*(f[1]-f[0])/100+f[0]}d=Math.pow(10,7);return Number((Math.round(a*
+d)/d).toFixed(7))};k.prototype.getStep=function(d){this.direction&&(d=100-d);var a=this.xPct,e=this.xSteps,k=this.snap;if(100!==d){var f=p(d,a);k?(e=a[f-1],a=a[f],d=d-e>(a-e)/2?a:e):(e[f-1]?(k=a[f-1],e=e[f-1],a=Math.round((d-a[f-1])/e)*e,a=k+a):a=d,d=a)}this.direction&&(d=100-d);return d};k.prototype.getApplicableStep=function(a){var g=p(a,this.xPct);a=100===a?2:1;return[this.xNumSteps[g-2],this.xVal[g-a],this.xNumSteps[g-a]]};k.prototype.convert=function(a){return this.getStep(this.toStepping(a))};
+a.noUiSlider={Spectrum:k}})(window.jQuery||window.Zepto);(function(a){function q(c){return"number"===typeof c&&!isNaN(c)&&isFinite(c)}function s(c,b){if(!q(b))throw Error("noUiSlider: 'step' is not numeric.");c.singleStep=b}function p(c,b){if("object"!==typeof b||a.isArray(b))throw Error("noUiSlider: 'range' is not an object.");if(void 0===b.min||void 0===b.max)throw Error("noUiSlider: Missing 'min' or 'max' in 'range'.");c.spectrum=new a.noUiSlider.Spectrum(b,c.snap,c.dir,c.singleStep)}function k(c,b){var d=b;b=a.isArray(d)?d:[d];if(!a.isArray(b)||!b.length||
+2").addClass(h[2]),e=["-lower","-upper"];c&&e.reverse();d.children().addClass(h[3]+" "+h[3]+e[b]);return d}function k(a,b,d){switch(a){case 1:b.addClass(h[7]);d[0].addClass(h[6]);break;case 3:d[1].addClass(h[6]);case 2:d[0].addClass(h[7]);case 0:b.addClass(h[6])}}function d(a,b,d){var e,f=[];for(e=0;e").appendTo(d).addClass(h[1])}function e(c,b,e){function f(){return v[["width","height"][b.ort]]()}function m(b){var a,c=[n.val()];for(a=0;ad&&(e+=Math.abs(d)),100=c[1]?c[2]:c[0],c[2]]]});return p(b)};c.getInfo=function(){return[z,b.style,b.ort]};n.val(b.start)}function m(c){if(!this.length)throw Error("noUiSlider: Can't initialize slider on empty selection.");var b=a.noUiSlider.testOptions(c,this);return this.each(function(){e(this,
+b,c)})}function f(c){return this.each(function(){if(this.destroy){var b=a(this).val(),d=this.destroy(),e=a.extend({},d,c);a(this).noUiSlider(e);this.reappend();d.start===e.start&&a(this).val(b)}else a(this).noUiSlider(c)})}function x(){return this[0][arguments.length?"vSet":"vGet"].apply(this[0],arguments)}var y=a(document),t=a.fn.val,u=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"},h="noUi-target noUi-base noUi-origin noUi-handle noUi-horizontal noUi-vertical noUi-background noUi-connect noUi-ltr noUi-rtl noUi-dragable noUi-state-drag noUi-state-tap noUi-active noUi-stacking".split(" ");a.fn.val=function(){var c=arguments,b=a(this[0]);return arguments.length?this.each(function(){(a(this).hasClass(h[0])?x:t).apply(a(this),c)}):(b.hasClass(h[0])?x:t).call(b)};a.fn.noUiSlider=
+function(a,b){return(b?f:m).call(this,a)}})(window.jQuery||window.Zepto);
diff --git a/jquery.nouislider.pips.css b/jquery.nouislider.pips.css
new file mode 100644
index 00000000..d1a93971
--- /dev/null
+++ b/jquery.nouislider.pips.css
@@ -0,0 +1,98 @@
+
+/* Base;
+ *
+ */
+.noUi-pips,
+.noUi-pips * {
+-moz-box-sizing: border-box;
+ box-sizing: border-box;
+}
+.noUi-pips {
+ position: absolute;
+ font: 400 12px Arial;
+ color: #999;
+}
+
+/* Values;
+ *
+ */
+.noUi-value {
+ width: 40px;
+ position: absolute;
+ text-align: center;
+}
+.noUi-value-sub {
+ color: #ccc;
+ font-size: 10px;
+}
+
+/* Markings;
+ *
+ */
+.noUi-marker {
+ position: absolute;
+ background: #CCC;
+}
+.noUi-marker-sub {
+ background: #AAA;
+}
+.noUi-marker-large {
+ background: #AAA;
+}
+
+/* Horizontal layout;
+ *
+ */
+.noUi-pips-horizontal {
+ padding: 10px 0;
+ height: 50px;
+ top: 100%;
+ left: 0;
+ width: 100%;
+}
+.noUi-value-horizontal {
+ margin-left: -20px;
+ padding-top: 20px;
+}
+.noUi-value-horizontal.noUi-value-sub {
+ padding-top: 15px;
+}
+
+.noUi-marker-horizontal.noUi-marker {
+ margin-left: -1px;
+ width: 2px;
+ height: 5px;
+}
+.noUi-marker-horizontal.noUi-marker-sub {
+ height: 10px;
+}
+.noUi-marker-horizontal.noUi-marker-large {
+ height: 15px;
+}
+
+/* Vertical layout;
+ *
+ */
+.noUi-pips-vertical {
+ padding: 0 10px;
+ height: 100%;
+ top: 0;
+ left: 100%;
+}
+.noUi-value-vertical {
+ width: 15px;
+ margin-left: 20px;
+ margin-top: -5px;
+}
+
+.noUi-marker-vertical.noUi-marker {
+ width: 5px;
+ height: 2px;
+ margin-top: -1px;
+}
+.noUi-marker-vertical.noUi-marker-sub {
+ width: 10px;
+}
+.noUi-marker-vertical.noUi-marker-large {
+ width: 15px;
+}
diff --git a/libLink b/libLink
new file mode 160000
index 00000000..e6a1ddf4
--- /dev/null
+++ b/libLink
@@ -0,0 +1 @@
+Subproject commit e6a1ddf4bd411e9f793db80c8692314783d28200
diff --git a/src/module.base.js b/src/module.base.js
new file mode 100644
index 00000000..b71a9c1e
--- /dev/null
+++ b/src/module.base.js
@@ -0,0 +1,872 @@
+/*jslint browser: true */
+/*jslint white: true */
+
+(function( $ ){
+
+ 'use strict';
+
+ var
+ // Cache the document selector;
+ /** @const */
+ doc = $(document),
+ // Make a backup of the original jQuery/Zepto .val() method.
+ /** @const */
+ $val = $.fn.val,
+ // Namespace for binding and unbinding slider events;
+ /** @const */
+ namespace = '.nui',
+ // Determine the events to bind. IE11 implements pointerEvents without
+ // a prefix, which breaks compatibility with the IE10 implementation.
+ /** @const */
+ actions = 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'
+ },
+ // Re-usable list of classes;
+ /** @const */
+ Classes = [
+/* 0 */ 'noUi-target'
+/* 1 */ ,'noUi-base'
+/* 2 */ ,'noUi-origin'
+/* 3 */ ,'noUi-handle'
+/* 4 */ ,'noUi-horizontal'
+/* 5 */ ,'noUi-vertical'
+/* 6 */ ,'noUi-background'
+/* 7 */ ,'noUi-connect'
+/* 8 */ ,'noUi-ltr'
+/* 9 */ ,'noUi-rtl'
+/* 10 */ ,'noUi-dragable'
+/* 11 */ ,''
+/* 12 */ ,'noUi-state-drag'
+/* 13 */ ,''
+/* 14 */ ,'noUi-state-tap'
+/* 15 */ ,'noUi-active'
+/* 16 */ ,''
+/* 17 */ ,'noUi-stacking'
+ ];
+
+
+// General helpers
+
+ // 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 $.isArray(a) ? a : [a];
+ }
+
+
+// Class handling
+
+ // Sets a class and removes it after [duration] ms.
+ function addClassFor ( element, className, duration ) {
+ element.addClass(className);
+ setTimeout(function(){
+ element.removeClass(className);
+ }, duration);
+ }
+
+ // 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];
+ }
+
+
+
+// Event handling
+
+ // Provide a clean event with standardized offset values.
+ function fixEvent ( e ) {
+
+ // 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;
+ }
+
+ // Get the originalEvent, if the event has been wrapped
+ // by jQuery. Zepto doesn't wrap the event.
+ if ( e.originalEvent ) {
+ e = e.originalEvent;
+ }
+
+ 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;
+ }
+
+ if ( mouse || pointer ) {
+
+ // Polyfill the pageXOffset and pageYOffset
+ // variables for IE7 and IE8;
+ if( !pointer && window.pageXOffset === undefined ){
+ window.pageXOffset = document.documentElement.scrollLeft;
+ window.pageYOffset = document.documentElement.scrollTop;
+ }
+
+ x = e.clientX + window.pageXOffset;
+ y = e.clientY + window.pageYOffset;
+ }
+
+ event.points = [x, y];
+ event.cursor = mouse;
+
+ return event;
+ }
+
+
+// DOM additions
+
+ // Append a handle to the base.
+ function addHandle ( direction, index ) {
+
+ var handle = $('
').addClass( Classes[2] ),
+ additions = [ '-lower', '-upper' ];
+
+ if ( direction ) {
+ additions.reverse();
+ }
+
+ handle.children().addClass(
+ Classes[3] + " " + Classes[3]+additions[index]
+ );
+
+ return handle;
+ }
+
+ // 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: target.addClass( Classes[7] );
+ handles[0].addClass( Classes[6] );
+ break;
+ case 3: handles[1].addClass( Classes[6] );
+ /* falls through */
+ case 2: handles[0].addClass( Classes[7] );
+ /* falls through */
+ case 0: target.addClass(Classes[6]);
+ 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( addHandle( direction, index ).appendTo(base) );
+ }
+
+ return handles;
+ }
+
+ // Initialize a single slider.
+ function addSlider ( direction, orientation, target ) {
+
+ // Apply classes and data to the target.
+ target.addClass([
+ Classes[0],
+ Classes[8 + direction],
+ Classes[4 + orientation]
+ ].join(' '));
+
+ return $('').appendTo(target).addClass( Classes[1] );
+ }
+
+
+// Slider scope
+
+function closure ( target, options, originalOptions ){
+
+// Internal variables
+
+ // All variables local to 'closure' are marked $.
+ var $Target = $(target),
+ $Locations = [-1, -1],
+ $Base,
+ $Handles,
+ $Spectrum = options.spectrum,
+ $Values = [],
+ // libLink. For rtl sliders, 'lower' and 'upper' should not be inverted
+ // for one-handle sliders, so trim 'upper' it that case.
+ triggerPos = ['lower', 'upper'].slice(0, options.handles);
+
+ // Invert the libLink connection for rtl sliders.
+ if ( options.dir ) {
+ triggerPos.reverse();
+ }
+
+
+// Helpers
+
+ // Shorthand for base dimensions.
+ function baseSize ( ) {
+ return $Base[['width', 'height'][options.ort]]();
+ }
+
+ // External event handling
+ function fireEvents ( events ) {
+
+ // Use the external api to get the values.
+ // Wrap the values in an array, as .trigger takes
+ // only one additional argument.
+ var index, values = [ $Target.val() ];
+
+ for ( index = 0; index < events.length; index += 1 ){
+ $Target.trigger(events[index], values);
+ }
+ }
+
+ // 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;
+ }
+
+
+// libLink integration
+
+ // Create a new function which calls .val on input change.
+ function createChangeHandler ( trigger ) {
+ return function ( ignore, value ){
+ // Determine which array position to 'null' based on 'trigger'.
+ $Target.val( [ trigger ? null : value, trigger ? value : null ], true );
+ };
+ }
+
+ // Called by libLink when it wants a set of links updated.
+ function linkUpdate ( flag ) {
+
+ var trigger = $.inArray(flag, triggerPos);
+
+ // The API might not have been set yet.
+ if ( $Target[0].linkAPI && $Target[0].linkAPI[flag] ) {
+ $Target[0].linkAPI[flag].change(
+ $Values[trigger],
+ $Handles[trigger].children(),
+ $Target
+ );
+ }
+ }
+
+ // Called by libLink to append an element to the slider.
+ function linkConfirm ( flag, element ) {
+
+ // Find the trigger for the passed flag.
+ var trigger = $.inArray(flag, triggerPos);
+
+ // If set, append the element to the handle it belongs to.
+ if ( element ) {
+ element.appendTo( $Handles[trigger].children() );
+ }
+
+ // The public API is reversed for rtl sliders, so the changeHandler
+ // should not be aware of the inverted trigger positions.
+ if ( options.dir ) {
+ trigger = trigger === 1 ? 0 : 1;
+ }
+
+ return createChangeHandler( trigger );
+ }
+
+ // Place elements back on the slider.
+ function reAppendLink ( ) {
+
+ var i, flag;
+
+ // The API keeps a list of elements: we can re-append them on rebuild.
+ for ( i = 0; i < triggerPos.length; i += 1 ) {
+ if ( this.linkAPI && this.linkAPI[(flag = triggerPos[i])] ) {
+ this.linkAPI[flag].reconfirm(flag);
+ }
+ }
+ }
+
+ target.LinkUpdate = linkUpdate;
+ target.LinkConfirm = linkConfirm;
+ target.LinkDefaultFormatter = options.format;
+ target.LinkDefaultFlag = 'lower';
+
+ target.reappend = reAppendLink;
+
+
+ // Test suggested values and apply margin, step.
+ function setHandle ( handle, to, noLimitOption ) {
+
+ var trigger = handle[0] !== $Handles[0][0] ? 1 : 0,
+ lowerMargin = $Locations[0] + options.margin,
+ upperMargin = $Locations[1] - options.margin,
+ lowerLimit = $Locations[0] + options.limit,
+ upperLimit = $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 ( $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 && $Handles.length > 1 ) {
+ to = trigger ? Math.min ( to, lowerLimit ) : Math.max( to, upperLimit );
+ }
+
+ // Handle the step option.
+ to = $Spectrum.getStep( to );
+
+ // Limit to 0/100 for .val input, trim anything beyond 7 digits, as
+ // JavaScript has some issues in its floating point implementation.
+ to = limit(parseFloat(to.toFixed(7)));
+
+ // Return false if handle can't move.
+ if ( to === $Locations[trigger] ) {
+ return false;
+ }
+
+ // Set the handle to the new position.
+ handle.css( options.style, to + '%' );
+
+ // Force proper handle stacking
+ if ( handle.is(':first-child') ) {
+ handle.toggleClass(Classes[17], to > 50 );
+ }
+
+ // Update locations.
+ $Locations[trigger] = to;
+
+ // Convert the value to the slider stepping/range.
+ $Values[trigger] = $Spectrum.fromStepping( to );
+
+ linkUpdate(triggerPos[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( $Handles[trigger], $Spectrum.toStepping( to ), i === (3 - options.dir) ) === false ) {
+
+ linkUpdate(triggerPos[trigger]);
+ }
+ }
+ }
+ }
+
+
+
+ // Handler for attaching events trough a proxy.
+ function attach ( events, element, callback, data ) {
+
+ // This function can be used to 'filter' events to the slider.
+
+ // Add the noUiSlider namespace to all events.
+ events = events.replace( /\s/g, namespace + ' ' ) + namespace;
+
+ // Bind a closure on the target.
+ return element.on( events, function( e ){
+
+ // jQuery and Zepto (1) handle unset attributes differently,
+ // but always falsy; #208
+ if ( !!$Target.attr('disabled') ) {
+ return false;
+ }
+
+ // Stop if an active 'tap' transition is taking place.
+ if ( $Target.hasClass( Classes[14] ) ) {
+ return false;
+ }
+
+ e = fixEvent(e);
+ e.calcPoint = e.points[ options.ort ];
+
+ // Call the event handler with the event [ and additional data ].
+ callback ( e, data );
+ });
+ }
+
+ // Handle movement on document for handle and range drag.
+ function move ( event, data ) {
+
+ var handles = data.handles || $Handles, positions, state = false,
+ proposal = ((event.calcPoint - data.start) * 100) / baseSize(),
+ h = handles[0][0] !== $Handles[0][0] ? 1 : 0;
+
+ // Calculate relative positions for the handles.
+ positions = getPositions( proposal, data.positions, handles.length > 1);
+
+ state = setHandle ( handles[0], positions[h], handles.length === 1 );
+
+ if ( handles.length > 1 ) {
+ state = setHandle ( handles[1], positions[h?0:1], false ) || state;
+ }
+
+ // Fire the 'slide' event if any handle moved.
+ if ( state ) {
+ fireEvents(['slide']);
+ }
+ }
+
+ // Unbind move events on document, call callbacks.
+ function end ( event ) {
+
+ // The handle is no longer active, so remove the class.
+ $('.' + Classes[15]).removeClass(Classes[15]);
+
+ // Remove cursor styles and text-selection events bound to the body.
+ if ( event.cursor ) {
+ $('body').css('cursor', '').off( namespace );
+ }
+
+ // Unbind the move and end events, which are added on 'start'.
+ doc.off( namespace );
+
+ // Remove dragging class.
+ $Target.removeClass(Classes[12]);
+
+ // Fire the change and set events.
+ fireEvents(['set', 'change']);
+ }
+
+ // Bind move events on document.
+ function start ( event, data ) {
+
+ // Mark the handle as 'active' so it can be styled.
+ if( data.handles.length === 1 ) {
+ data.handles[0].children().addClass(Classes[15]);
+ }
+
+ // A drag should never propagate up to the 'tap' event.
+ event.stopPropagation();
+
+ // Attach the move event.
+ attach ( actions.move, doc, move, {
+ start: event.calcPoint,
+ handles: data.handles,
+ positions: [
+ $Locations[0],
+ $Locations[$Handles.length - 1]
+ ]
+ });
+
+ // Unbind all movement when the drag ends.
+ attach ( actions.end, doc, end, null );
+
+ // 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.
+ $('body').css('cursor', $(event.target).css('cursor'));
+
+ // Mark the target with a dragging state.
+ if ( $Handles.length > 1 ) {
+ $Target.addClass(Classes[12]);
+ }
+
+ // Prevent text selection when dragging the handles.
+ $('body').on('selectstart' + namespace, false);
+ }
+ }
+
+ // Move closest handle to tapped location.
+ function tap ( event ) {
+
+ var location = event.calcPoint, total = 0, to;
+
+ // The tap event shouldn't propagate up and cause 'edge' to run.
+ event.stopPropagation();
+
+ // Add up the handle offsets.
+ $.each( $Handles, function(){
+ total += this.offset()[ options.style ];
+ });
+
+ // Find the handle closest to the tapped position.
+ total = ( location < total/2 || $Handles.length === 1 ) ? 0 : 1;
+
+ location -= $Base.offset()[ 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 300 ms, so re-enable the slider afterwards.
+ addClassFor( $Target, Classes[14], 300 );
+ }
+
+ // Find the closest handle and calculate the tapped point.
+ // The set handle to the new position.
+ setHandle( $Handles[total], to );
+
+ fireEvents(['slide', 'set', 'change']);
+
+ if ( options.events.snap ) {
+ start(event, { handles: [$Handles[total]] });
+ }
+ }
+
+ // Attach events to several slider parts.
+ function events ( behaviour ) {
+
+ var i, drag;
+
+ // Attach the standard drag event to the handles.
+ if ( !behaviour.fixed ) {
+
+ for ( i = 0; i < $Handles.length; i += 1 ) {
+
+ // These events are only bound to the visual handle
+ // element, not the 'real' origin element.
+ attach ( actions.start, $Handles[i].children(), start, {
+ handles: [ $Handles[i] ]
+ });
+ }
+ }
+
+ // Attach the tap event to the slider base.
+ if ( behaviour.tap ) {
+
+ attach ( actions.start, $Base, tap, {
+ handles: $Handles
+ });
+ }
+
+ // Make the range dragable.
+ if ( behaviour.drag ){
+
+ drag = $Base.find( '.' + Classes[7] ).addClass( Classes[10] );
+
+ // 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 = drag.add($Base.children().not( drag ).children());
+ }
+
+ attach ( actions.start, drag, start, {
+ handles: $Handles
+ });
+ }
+ }
+
+
+
+ // Set the slider value.
+ function valueSet ( input ) {
+
+ // LibLink: don't accept new values when currently emitting changes.
+ if ( $Target[0].LinkIsEmitting ) {
+ return this;
+ }
+
+ var count, values = asArray( input );
+
+ // 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. (no report, unit testing);
+ if ( options.animate && $Locations[0] !== -1 ) {
+ addClassFor( $Target, Classes[14], 300 );
+ }
+
+ // Determine how often to set the handles.
+ count = $Handles.length > 1 ? 3 : 1;
+
+ if ( values.length === 1 ) {
+ count = 1;
+ }
+
+ setValues ( count, values );
+
+ // Fire the 'set' event. As of noUiSlider 7,
+ // this is no longer optional.
+ fireEvents(['set']);
+
+ return this;
+ }
+
+ // 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( $Values[i] );
+ }
+
+ return inSliderOrder( retour );
+ }
+
+
+
+ // Destroy the slider and unbind all events.
+ function destroyTarget ( ) {
+
+ // Unbind events on the slider, remove all classes and child elements.
+ $(this).off(namespace)
+ .removeClass(Classes.join(' '))
+ .empty();
+
+ delete this.LinkUpdate;
+ delete this.LinkConfirm;
+ delete this.LinkDefaultFormatter;
+ delete this.LinkDefaultFlag;
+ delete this.reappend;
+ delete this.vGet;
+ delete this.vSet;
+ delete this.getCurrentStep;
+ delete this.getInfo;
+ delete this.destroy;
+
+ // Return the original options from the closure.
+ return originalOptions;
+ }
+
+ // 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 = $.map($Locations, function( location, index ){
+
+ var step = $Spectrum.getApplicableStep( location ),
+ value = $Values[index],
+ increment = step[2],
+ decrement = (value - step[2]) >= step[1] ? step[2] : step[0];
+
+ return [[decrement, increment]];
+ });
+
+ // Return values in the proper order.
+ return inSliderOrder( retour );
+ }
+
+
+
+// Initialize slider
+
+ // Throw an error if the slider was already initialized.
+ if ( $Target.hasClass(Classes[0]) ) {
+ throw new Error('Slider was already initialized.');
+ }
+
+ // Create the base element, initialise HTML and set classes.
+ // Add handles and links.
+ $Base = addSlider( options.dir, options.ort, $Target );
+ $Handles = addHandles( options.handles, options.dir, $Base );
+
+ // Set the connect classes.
+ addConnection ( options.connect, $Target, $Handles );
+
+ // Attach user events.
+ events( options.events );
+
+// Methods
+
+ target.vSet = valueSet;
+ target.vGet = valueGet;
+ target.destroy = destroyTarget;
+ target.getCurrentStep = getCurrentStep;
+ target.getInfo = function(){
+ return [
+ $Spectrum,
+ options.style,
+ options.ort
+ ];
+ };
+
+ // Use the public value method to set the start values.
+ $Target.val( options.start );
+}
+
+
+// Access points
+
+ // Run the standard initializer
+ function initialize ( originalOptions ) {
+
+ // Throw error if group is empty.
+ if ( !this.length ){
+ throw new Error("noUiSlider: Can't initialize slider on empty selection.");
+ }
+
+ // Test the options once, not for every slider.
+ var options = $.noUiSlider.testOptions( originalOptions, this );
+
+ // Loop all items, and provide a new closed-scope environment.
+ return this.each(function(){
+ closure(this, options, originalOptions);
+ });
+ }
+
+ // Destroy the slider, then re-enter initialization.
+ function rebuild ( options ) {
+
+ return this.each(function(){
+
+ // The rebuild flag can be used if the slider wasn't initialized yet.
+ if ( !this.destroy ) {
+ $(this).noUiSlider( options );
+ return;
+ }
+
+ // Get the current values from the slider,
+ // including the initialization options.
+ var values = $(this).val(), originalOptions = this.destroy(),
+
+ // Extend the previous options with the newly provided ones.
+ newOptions = $.extend( {}, originalOptions, options );
+
+ // Run the standard initializer.
+ $(this).noUiSlider( newOptions );
+
+ // Place Link elements back.
+ this.reappend();
+
+ // If the start option hasn't changed,
+ // reset the previous values.
+ if ( originalOptions.start === newOptions.start ) {
+ $(this).val(values);
+ }
+ });
+ }
+
+ // Access the internal getting and setting methods based on argument count.
+ function value ( ) {
+ return this[0][ !arguments.length ? 'vGet' : 'vSet' ].apply(this[0], arguments);
+ }
+
+ // Override the .val() method. Test every element. Is it a slider? Go to
+ // the slider value handling. No? Use the standard method.
+ // Note how $.fn.val expects 'this' to be an instance of $. For convenience,
+ // the above 'value' function does too.
+ $.fn.val = function ( ) {
+
+ // this === instanceof $
+
+ function valMethod( a ){
+ return a.hasClass(Classes[0]) ? value : $val;
+ }
+
+ var args = arguments,
+ first = $(this[0]);
+
+ if ( !arguments.length ) {
+ return valMethod(first).call(first);
+ }
+
+ // Return the set so it remains chainable
+ return this.each(function(){
+ valMethod($(this)).apply($(this), args);
+ });
+ };
+
+// Extend jQuery/Zepto with the noUiSlider method.
+ $.fn.noUiSlider = function ( options, rebuildFlag ) {
+ return ( rebuildFlag ? rebuild : initialize ).call(this, options);
+ };
+
+}( window.jQuery || window.Zepto ));
diff --git a/src/module.options.js b/src/module.options.js
new file mode 100644
index 00000000..20d64aa8
--- /dev/null
+++ b/src/module.options.js
@@ -0,0 +1,269 @@
+/*jslint browser: true */
+/*jslint white: true */
+
+/* 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. */
+
+(function( $ ){
+
+ 'use strict';
+
+ // Wraps a variable as an array, if it isn't one yet.
+ function asArray ( a ) {
+ return $.isArray(a) ? a : [a];
+ }
+
+ // Checks whether a value is numerical.
+ function isNumeric ( a ) {
+ return typeof a === 'number' && !isNaN( a ) && isFinite( a );
+ }
+
+ /** @const */
+ var defaultFormatter = { 'to': function( value ){
+ return 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' || $.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'.");
+ }
+
+ parsed.spectrum = new $.noUiSlider.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 ( !$.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 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.");
+ }
+
+ 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;
+
+ parsed.events = {
+ tap: tap || snap,
+ drag: drag,
+ fixed: fixed,
+ snap: snap
+ };
+ }
+
+ 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 testOptions ( options ) {
+
+ var parsed = {
+ margin: 0,
+ limit: 0,
+ animate: true,
+ 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 },
+ '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 }
+ };
+
+ // Set defaults where applicable.
+ options = $.extend({
+ 'connect': false,
+ 'direction': 'ltr',
+ 'behaviour': 'tap',
+ 'orientation': 'horizontal'
+ }, options);
+
+ // 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.
+ $.each( tests, function( name, test ){
+
+ // If the option isn't set, but it is required, throw an error.
+ if ( options[name] === undefined ) {
+
+ if ( test.r ) {
+ throw new Error("noUiSlider: '" + name + "' is required.");
+ }
+
+ return true;
+ }
+
+ test.t( parsed, options[name] );
+ });
+
+ // Pre-define the styles.
+ parsed.style = parsed.ort ? 'top' : 'left';
+
+ return parsed;
+ }
+
+ // Test all developer settings and parse to assumption-safe values.
+ $.noUiSlider.testOptions = testOptions;
+
+}( window.jQuery || window.Zepto ));
diff --git a/src/module.range.js b/src/module.range.js
new file mode 100644
index 00000000..9c44754d
--- /dev/null
+++ b/src/module.range.js
@@ -0,0 +1,290 @@
+/*jslint browser: true */
+/*jslint white: true */
+
+(function( $ ){
+
+ 'use strict';
+
+// Helpers
+
+ // Determine the size of a sub-range in relation to a full range.
+ function subRangeRatio ( pa, pb ) {
+ return (100 / (pb - pa));
+ }
+
+ // Round a value to the closest 'to'.
+ function closest ( value, to ) {
+ return Math.round(value / to) * to;
+ }
+
+ // Checks whether a value is numerical.
+ function isNumeric ( a ) {
+ return typeof a === 'number' && !isNaN( a ) && isFinite( a );
+ }
+
+ // Rounds a number to 7 supported decimals.
+ function accurateNumber( number ) {
+ var p = Math.pow(10, 7);
+ return Number((Math.round(number*p)/p).toFixed(7));
+ }
+
+
+// Value calculation
+
+ // (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 that = this, index;
+
+ // Loop all entries.
+ for ( index in entry ) {
+ if ( entry.hasOwnProperty(index) ) {
+ handleEntryPoint(index, entry[index], that);
+ }
+ }
+
+ // Store the actual step values.
+ that.xNumSteps = that.xSteps.slice(0);
+
+ for ( index in that.xNumSteps ) {
+ if ( that.xNumSteps.hasOwnProperty(index) ) {
+ handleStepPoint(Number(index), that.xNumSteps[index], that);
+ }
+ }
+ }
+
+ 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 accurateNumber(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));
+ };
+
+ $.noUiSlider = {
+ Spectrum: Spectrum
+ };
+
+}( window.jQuery || window.Zepto ));
diff --git a/src/optional.pips.js b/src/optional.pips.js
new file mode 100644
index 00000000..a7c862d0
--- /dev/null
+++ b/src/optional.pips.js
@@ -0,0 +1,234 @@
+/*jslint browser: true */
+/*jslint white: true */
+
+(function( $ ){
+
+ 'use strict';
+
+ // Removes duplicates from an array.
+ function unique(array) {
+ return $.grep(array, function(el, index) {
+ return index === $.inArray(el, array);
+ });
+ }
+
+// Pips
+
+ function getGroup ( $Spectrum, mode, values, stepped ) {
+
+ // Use the range.
+ if ( mode === 'range' || mode === 'steps' ) {
+ return $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 $.map(values, function( value ){
+ return $Spectrum.fromStepping( stepped ? $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 $.map(values, function( value ){
+
+ // Convert to percentage, apply step, return to value.
+ return $Spectrum.fromStepping( $Spectrum.getStep( $Spectrum.toStepping( value ) ) );
+ });
+
+ }
+
+ // Otherwise, we can simply use the values.
+ return values;
+ }
+ }
+
+ function generateSpread ( $Spectrum, density, mode, group ) {
+
+ var originalSpectrumDirection = $Spectrum.direction,
+ indexes = {},
+ firstInRange = $Spectrum.xVal[0],
+ lastInRange = $Spectrum.xVal[$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.
+ $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;
+ }
+
+ $.each(group, function ( index ) {
+
+ // Get the current step and the lower + upper positions.
+ var step, i, q,
+ low = group[index],
+ 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 = $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 += step ) {
+
+ // Get the percentage value for the current step,
+ // calculate the size for the subrange.
+ newPct = $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 = ($.inArray(i, group) > -1) ? 1 : ( mode === 'steps' ? 2 : 0 );
+
+ // Enforce the 'ignoreFirst' option by overwriting the type for 0.
+ if ( !index && ignoreFirst && !low ) {
+ 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.
+ $Spectrum.direction = originalSpectrumDirection;
+
+ return indexes;
+ }
+
+ function addMarking ( CSSstyle, orientation, direction, spread, filterFunc ) {
+
+ var style = ['horizontal', 'vertical'][orientation],
+ element = $('');
+
+ element.addClass('noUi-pips noUi-pips-'+style);
+
+ function getSize( type, value ){
+ return [ '-normal', '-large', '-sub' ][(type&&filterFunc) ? filterFunc(value, type) : type];
+ }
+ function getTags( offset, source, values ) {
+ return 'class="' + source + ' ' +
+ source + '-' + style + ' ' +
+ source + getSize(values[1], values[0]) +
+ '" style="' + CSSstyle + ': ' + offset + '%"';
+ }
+ function addSpread ( offset, values ){
+
+ if ( direction ) {
+ offset = 100 - offset;
+ }
+
+ // Add a marker for every point
+ element.append('');
+
+ // Values are only appended for points marked '1' or '2'.
+ if ( values[1] ) {
+ element.append('