From ac5166b42fae974ffbbace5c7c444b7f87afe79d Mon Sep 17 00:00:00 2001 From: Leon Gersen Date: Mon, 21 Apr 2014 14:15:33 +0200 Subject: [PATCH] Tests, error throwing, closure --- Link.js | 53 +++++++++++++------------- jquery.nouislider.js | 90 ++++++++++++++++++++------------------------ tests/run.html | 12 +++++- tests/update-link.js | 58 ++++++++++++++++++++++++++++ tests/val.js | 51 +++++++++++++++++++++++++ 5 files changed, 188 insertions(+), 76 deletions(-) create mode 100644 tests/update-link.js create mode 100644 tests/val.js diff --git a/Link.js b/Link.js index 1fee7828..29df4b58 100644 --- a/Link.js +++ b/Link.js @@ -5,12 +5,6 @@ $.Link (part of noUiSlider) - WTFPL */ /*jslint sub: true */ /*jslint white: true */ -// ==ClosureCompiler== -// @externs_url http://refreshless.com/externs/jquery-1.8.js -// @compilation_level ADVANCED_OPTIMIZATIONS -// @warning_level VERBOSE -// ==/ClosureCompiler== - (function( $ ){ 'use strict'; @@ -18,7 +12,7 @@ $.Link (part of noUiSlider) - WTFPL */ // Throw an error if formatting options are incompatible. function throwEqualError( F, a, b ) { if ( (F[a] || F[b]) && (F[a] === F[b]) ) { - throwError("(Link) '"+a+"' can't match '"+b+"'.'"); + throw new Error("(Link) '"+a+"' can't match '"+b+"'.'"); } } @@ -65,7 +59,7 @@ var } if ( typeof options !== 'object' ){ - throwError("(Format) 'format' option must be an object."); + throw new Error("(Format) 'format' option must be an object."); } var settings = {}; @@ -84,7 +78,7 @@ var // More can't be guaranteed due to floating point issues. if ( val === 'decimals' ){ if ( options[val] < 0 || options[val] > 7 ){ - throwError("(Format) 'format.decimals' option must be between 0 and 7."); + throw new Error("(Format) 'format.decimals' option must be between 0 and 7."); } } @@ -92,7 +86,7 @@ var // If the value isn't valid, emit an error. } else { - throwError("(Format) 'format."+val+"' must be a " + typeof FormatDefaults[i] + "."); + throw new Error("(Format) 'format."+val+"' must be a " + typeof FormatDefaults[i] + "."); } }); @@ -118,7 +112,14 @@ var number = this.v('encoder')( number ); - var negative = '', preNegative = '', base = '', mark = ''; + 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'); @@ -126,15 +127,9 @@ var } // Round to proper decimal count - number = Math.abs(number).toFixed( this.v('decimals') ).toString(); + number = Math.abs(number).toFixed(decimals).toString(); number = number.split('.'); - // Rounding away decimals might cause a value of -0 - // when using very small ranges. Remove those cases. - if ( parseFloat(number) === 0 ) { - number[0] = '0'; - } - // Group numbers in sets of three. if ( this.v('thousand') ) { base = reverse(number[0]).match(/.{1,3}/g); @@ -167,10 +162,12 @@ var // 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 ) { + if ( input === null || input === undefined ) { return false; } + input = this.v('from')(input); + // Remove formatting and set period for float parsing. input = input.toString(); @@ -189,7 +186,7 @@ var input = input.replace(new RegExp('^'+esc( this.v('prefix') )), ''); // Only replace if a negative sign is set. - if ( this.v['negative'] ) { + if ( this.v('negative') ) { // Reset isNeg to prevent double '-' insertion. isNeg = ''; @@ -215,7 +212,7 @@ var return false; } - return this.v('from')(input); + return input; }; @@ -273,6 +270,7 @@ var // Initialisor + /** @constructor */ Link.prototype.init = function ( target, method, format, update ) { // Write all formatting to this object. @@ -291,7 +289,7 @@ var // 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, method ); + this.setHidden( target ); return; } @@ -327,7 +325,7 @@ var // 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 ) { @@ -358,16 +356,19 @@ var // Set formatting options. Link.prototype.setFormatting = function ( options ) { - this.formatting = new Format( $.extend({}, options, this.formatting )); + 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 ) { diff --git a/jquery.nouislider.js b/jquery.nouislider.js index 3bd67f2d..6dfd19c9 100644 --- a/jquery.nouislider.js +++ b/jquery.nouislider.js @@ -7,24 +7,21 @@ $.fn.noUiSlider - WTFPL - refreshless.com/nouislider/ */ /*jslint continue: true */ /*jslint plusplus: true */ -// ==ClosureCompiler== -// @externs_url http://refreshless.com/externs/jquery-1.8.js -// @compilation_level ADVANCED_OPTIMIZATIONS -// @warning_level VERBOSE -// ==/ClosureCompiler== - (function( $ ){ 'use strict'; var // Cache the document selector; -/** @const */ doc = $(document), + /** @const */ + doc = $(document), // Namespace for binding and unbinding slider events; -/** @const */ namespace = '.nui', + /** @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'] ? { + /** @const */ + actions = window.navigator['pointerEnabled'] ? { start: 'pointerdown', move: 'pointermove', end: 'pointerup' @@ -38,7 +35,8 @@ $.fn.noUiSlider - WTFPL - refreshless.com/nouislider/ */ end: 'mouseup touchend' }, // Re-usable list of classes; -/** @const */ Classes = [ + /** @const */ + Classes = [ /* 0 */ 'noUi-target' /* 1 */ ,'noUi-base' /* 2 */ ,'noUi-origin' @@ -60,13 +58,6 @@ $.fn.noUiSlider - WTFPL - refreshless.com/nouislider/ */ ]; -// Error handling - - function throwError( message ){ - throw new RangeError('noUiSlider: ' + message); - } - - // General helpers // Limits a value to 0 - 100 @@ -260,7 +251,7 @@ $.fn.noUiSlider - WTFPL - refreshless.com/nouislider/ */ function testStep ( parsed, entry ) { if ( !isNumeric( entry ) ) { - throwError("'step' is not numeric."); + throw new Error("noUiSlider: 'step' is not numeric."); } // The step option can still be used to set stepping @@ -272,7 +263,7 @@ $.fn.noUiSlider - WTFPL - refreshless.com/nouislider/ */ // Filter incorrect input. if ( typeof entry !== 'object' || $.isArray(entry) ) { - throwError("'range' is not an object."); + throw new Error("noUiSlider: 'range' is not an object."); } // Loop all entries. @@ -287,7 +278,7 @@ $.fn.noUiSlider - WTFPL - refreshless.com/nouislider/ */ // Reject any invalid input. if ( !$.isArray( value ) ){ - throwError("'range' contains invalid value."); + throw new Error("noUiSlider: 'range' contains invalid value."); } // Covert min/max syntax to 0 and 100. @@ -301,7 +292,7 @@ $.fn.noUiSlider - WTFPL - refreshless.com/nouislider/ */ // Check for correct input. if ( !isNumeric( percentage ) || !isNumeric( value[0] ) ) { - throwError("'range' value isn't numeric."); + throw new Error("noUiSlider: 'range' value isn't numeric."); } // Store values. @@ -349,7 +340,7 @@ $.fn.noUiSlider - WTFPL - refreshless.com/nouislider/ */ // 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 ) { - throwError("'start' option is incorrect."); + throw new Error("noUiSlider: 'start' option is incorrect."); } // Store the number of handles. @@ -366,7 +357,7 @@ $.fn.noUiSlider - WTFPL - refreshless.com/nouislider/ */ parsed.snap = entry; if ( typeof entry !== 'boolean' ){ - throwError("'snap' option must be a boolean."); + throw new Error("noUiSlider: 'snap' option must be a boolean."); } } @@ -381,7 +372,7 @@ $.fn.noUiSlider - WTFPL - refreshless.com/nouislider/ */ } else if ( entry === false ) { parsed.connect = 0; } else { - throwError("'connect' option doesn't match handle count."); + throw new Error("noUiSlider: 'connect' option doesn't match handle count."); } } @@ -397,14 +388,14 @@ $.fn.noUiSlider - WTFPL - refreshless.com/nouislider/ */ parsed.ort = 1; break; default: - throwError("'orientation' option is invalid."); + throw new Error("noUiSlider: 'orientation' option is invalid."); } } function testMargin ( parsed, entry ) { if ( parsed.xPct.length > 2 ) { - throwError("'margin' option is only supported on linear sliders."); + throw new Error("noUiSlider: 'margin' option is only supported on linear sliders."); } // Parse value to range and store. As xVal is checked @@ -412,7 +403,7 @@ $.fn.noUiSlider - WTFPL - refreshless.com/nouislider/ */ parsed.margin = fromPercentage(parsed.xVal, entry); if ( !isNumeric(entry) ){ - throwError("'margin' option must be numeric."); + throw new Error("noUiSlider: 'margin' option must be numeric."); } } @@ -430,7 +421,7 @@ $.fn.noUiSlider - WTFPL - refreshless.com/nouislider/ */ parsed.connect = [0,2,1,3][parsed.connect]; break; default: - throwError("'direction' option was not recognized."); + throw new Error("noUiSlider: 'direction' option was not recognized."); } } @@ -438,7 +429,7 @@ $.fn.noUiSlider - WTFPL - refreshless.com/nouislider/ */ // Make sure the input is a string. if ( typeof entry !== 'string' ) { - throwError("'behaviour' must be a string containing options."); + throw new Error("noUiSlider: 'behaviour' must be a string containing options."); } // Check if the string contains any keywords. @@ -467,24 +458,20 @@ $.fn.noUiSlider - WTFPL - refreshless.com/nouislider/ */ // Check if the provided option is an array. if ( !$.isArray(linkInstances) ) { - throwError("'serialization."+(!index ? 'lower' : 'upper')+"' must be an array."); + 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) ) { - throwError("'serialization."+(!index ? 'lower' : 'upper')+"' can only contain Link instances."); + 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'] ); - - // this.setScope( this.scope || sliders ); - // Run internal validator. - }); }); @@ -534,10 +521,10 @@ $.fn.noUiSlider - WTFPL - refreshless.com/nouislider/ */ // Set defaults where applicable. options = $.extend({ - 'connect': false - ,'direction': 'ltr' - ,'behaviour': 'tap' - ,'orientation': 'horizontal' + 'connect': false, + 'direction': 'ltr', + 'behaviour': 'tap', + 'orientation': 'horizontal' }, options); // Make sure the test for serialization runs. @@ -553,11 +540,12 @@ $.fn.noUiSlider - WTFPL - refreshless.com/nouislider/ */ $.each( tests, function( name, test ){ if ( options[name] === undefined ) { + if ( test.r ) { - throwError("'" + name + "' is required."); - } else { - return true; + throw new Error("noUiSlider: '" + name + "' is required."); } + + return true; } test.t( parsed, options[name], sliders ); @@ -595,7 +583,8 @@ $.fn.noUiSlider - WTFPL - refreshless.com/nouislider/ */ // If the Link requires creation of a new element, // create this element and return a new Link instance. if ( link.el ) { - link = new Link({ + + link = new $.Link({ 'target': $(link.el).clone().appendTo( handle ), 'method': link.method, 'format': link.formatting @@ -609,7 +598,7 @@ $.fn.noUiSlider - WTFPL - refreshless.com/nouislider/ */ // Loop all links for a handle. function addElements ( elements, handle, formatting ) { - var index, list = [], standard = new Link({}, true); + var index, list = [], standard = new $.Link({}, true); // Use the Link interface to provide unified // formatting for the .val() method. @@ -1062,7 +1051,8 @@ function closure ( target, options, originalOptions ){ // Methods // Set the slider value. - target.vSet = function ( ){ + /** @expose */ + target.vSet = function ( ) { var args = Array.prototype.slice.call( arguments, 0 ), callback, link, update, animate, @@ -1127,10 +1117,10 @@ function closure ( target, options, originalOptions ){ if (!index) { actual = this.actual; + return true; } this.write( - //fromStepping(options, actual), actual, $Handles[i%2].children(), $Target, @@ -1148,7 +1138,8 @@ function closure ( target, options, originalOptions ){ }; // Get the slider value. - target.vGet = function ( ){ + /** @expose */ + target.vGet = function ( ) { var i, retour = []; @@ -1170,7 +1161,8 @@ function closure ( target, options, originalOptions ){ }; // Destroy the slider and unbind all events. - target.destroy = function ( ){ + /** @expose */ + target.destroy = function ( ) { // Loop all linked serialization objects and unbind all // events in the noUiSlider namespace. @@ -1207,7 +1199,7 @@ function closure ( target, options, originalOptions ){ // Throw error if group is empty. if ( !this.length ){ - throwError("Can't initialize slider on empty selection."); + throw new Error("noUiSlider: Can't initialize slider on empty selection."); } // Test the options once, not for every slider. diff --git a/tests/run.html b/tests/run.html index 3278c6a0..cdef8aea 100644 --- a/tests/run.html +++ b/tests/run.html @@ -33,8 +33,16 @@ + - + + + +