mediawiki.util: Use correct encoding for fragment in getUrl
authorFomafix <fomafix@googlemail.com>
Mon, 21 Dec 2015 06:17:11 +0000 (06:17 +0000)
committerBartosz Dziewoński <matma.rex@gmail.com>
Mon, 21 Dec 2015 16:30:21 +0000 (17:30 +0100)
Introduce mw.util.escapeId with same encoding as Sanitizer::escapeId.

Add more tests to getUrl:
* empty title
* several characters for encoding test

Bug: T103553
Bug: T103661
Change-Id: I15d8c48b9ea4a144a0938353c5b265cb6b6a159b

resources/src/mediawiki/mediawiki.util.js
tests/qunit/suites/resources/mediawiki/mediawiki.util.test.js

index 7b45248..f9810f9 100644 (file)
                                .replace( /\)/g, '%29' ).replace( /\*/g, '%2A' ).replace( /~/g, '%7E' );
                },
 
+               /**
+                * Encode the string like Sanitizer::escapeId in PHP
+                *
+                * @param {string} str String to be encoded.
+                */
+               escapeId: function ( str ) {
+                       str = String( str );
+                       return util.rawurlencode( str.replace( / /g, '_' ) )
+                               .replace( /%3A/g, ':' )
+                               .replace( /%/g, '.' );
+               },
+
                /**
                 * Encode page titles for use in a URL
                 *
                        var titleFragmentStart,
                                url,
                                fragment = '',
-                               pageName = util.wikiUrlencode( typeof str === 'string' ? str : mw.config.get( 'wgPageName' ) );
+                               pageName = typeof str === 'string' ? str : mw.config.get( 'wgPageName' );
 
                        // Find any fragment should one exist
                        if ( typeof str === 'string' ) {
-                               titleFragmentStart = pageName.indexOf( '%23' );
+                               titleFragmentStart = pageName.indexOf( '#' );
                                if ( titleFragmentStart !== -1 ) {
-                                       fragment = pageName.slice( titleFragmentStart + 3 );
+                                       fragment = pageName.slice( titleFragmentStart + 1 );
                                        // Exclude the fragment from the page name
                                        pageName = pageName.slice( 0, titleFragmentStart );
                                }
                        }
 
-                       url = mw.config.get( 'wgArticlePath' ).replace( '$1', pageName );
+                       url = mw.config.get( 'wgArticlePath' ).replace( '$1', util.wikiUrlencode( pageName ) );
 
                        // Add query string if necessary
                        if ( params && !$.isEmptyObject( params ) ) {
                                url += ( url.indexOf( '?' ) !== -1 ? '&' : '?' ) + $.param( params );
                        }
 
-                       // Insert the already URL-encoded fragment should it exist, replacing % with .
+                       // Append the encoded fragment
                        if ( fragment.length > 0 ) {
-                               url += '#' + fragment.replace( /%/g, '.' );
+                               url += '#' + util.escapeId( fragment );
                        }
 
                        return url;
index 75dd8cd..0b98106 100644 (file)
                assert.equal( mw.util.rawurlencode( 'Test:A & B/Here' ), 'Test%3AA%20%26%20B%2FHere' );
        } );
 
+       QUnit.test( 'escapeId', 17, function ( assert ) {
+               mw.config.set( 'wgExperimentalHtmlIds', false );
+               $.each( {
+                       '+': '.2B',
+                       '&': '.26',
+                       '=': '.3D',
+                       ':': ':',
+                       ';': '.3B',
+                       '@': '.40',
+                       $: '.24',
+                       '-_.': '-_.',
+                       '!': '.21',
+                       '*': '.2A',
+                       '/': '.2F',
+                       '[]': '.5B.5D',
+                       '<>': '.3C.3E',
+                       '\'': '.27',
+                       '§': '.C2.A7',
+                       'Test:A & B/Here': 'Test:A_.26_B.2FHere',
+                       'A&B&amp;C&amp;amp;D&amp;amp;amp;E': 'A.26B.26amp.3BC.26amp.3Bamp.3BD.26amp.3Bamp.3Bamp.3BE'
+               }, function ( input, output ) {
+                       assert.equal( mw.util.escapeId( input ), output );
+               } );
+       } );
+
        QUnit.test( 'wikiUrlencode', 11, function ( assert ) {
                assert.equal( mw.util.wikiUrlencode( 'Test:A & B/Here' ), 'Test:A_%26_B/Here' );
                // See also wfUrlencodeTest.php#provideURLS
                } );
        } );
 
-       QUnit.test( 'getUrl', 8, function ( assert ) {
+       QUnit.test( 'getUrl', 12, function ( assert ) {
                // Not part of startUp module
                mw.config.set( 'wgArticlePath', '/wiki/$1' );
                mw.config.set( 'wgPageName', 'Foobar' );
                href = mw.util.getUrl( 'Foo:Sandbox#Fragment', { action: 'edit' } );
                assert.equal( href, '/wiki/Foo:Sandbox?action=edit#Fragment', 'advanced title with query string and fragment' );
 
+               href = mw.util.getUrl( 'Foo:Sandbox#', { action: 'edit' } );
+               assert.equal( href, '/wiki/Foo:Sandbox?action=edit', 'title with query string and empty fragment' );
+
+               href = mw.util.getUrl( '#Fragment' );
+               assert.equal( href, '/wiki/#Fragment', 'epmty title with fragment' );
+
+               href = mw.util.getUrl( '#Fragment', { action: 'edit' } );
+               assert.equal( href, '/wiki/?action=edit#Fragment', 'epmty title with query string and fragment' );
+
                href = mw.util.getUrl( 'Foo:Sandbox \xC4#Fragment \xC4', { action: 'edit' } );
                assert.equal( href, '/wiki/Foo:Sandbox_%C3%84?action=edit#Fragment_.C3.84', 'title with query string, fragment, and special characters' );
 
                href = mw.util.getUrl( 'Foo:%23#Fragment', { action: 'edit' } );
                assert.equal( href, '/wiki/Foo:%2523?action=edit#Fragment', 'title containing %23 (#), fragment, and a query string' );
+
+               href = mw.util.getUrl( '#+&=:;@$-_.!*/[]<>\'§', { action: 'edit' } );
+               assert.equal( href, '/wiki/?action=edit#.2B.26.3D:.3B.40.24-_..21.2A.2F.5B.5D.3C.3E.27.C2.A7', 'fragment with various characters' );
        } );
 
        QUnit.test( 'wikiScript', 4, function ( assert ) {