From d937c14f4acac044cbefe551296860fdea295622 Mon Sep 17 00:00:00 2001 From: James Addison Date: Wed, 6 May 2020 12:28:11 +0100 Subject: [PATCH 01/10] Standalone keys: Add illustrative deserialization test case --- unit/unit.js | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/unit/unit.js b/unit/unit.js index 52ca44f..bd7f91a 100644 --- a/unit/unit.js +++ b/unit/unit.js @@ -478,6 +478,15 @@ test( 'jQuery.deparam - pre-1.4-style params', function() { same( $.deparam( params_str, true ), params_obj_coerce, '$.deparam( String, true )' ); }); +test( 'jQuery.deparam - standalone keys', function() { + var params_str = 'a=1&a&b=2&c=3&c=undefined&c=&d&e[a]=4&e[b]&e[c]=', + params_obj = { a:['1',''], b:'2', c:['3','undefined',''], d:'', e:{a:'4',b:'',c:''} }, + params_obj_coerce = { a:[1,null], b:2, c:[3,undefined,''], d:null, e:{a:4,b:null,c:''} }; + + same( $.deparam( params_str, false ), params_obj, '$.deparam( String, false )' ); + same( $.deparam( params_str, true ), params_obj_coerce, '$.deparam( String, true )' ); +}); + test( 'jQuery.deparam.querystring', function() { expect( 12 ); From a7c286decab658eeece921b6dc83aa51e93ccec4 Mon Sep 17 00:00:00 2001 From: James Addison Date: Wed, 6 May 2020 13:46:39 +0100 Subject: [PATCH 02/10] Standalone keys: Expand test cases to include backwards-compatibility --- unit/unit.js | 19 ++++++++++++++----- 1 file changed, 14 insertions(+), 5 deletions(-) diff --git a/unit/unit.js b/unit/unit.js index bd7f91a..07d0bf5 100644 --- a/unit/unit.js +++ b/unit/unit.js @@ -479,12 +479,21 @@ test( 'jQuery.deparam - pre-1.4-style params', function() { }); test( 'jQuery.deparam - standalone keys', function() { - var params_str = 'a=1&a&b=2&c=3&c=undefined&c=&d&e[a]=4&e[b]&e[c]=', - params_obj = { a:['1',''], b:'2', c:['3','undefined',''], d:'', e:{a:'4',b:'',c:''} }, - params_obj_coerce = { a:[1,null], b:2, c:[3,undefined,''], d:null, e:{a:4,b:null,c:''} }; + var params_str = 'a=1&a&b=2&c=3&c=undefined&c=&d&e[a]=4&e[b]&e[c]='; - same( $.deparam( params_str, false ), params_obj, '$.deparam( String, false )' ); - same( $.deparam( params_str, true ), params_obj_coerce, '$.deparam( String, true )' ); + // Backwards-compatibility test cases + var bc_params_obj = { a:'', b:'2', c:['3','undefined',''], d:'', e:{a:'4',c:''}, 'e[b]': '' }, + bc_params_obj_coerce = { a:undefined, b:2, c:[3,undefined,''], d:undefined, e:{a:4,c:''}, 'e[b]': undefined }; + + // Intended-behaviour test cases + var params_obj = { a:['1',''], b:'2', c:['3','undefined',''], d:'', e:{a:'4',b:'',c:''} }, + params_obj_coerce = { a:[1,null], b:2, c:[3,undefined,''], d:null, e:{a:4,b:null,c:''} }; + + expect( 4 ); + same( $.deparam( params_str, false ), bc_params_obj, '$.deparam( String, false )' ); + same( $.deparam( params_str, true ), bc_params_obj_coerce, '$.deparam( String, true )' ); + same( $.deparam( params_str, false, true ), params_obj, '$.deparam( String, false, true )' ); + same( $.deparam( params_str, true, true ), params_obj_coerce, '$.deparam( String, true, true )' ); }); test( 'jQuery.deparam.querystring', function() { From 8f10005c92d4971e184cc54fe749948d4eab467b Mon Sep 17 00:00:00 2001 From: James Addison Date: Wed, 6 May 2020 14:34:35 +0100 Subject: [PATCH 03/10] Standalone keys: Add standaloneKeys parameter (with no-op implementation) --- jquery.ba-bbq.js | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/jquery.ba-bbq.js b/jquery.ba-bbq.js index 3a5995d..b3117ea 100644 --- a/jquery.ba-bbq.js +++ b/jquery.ba-bbq.js @@ -451,19 +451,22 @@ // // Usage: // - // > jQuery.deparam( params [, coerce ] ); + // > jQuery.deparam( params [, coerce, standaloneKeys ] ); // // Arguments: // // params - (String) A params string to be parsed. // coerce - (Boolean) If true, coerces any numbers or true, false, null, and // undefined to their actual value. Defaults to false if omitted. + // standaloneKeys - (Boolean) If true, keys without values are allowed in + // the input string, and will be returned as null. Defaults to false if + // omitted. // // Returns: // // (Object) An object representing the deserialized params string. - $.deparam = jq_deparam = function( params, coerce ) { + $.deparam = jq_deparam = function( params, coerce, standaloneKeys ) { var obj = {}, coerce_types = { 'true': !0, 'false': !1, 'null': null }; From 3eb3ced45139999145da708fe725af39b2601da4 Mon Sep 17 00:00:00 2001 From: James Addison Date: Wed, 6 May 2020 14:38:28 +0100 Subject: [PATCH 04/10] Standalone keys: Add coercion-to-null when standaloneKeys is enabled --- jquery.ba-bbq.js | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/jquery.ba-bbq.js b/jquery.ba-bbq.js index b3117ea..9d19866 100644 --- a/jquery.ba-bbq.js +++ b/jquery.ba-bbq.js @@ -550,7 +550,9 @@ } else if ( key ) { // No value was defined, so set something meaningful. obj[key] = coerce - ? undefined + ? standaloneKeys + ? null + : undefined : ''; } }); From 2fa07ed104f6b608300f25e6bdea9db2521522b9 Mon Sep 17 00:00:00 2001 From: James Addison Date: Wed, 6 May 2020 14:46:54 +0100 Subject: [PATCH 05/10] Standalone keys: Relocate logic block --- jquery.ba-bbq.js | 23 ++++++++++++----------- 1 file changed, 12 insertions(+), 11 deletions(-) diff --git a/jquery.ba-bbq.js b/jquery.ba-bbq.js index 9d19866..79b3a31 100644 --- a/jquery.ba-bbq.js +++ b/jquery.ba-bbq.js @@ -500,7 +500,16 @@ } // Are we dealing with a name=value pair, or just a name? - if ( param.length === 2 ) { + if ( param.length === 1 && key ) { + // No value was defined, so set something meaningful. + val = coerce + ? standaloneKeys + ? null + : undefined + : ''; + } + + else if ( param.length === 2 ) { val = decode( param[1] ); // Coerce values. @@ -510,6 +519,7 @@ : coerce_types[val] !== undefined ? coerce_types[val] // true, false, null : val; // string } + } if ( keys_last ) { // Complex key, build deep object structure based on a few rules: @@ -528,7 +538,7 @@ : val; } - } else { + } else if ( key ) { // Simple key, even simpler rules, since only scalars and shallow // arrays are allowed. @@ -546,15 +556,6 @@ obj[key] = val; } } - - } else if ( key ) { - // No value was defined, so set something meaningful. - obj[key] = coerce - ? standaloneKeys - ? null - : undefined - : ''; - } }); return obj; From b94ec7c32c9bc5af0264843bbb5e28c7399792fc Mon Sep 17 00:00:00 2001 From: James Addison Date: Wed, 6 May 2020 15:21:05 +0100 Subject: [PATCH 06/10] Standalone keys: Implement backwards-compatibility fix --- jquery.ba-bbq.js | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/jquery.ba-bbq.js b/jquery.ba-bbq.js index 79b3a31..7b1578b 100644 --- a/jquery.ba-bbq.js +++ b/jquery.ba-bbq.js @@ -507,6 +507,14 @@ ? null : undefined : ''; + + if (!standaloneKeys) { + // Backwards-compatibility: + // * Prior to the introduction of the standaloneKeys parameter, keys + // without corresponding values would result in an undefined entry + keys_last = false; + obj[key] = undefined; + } } else if ( param.length === 2 ) { From f8c0a8c47db28cf34225376b07764174936c434c Mon Sep 17 00:00:00 2001 From: James Addison Date: Wed, 6 May 2020 15:48:52 +0100 Subject: [PATCH 07/10] Standalone keys: indenting and whitespace cleanup --- jquery.ba-bbq.js | 70 ++++++++++++++++++++++++------------------------ 1 file changed, 35 insertions(+), 35 deletions(-) diff --git a/jquery.ba-bbq.js b/jquery.ba-bbq.js index 7b1578b..34eda8a 100644 --- a/jquery.ba-bbq.js +++ b/jquery.ba-bbq.js @@ -528,42 +528,42 @@ : val; // string } } - - if ( keys_last ) { - // Complex key, build deep object structure based on a few rules: - // * The 'cur' pointer starts at the object top-level. - // * [] = array push (n is set to array length), [n] = array if n is - // numeric, otherwise object. - // * If at the last keys part, set the value. - // * For each keys part, if the current level is undefined create an - // object or array based on the type of the next keys part. - // * Move the 'cur' pointer to the next level. - // * Rinse & repeat. - for ( ; i <= keys_last; i++ ) { - key = keys[i] === '' ? cur.length : keys[i]; - cur = cur[key] = i < keys_last - ? cur[key] || ( keys[i+1] && isNaN( keys[i+1] ) ? {} : [] ) - : val; - } - - } else if ( key ) { - // Simple key, even simpler rules, since only scalars and shallow - // arrays are allowed. - - if ( $.isArray( obj[key] ) ) { - // val is already an array, so push on the next value. - obj[key].push( val ); - - } else if ( obj[key] !== undefined ) { - // val isn't an array, but since a second value has been specified, - // convert val into an array. - obj[key] = [ obj[key], val ]; - - } else { - // val is a scalar. - obj[key] = val; - } + + if ( keys_last ) { + // Complex key, build deep object structure based on a few rules: + // * The 'cur' pointer starts at the object top-level. + // * [] = array push (n is set to array length), [n] = array if n is + // numeric, otherwise object. + // * If at the last keys part, set the value. + // * For each keys part, if the current level is undefined create an + // object or array based on the type of the next keys part. + // * Move the 'cur' pointer to the next level. + // * Rinse & repeat. + for ( ; i <= keys_last; i++ ) { + key = keys[i] === '' ? cur.length : keys[i]; + cur = cur[key] = i < keys_last + ? cur[key] || ( keys[i+1] && isNaN( keys[i+1] ) ? {} : [] ) + : val; } + + } else if ( key ) { + // Simple key, even simpler rules, since only scalars and shallow + // arrays are allowed. + + if ( $.isArray( obj[key] ) ) { + // val is already an array, so push on the next value. + obj[key].push( val ); + + } else if ( obj[key] !== undefined ) { + // val isn't an array, but since a second value has been specified, + // convert val into an array. + obj[key] = [ obj[key], val ]; + + } else { + // val is a scalar. + obj[key] = val; + } + } }); return obj; From 56423ed310ee1b322da72dff8a6295ae257084e4 Mon Sep 17 00:00:00 2001 From: James Addison Date: Wed, 6 May 2020 15:52:13 +0100 Subject: [PATCH 08/10] Standalone params: Restore original params.length conditional block ordering --- jquery.ba-bbq.js | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/jquery.ba-bbq.js b/jquery.ba-bbq.js index 34eda8a..73d5699 100644 --- a/jquery.ba-bbq.js +++ b/jquery.ba-bbq.js @@ -500,7 +500,19 @@ } // Are we dealing with a name=value pair, or just a name? - if ( param.length === 1 && key ) { + if ( param.length === 2 ) { + val = decode( param[1] ); + + // Coerce values. + if ( coerce ) { + val = val && !isNaN(val) ? +val // number + : val === 'undefined' ? undefined // undefined + : coerce_types[val] !== undefined ? coerce_types[val] // true, false, null + : val; // string + } + } + + else if ( param.length === 1 && key ) { // No value was defined, so set something meaningful. val = coerce ? standaloneKeys @@ -517,18 +529,6 @@ } } - else if ( param.length === 2 ) { - val = decode( param[1] ); - - // Coerce values. - if ( coerce ) { - val = val && !isNaN(val) ? +val // number - : val === 'undefined' ? undefined // undefined - : coerce_types[val] !== undefined ? coerce_types[val] // true, false, null - : val; // string - } - } - if ( keys_last ) { // Complex key, build deep object structure based on a few rules: // * The 'cur' pointer starts at the object top-level. From 025ccd65d3cda3a8ea1d30e314f96a515bfad336 Mon Sep 17 00:00:00 2001 From: James Addison Date: Wed, 6 May 2020 16:28:06 +0100 Subject: [PATCH 09/10] Standalone params: Nitpick: key-value spacing in tests --- unit/unit.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/unit/unit.js b/unit/unit.js index 07d0bf5..8136cb5 100644 --- a/unit/unit.js +++ b/unit/unit.js @@ -482,8 +482,8 @@ test( 'jQuery.deparam - standalone keys', function() { var params_str = 'a=1&a&b=2&c=3&c=undefined&c=&d&e[a]=4&e[b]&e[c]='; // Backwards-compatibility test cases - var bc_params_obj = { a:'', b:'2', c:['3','undefined',''], d:'', e:{a:'4',c:''}, 'e[b]': '' }, - bc_params_obj_coerce = { a:undefined, b:2, c:[3,undefined,''], d:undefined, e:{a:4,c:''}, 'e[b]': undefined }; + var bc_params_obj = { a:'', b:'2', c:['3','undefined',''], d:'', e:{a:'4',c:''}, 'e[b]':'' }, + bc_params_obj_coerce = { a:undefined, b:2, c:[3,undefined,''], d:undefined, e:{a:4,c:''}, 'e[b]':undefined }; // Intended-behaviour test cases var params_obj = { a:['1',''], b:'2', c:['3','undefined',''], d:'', e:{a:'4',b:'',c:''} }, From 950bfc1780af97e0753172c99184863d29dbc3e8 Mon Sep 17 00:00:00 2001 From: James Addison Date: Wed, 6 May 2020 18:29:11 +0100 Subject: [PATCH 10/10] Standalone keys: Run 'yui-compressor jquery.ba-bbq.js --preserve-semi -o jquery.ba-bbq.min.js' (v2.4.8) --- jquery.ba-bbq.min.js | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/jquery.ba-bbq.min.js b/jquery.ba-bbq.min.js index 80de36f..2c82fd6 100644 --- a/jquery.ba-bbq.min.js +++ b/jquery.ba-bbq.min.js @@ -1,4 +1,4 @@ -/* +/*! * jQuery BBQ: Back Button & Query Library - v1.3pre - 8/26/2010 * http://benalman.com/projects/jquery-bbq-plugin/ * @@ -6,8 +6,8 @@ * Dual licensed under the MIT and GPL licenses. * http://benalman.com/about/license/ */ -(function($,r){var h,n=Array.prototype.slice,t=decodeURIComponent,a=$.param,j,c,m,y,b=$.bbq=$.bbq||{},s,x,k,e=$.event.special,d="hashchange",B="querystring",F="fragment",z="elemUrlAttr",l="href",w="src",p=/^.*\?|#.*$/g,u,H,g,i,C,E={};function G(I){return typeof I==="string"}function D(J){var I=n.call(arguments,1);return function(){return J.apply(this,I.concat(n.call(arguments)))}}function o(I){return I.replace(H,"$2")}function q(I){return I.replace(/(?:^[^?#]*\?([^#]*).*$)?.*/,"$1")}function f(K,P,I,L,J){var R,O,N,Q,M;if(L!==h){N=I.match(K?H:/^([^#?]*)\??([^#]*)(#?.*)/);M=N[3]||"";if(J===2&&G(L)){O=L.replace(K?u:p,"")}else{Q=m(N[2]);L=G(L)?m[K?F:B](L):L;O=J===2?L:J===1?$.extend({},L,Q):$.extend({},Q,L);O=j(O);if(K){O=O.replace(g,t)}}R=N[1]+(K?C:O||!N[1]?"?":"")+O+M}else{R=P(I!==h?I:location.href)}return R}a[B]=D(f,0,q);a[F]=c=D(f,1,o);a.sorted=j=function(J,K){var I=[],L={};$.each(a(J,K).split("&"),function(P,M){var O=M.replace(/(?:%5B|=).*$/,""),N=L[O];if(!N){N=L[O]=[];I.push(O)}N.push(M)});return $.map(I.sort(),function(M){return L[M]}).join("&")};c.noEscape=function(J){J=J||"";var I=$.map(J.split(""),encodeURIComponent);g=new RegExp(I.join("|"),"g")};c.noEscape(",/");c.ajaxCrawlable=function(I){if(I!==h){if(I){u=/^.*(?:#!|#)/;H=/^([^#]*)(?:#!|#)?(.*)$/;C="#!"}else{u=/^.*#/;H=/^([^#]*)#?(.*)$/;C="#"}i=!!I}return i};c.ajaxCrawlable(0);$.deparam=m=function(L,I){var K={},J={"true":!0,"false":!1,"null":null};$.each(L.replace(/\+/g," ").split("&"),function(O,T){var N=T.split("="),S=t(N[0]),M,R=K,P=0,U=S.split("]["),Q=U.length-1;if(/\[/.test(U[0])&&/\]$/.test(U[Q])){U[Q]=U[Q].replace(/\]$/,"");U=U.shift().split("[").concat(U);Q=U.length-1}else{Q=0}if(N.length===2){M=t(N[1]);if(I){M=M&&!isNaN(M)?+M:M==="undefined"?h:J[M]!==h?J[M]:M}if(Q){for(;P<=Q;P++){S=U[P]===""?R.length:U[P];R=R[S]=P7);function a(j){j=j||location.href;return"#"+j.replace(/^[^#]*#?(.*)$/,"$1")}$.fn[c]=function(j){return j?this.bind(c,j):this.trigger(c)};$.fn[c].delay=50;g[c]=$.extend(g[c],{setup:function(){if(d){return false}$(f.start)},teardown:function(){if(d){return false}$(f.stop)}});f=(function(){var j={},p,m=a(),k=function(q){return q},l=k,o=k;j.start=function(){p||n()};j.stop=function(){p&&clearTimeout(p);p=b};function n(){var r=a(),q=o(m);if(r!==m){l(m=r,q);$(e).trigger(c)}else{if(q!==m){location.href=location.href.replace(/#.*/,"")+q}}p=setTimeout(n,$.fn[c].delay)}$.browser.msie&&!d&&(function(){var q,r;j.start=function(){if(!q){r=$.fn[c].src;r=r&&r+a();q=$('