Merge "Avoid usage of deprecated setTags() method, use addTags() instead"
[lhc/web/wiklou.git] / resources / src / mediawiki.Uri / Uri.js
index 4343ecc..a91e57a 100644 (file)
                 * @param {boolean} [options.strictMode=false] Trigger strict mode parsing of the url.
                 * @param {boolean} [options.overrideKeys=false] Whether to let duplicate query parameters
                 *  override each other (`true`) or automagically convert them to an array (`false`).
+                * @param {boolean} [options.arrayParams=false] Whether to parse array query parameters (e.g.
+                *  `&foo[0]=a&foo[1]=b` or `&foo[]=a&foo[]=b`) or leave them alone. Currently this does not
+                *  handle associative or multi-dimensional arrays, but that may be improved in the future.
+                *  Implies `overrideKeys: true` (query parameters without `[...]` are not parsed as arrays).
                 * @throws {Error} when the query string or fragment contains an unknown % sequence
                 */
                function Uri( uri, options ) {
                        options = typeof options === 'object' ? options : { strictMode: !!options };
                        options = $.extend( {
                                strictMode: false,
-                               overrideKeys: false
+                               overrideKeys: false,
+                               arrayParams: false
                        }, options );
 
+                       this.arrayParams = options.arrayParams;
+
                        if ( uri !== undefined && uri !== null && uri !== '' ) {
                                if ( typeof uri === 'string' ) {
                                        this.parse( uri, options );
                                // using replace to iterate over a string
                                if ( uri.query ) {
                                        uri.query.replace( /(?:^|&)([^&=]*)(?:(=)([^&]*))?/g, function ( match, k, eq, v ) {
+                                               var arrayKeyMatch, i;
                                                if ( k ) {
                                                        k = Uri.decode( k );
                                                        v = ( eq === '' || eq === undefined ) ? null : Uri.decode( v );
+                                                       arrayKeyMatch = k.match( /^([^[]+)\[(\d*)\]$/ );
+
+                                                       // If arrayParams and this parameter name contains an array index...
+                                                       if ( options.arrayParams && arrayKeyMatch ) {
+                                                               // Remove the index from parameter name
+                                                               k = arrayKeyMatch[ 1 ];
+
+                                                               // Turn the parameter value into an array (throw away anything else)
+                                                               if ( !Array.isArray( q[ k ] ) ) {
+                                                                       q[ k ] = [];
+                                                               }
+
+                                                               i = arrayKeyMatch[ 2 ];
+                                                               if ( i === '' ) {
+                                                                       // If no explicit index, append at the end
+                                                                       i = q[ k ].length;
+                                                               }
+
+                                                               q[ k ][ i ] = v;
 
                                                        // If overrideKeys, always (re)set top level value.
                                                        // If not overrideKeys but this key wasn't set before, then we set it as well.
-                                                       if ( options.overrideKeys || !hasOwn.call( q, k ) ) {
+                                                       // arrayParams implies overrideKeys (no array handling for non-array params).
+                                                       } else if ( options.arrayParams || options.overrideKeys || !hasOwn.call( q, k ) ) {
                                                                q[ k ] = v;
 
                                                        // Use arrays if overrideKeys is false and key was already seen before
                         * @return {string}
                         */
                        getQueryString: function () {
-                               var args = [];
+                               var args = [],
+                                       arrayParams = this.arrayParams;
                                // eslint-disable-next-line no-jquery/no-each-util
                                $.each( this.query, function ( key, val ) {
                                        var k = Uri.encode( key ),
-                                               vals = Array.isArray( val ) ? val : [ val ];
-                                       vals.forEach( function ( v ) {
+                                               isArrayParam = Array.isArray( val ),
+                                               vals = isArrayParam ? val : [ val ];
+                                       vals.forEach( function ( v, i ) {
+                                               var ki = k;
+                                               if ( arrayParams && isArrayParam ) {
+                                                       ki += Uri.encode( '[' + i + ']' );
+                                               }
                                                if ( v === null ) {
-                                                       args.push( k );
+                                                       args.push( ki );
                                                } else if ( k === 'title' ) {
-                                                       args.push( k + '=' + mw.util.wikiUrlencode( v ) );
+                                                       args.push( ki + '=' + mw.util.wikiUrlencode( v ) );
                                                } else {
-                                                       args.push( k + '=' + Uri.encode( v ) );
+                                                       args.push( ki + '=' + Uri.encode( v ) );
                                                }
                                        } );
                                } );