diff --git a/README.md b/README.md index 80b5ea48..884757fe 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ # noUiSlider -noUiSlider is lightweight plugin, developed to be a jQuery UI alternative. It features cross-browser support, a `just-another-input-type` style of getting and setting values, a wide range of options and support for a bunch of touch devices. It works wonders on Android phones, iPhone & iPad, Windows phone and touch-screen laptops and tablets. It works excellent on the desktop too; All modern browsers and IE7+ are supported. The end result? A lean, extendible and bloat-less plugin that'll just do its job. To add even more flexibility, noUiSlider is compatible with both jQuery and Zepto.js. Oh, and the licensing terms are simple: [just do what you want](http://refreshless.com/nouislider/terms-of-use). +noUiSlider is lightweight plugin, developed to be a jQuery UI alternative. It features cross-browser support, a `just-another-input-type` style of getting and setting values, a wide range of options and support for a bunch of touch devices. It works wonders on Android phones, iPhone & iPad, Windows phone and touch-screen laptops and tablets. It works excellent on the desktop too; All modern browsers and IE7+ are supported. The end result? A lean, extendible and bloat-less plugin that'll just do its job. To add even more flexibility, noUiSlider is compatible with both jQuery and Zepto.js. Oh, and the licensing terms are simple: [just do what you want](http://www.wtfpl.net/about/). Documentation ------- @@ -10,13 +10,13 @@ An extensive documentation, including **examples**, **options** and **configurat Changes ------- -**Changelog for version 6.1.0:** -**Compatible with 6.0.0** +**Changelog for version 6.2.0:** +*(Compatible with 6.0.0)* -+ Split out value methods into [$.classVal](https://github.com/leongersen/classVal). This is **included** in the release download. -+ `$.noUiSlider.Link` is now an alias to `$.Link`. The Link functionality has been moved into a new file. (also in the download). -+ Several bug fixes. -+ Added `to` and `from` to [number formatting](http://refreshless.com/nouislider/number-formatting) ++ 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:** @@ -30,24 +30,42 @@ Changes Unit Testing ------------ - -Unit tests where added with noUiSlider 6. The event testing coverage isn't 100% yet, but coverage of the `Link` is extensive. More tests will be added eventually. +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. Version numbering ------------------------------ -Version numbering follows the 'Semantic versioning' style. +Version numbering follows the 'Semantic versioning' style. You'll find an excellent documentation at [Semver.org](http://semver.org/). Compression and Error checking ------------------------------ -**CSS** ([CSSMinifier](http://cssminifier.com/)) -The stylesheet is trimmed to remove whitespace and comments to provide a `min` version. +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 folling 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 -**JS** ([Google Closure Compiler](http://closure-compiler.appspot.com/home)) -The plugin is compressed using the Google Closure compiler. The source was adapted to facilitate the `ADVANCED_OPTIMIZATIONS` level. +java -jar .\compiler\compiler.jar --compilation_level ADVANCED_OPTIMIZATIONS --externs %jquery% --warning_level VERBOSE --js %link% --js %source% --js_output_file %result% -**Code** ([JsLint](http://jslint.com/)) -The plugin code is checked using JsLint. Any remaining errors and warnings are intentional. +echo "Done." +PAUSE +``` Known issues ------------ diff --git a/bower.json b/bower.json index cc230fa3..63aeb2f0 100644 --- a/bower.json +++ b/bower.json @@ -12,13 +12,11 @@ "slide" ], "main": [ - "Link.js", - "jquery.nouislider.js", + "jquery.nouislider.min.js", "jquery.nouislider.css" ], "dependencies": { - "jquery": ">= 1.7.0", - "classval": ">= 0.1.0" + "jquery": ">= 1.7.0" }, "ignore": [ "**/.*", diff --git a/jquery.nouislider.js b/jquery.nouislider.js index 6dfd19c9..1b55831d 100644 --- a/jquery.nouislider.js +++ b/jquery.nouislider.js @@ -15,6 +15,9 @@ $.fn.noUiSlider - WTFPL - refreshless.com/nouislider/ */ // 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', @@ -164,7 +167,10 @@ $.fn.noUiSlider - WTFPL - refreshless.com/nouislider/ */ function getStep ( options, value ){ var j = 1, a, b; - while ( value >= options.xPct[j] ){ + + // 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++; } @@ -266,6 +272,12 @@ $.fn.noUiSlider - WTFPL - refreshless.com/nouislider/ */ 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 ) { @@ -506,15 +518,16 @@ $.fn.noUiSlider - WTFPL - refreshless.com/nouislider/ */ ,margin: 0 }, tests; + // Tests are executed in the order they are presented here. tests = { 'step': { r: false, t: testStep }, - 'range': { r: true, t: testRange }, 'start': { r: true, t: testStart }, - 'snap': { r: false, t: testSnap }, '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 }, - 'direction': { r: true, t: testDirection }, 'behaviour': { r: true, t: testBehaviour }, 'serialization': { r: true, t: testSerialization } }; @@ -1235,6 +1248,35 @@ function closure ( target, options, originalOptions ){ }); } + // 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 */ @@ -1246,7 +1288,4 @@ function closure ( target, options, originalOptions ){ return ( re ? rebuild : initialize ).call(this, options); }; -// Attach a classbased val handler. - $.classVal(Classes[0], 'vGet', 'vSet', false); - }( window['jQuery'] || window['Zepto'] )); diff --git a/jquery.nouislider.min.js b/jquery.nouislider.min.js new file mode 100644 index 00000000..b9a63edd --- /dev/null +++ b/jquery.nouislider.min.js @@ -0,0 +1,31 @@ +/* + +$.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],50d&&(e+=Math.abs(d)),100\ + \ + \ +
\ + '); + + var one = $("#one"); + var two = $("#two"); + var three = $("#three"); + + var slider = $("#simpleslider").noUiSlider({ + range: { min: 20, max: 120 }, + start: 30 + }); + + one.val(35); + equal(one.val(), 35); + + one.val(35); + equal(one.val(), 35); + + two.val( 40 ); + equal(two.val(), 40); + + slider.add(one).val(90); + + equal(slider.val(), '90.00'); + equal(one.val(), 90); + + Q.find("input").val(60); + + equal(one.val(), 60); + equal(two.val(), 60); + equal(three.val(), 60); + + three.val(50); + + ok(one[0] === one.val(10)[0]); + ok(two[0] === two.val(20)[0]); + + }); diff --git a/tests/errors.js b/tests/errors.js index 4034d2d3..41674fa1 100644 --- a/tests/errors.js +++ b/tests/errors.js @@ -2,7 +2,10 @@ test( "Testing input validation.", function(){ Q.html('\ -
\ +
\ +
\ +
\ +
\ '); var settings = { @@ -15,7 +18,7 @@ }; throws(function(){ - $('.slider').noUiSlider($.extend({}, { + $('.slider1').noUiSlider($.extend({}, { serialization: { lower: [ new Link({ @@ -30,7 +33,7 @@ }, "Decimal count."); throws(function(){ - $('.slider').noUiSlider($.extend({}, { + $('.slider2').noUiSlider($.extend({}, { serialization: { format: { negative: function(){} @@ -40,7 +43,7 @@ }, "Format item type."); throws(function(){ - $('.slider').noUiSlider($.extend({}, { + $('.slider3').noUiSlider($.extend({}, { serialization: { lower: [ new Link({ @@ -57,4 +60,10 @@ }, settings)); }, "Incompatible equal formatting options."); + throws(function(){ + $('.slider4').noUiSlider({ + range: { }, + start: [20, 30] + }); + }, "Missing 'min' or 'max' in range."); }); diff --git a/tests/non-linear-rtl.js b/tests/non-linear-rtl.js new file mode 100644 index 00000000..66b795b0 --- /dev/null +++ b/tests/non-linear-rtl.js @@ -0,0 +1,53 @@ + + test( "Testing ltr and rtl non-linear", function(){ + + Q.html('\ +
\ +
\ + '); + + var sliderRTL = $('.sliderRTL'); + var sliderLTR = $('.sliderLTR'); + + sliderRTL.noUiSlider({ + range: { + 'min': 0, + '30%': 5, + '50%': [ 10, 10 ], + 'max': 50 + }, + start: 44, + direction : 'rtl', + serialization: { + format: { decimals: 0 } + } + }); + + sliderLTR.noUiSlider({ + range: { + 'min': 0, + '30%': 5, + '50%': [ 10, 10 ], + 'max': 50 + }, + start: 44, + serialization: { + format: { decimals: 0 } + } + }); + + equal(sliderRTL.val(), '40', 'Start stepping on rtl works'); + equal(sliderLTR.val(), '40', 'Start stepping on ltr works'); + + sliderRTL.val(42); + sliderLTR.val(42); + + equal(sliderRTL.val(), '40', 'RTL slider stepped by 10 in upper half.'); + equal(sliderLTR.val(), '40', 'LTR slider stepped by 10 in upper half.'); + + sliderRTL.val(6); + sliderLTR.val(6); + + equal(sliderRTL.val(), '6', 'RTL slider didn\'t step in lower half.'); + equal(sliderLTR.val(), '6', 'LTR slider didn\'t step in lower half.'); + }); diff --git a/tests/rtl.js b/tests/rtl.js index 58bdd503..cc669589 100644 --- a/tests/rtl.js +++ b/tests/rtl.js @@ -21,12 +21,12 @@ serialization: { lower: [ new Link({ - target: $("#min"), + target: $("#min") }) ], upper: [ new Link({ - target: $("#max"), + target: $("#max") }) ] } @@ -41,7 +41,7 @@ slider.val([30,35]); deepEqual(slider.val(), ["30.00", "35.00"], "RTL slider understepped properly."); - + }); test( "RTL slider multiple value set.", function(){ @@ -62,17 +62,17 @@ serialization: { lower: [ new Link({ - target: $("#min"), + target: $("#min") }) - ], + ] } }); - + equal(slider.val(), 0.4); - + slider.val(0.201, true); equal(slider.val(), 0.2); - + slider.val(0.201, true); equal(slider.val(), 0.2); }); diff --git a/tests/run.html b/tests/run.html index cdef8aea..7972ce3a 100644 --- a/tests/run.html +++ b/tests/run.html @@ -1,17 +1,9 @@ - Testing - - + + - + + + + + - +--> - + @@ -71,5 +68,7 @@ + +