r102616 MediaWiki - Code Review archive

Repository:MediaWiki
Revision:r102615‎ | r102616 | r102617 >
Date:02:08, 10 November 2011
Author:krinkle
Status:ok
Tags:
Comment:
[mediawiki.Uri] Add overrideKeys option
* The behavior of turning foo=bar&foo=quux&lorem=ipsum into "{ lorem: 'ipsum', foo: ['bar', 'quux'] }", has annoyed me several times. As it is in contrary with the way PHP works (PHP only makes numeral arrays if the key ends in '[]'). Adding in an option to make mw.Uri behave like that.
* We may wanna make that the default at some point, leaving default behavior unchanged for now.
* Converted 'strictMode' into 'options', kept backwards compatibility
* Fixed documentation comment for example (q1=0 -> "{ q1: '0'")
* Updated unit tests to account for this option.
Modified paths:
  • /trunk/phase3/resources/mediawiki/mediawiki.Uri.js (modified) (history)
  • /trunk/phase3/tests/jasmine/spec/mediawiki.Uri.spec.js (modified) (history)

Diff [purge]

Index: trunk/phase3/tests/jasmine/spec/mediawiki.Uri.spec.js
@@ -92,9 +92,23 @@
9393 expect( uri.getQueryString() ).toEqual( 'q=uri' );
9494 } );
9595
96 - describe( "should handle multiple value query args", function() {
97 - var uri = new mw.Uri( 'http://www.sample.com/dir/?m=foo&m=bar&n=1' );
 96+ describe( "should handle multiple value query args (overrideKeys on)", function() {
 97+ var uri = new mw.Uri( 'http://www.sample.com/dir/?m=foo&m=bar&n=1', { overrideKeys: true } );
9898 it ( "should parse with multiple values", function() {
 99+ expect( uri.query.m ).toEqual( 'bar' );
 100+ expect( uri.query.n ).toEqual( '1' );
 101+ } );
 102+ it ( "should accept multiple values", function() {
 103+ uri.query.n = [ "x", "y", "z" ];
 104+ expect( uri.toString() ).toContain( 'm=bar' );
 105+ expect( uri.toString() ).toContain( 'n=x&n=y&n=z' );
 106+ expect( uri.toString().length ).toEqual( 'http://www.sample.com/dir/?m=bar&n=x&n=y&n=z'.length );
 107+ } );
 108+ } );
 109+
 110+ describe( "should handle multiple value query args (overrideKeys off)", function() {
 111+ var uri = new mw.Uri( 'http://www.sample.com/dir/?m=foo&m=bar&n=1', { overrideKeys: false } );
 112+ it ( "should parse with multiple values", function() {
99113 expect( uri.query.m.length ).toEqual( 2 );
100114 expect( uri.query.m[0] ).toEqual( 'foo' );
101115 expect( uri.query.m[1] ).toEqual( 'bar' );
Index: trunk/phase3/resources/mediawiki/mediawiki.Uri.js
@@ -89,7 +89,7 @@
9090 'host', // www.test.com
9191 'port', // 81
9292 'path', // /dir/dir.2/index.htm
93 - 'query', // q1=0&&test1&test2=value (will become { q1: 0, test1: '', test2: 'value' } )
 93+ 'query', // q1=0&&test1&test2=value (will become { q1: '0', test1: '', test2: 'value' } )
9494 'fragment' // top
9595 ];
9696
@@ -103,14 +103,23 @@
104104 /**
105105 * Constructs URI object. Throws error if arguments are illegal/impossible, or otherwise don't parse.
106106 * @constructor
107 - * @param {!Object|String} URI string, or an Object with appropriate properties (especially another URI object to clone). Object must have non-blank 'protocol', 'host', and 'path' properties.
108 - * @param {Boolean} strict mode (when parsing a string)
 107+ * @param {Object|String} URI string, or an Object with appropriate properties (especially another URI object to clone).
 108+ * Object must have non-blank 'protocol', 'host', and 'path' properties.
 109+ * @param {Object|Boolean} Object with options, or (backwards compatibility) a boolean for strictMode
 110+ * - strictMode {Boolean} Trigger strict mode parsing of the url. Default: false
 111+ * - overrideKeys {Boolean} Wether to let duplicate query parameters override eachother (true) or automagically
 112+ * convert to an array (false, default).
109113 */
110 - function Uri( uri, strictMode ) {
111 - strictMode = !!strictMode;
 114+ function Uri( uri, options ) {
 115+ options = typeof options === 'object' ? options : { strictMode: !!options };
 116+ options = $.extend( {
 117+ strictMode: false,
 118+ overrideKeys: false
 119+ }, options );
 120+
112121 if ( uri !== undefined && uri !== null || uri !== '' ) {
113122 if ( typeof uri === 'string' ) {
114 - this._parse( uri, strictMode );
 123+ this._parse( uri, options );
115124 } else if ( typeof uri === 'object' ) {
116125 var _this = this;
117126 $.each( properties, function( i, property ) {
@@ -159,11 +168,11 @@
160169 /**
161170 * Parse a string and set our properties accordingly.
162171 * @param {String} URI
163 - * @param {Boolean} strictness
 172+ * @param {Object} options
164173 * @return {Boolean} success
165174 */
166 - _parse: function( str, strictMode ) {
167 - var matches = parser[ strictMode ? 'strict' : 'loose' ].exec( str );
 175+ _parse: function( str, options ) {
 176+ var matches = parser[ options.strictMode ? 'strict' : 'loose' ].exec( str );
168177 var uri = this;
169178 $.each( properties, function( i, property ) {
170179 uri[ property ] = matches[ i+1 ];
@@ -179,13 +188,22 @@
180189 if ( $1 ) {
181190 var k = Uri.decode( $1 );
182191 var v = ( $2 === '' || $2 === undefined ) ? null : Uri.decode( $3 );
183 - if ( typeof q[ k ] === 'string' ) {
184 - q[ k ] = [ q[ k ] ];
185 - }
186 - if ( typeof q[ k ] === 'object' ) {
187 - q[ k ].push( v );
 192+
 193+ // If overrideKeys, always (re)set top level value.
 194+ // If not overrideKeys but this key wasn't set before, then we set it as well.
 195+ if ( options.overrideKeys || q[ k ] === undefined ) {
 196+ q[ k ] = v;
 197+
 198+ // Use arrays if overrideKeys is false and key was already seen before
188199 } else {
189 - q[ k ] = v;
 200+ // Once before, still a string, turn into an array
 201+ if ( typeof q[ k ] === 'string' ) {
 202+ q[ k ] = [ q[ k ] ];
 203+ }
 204+ // Add to the array
 205+ if ( $.isArray( q[ k ] ) ) {
 206+ q[ k ].push( v );
 207+ }
190208 }
191209 }
192210 } );

Status & tagging log