Merge "mw.jqueryMsg: Handle non-string parameters to functions that expect strings...
authorjenkins-bot <jenkins-bot@gerrit.wikimedia.org>
Wed, 19 Sep 2018 19:08:46 +0000 (19:08 +0000)
committerGerrit Code Review <gerrit@wikimedia.org>
Wed, 19 Sep 2018 19:08:46 +0000 (19:08 +0000)
1  2 
resources/src/mediawiki.jqueryMsg/mediawiki.jqueryMsg.js
tests/qunit/suites/resources/mediawiki/mediawiki.jqueryMsg.test.js

@@@ -6,7 -6,7 +6,7 @@@
  * @author neilk@wikimedia.org
  * @author mflaschen@wikimedia.org
  */
 -( function ( mw, $ ) {
 +( function () {
        /**
         * @class mw.jqueryMsg
         * @singleton
@@@ -82,7 -82,7 +82,7 @@@
                        if ( typeof children[ i ] !== 'object' ) {
                                children[ i ] = document.createTextNode( children[ i ] );
                        }
 -                      if ( children[ i ] instanceof jQuery && children[ i ].hasClass( 'mediaWiki_htmlEmitter' ) ) {
 +                      if ( children[ i ] instanceof $ && children[ i ].hasClass( 'mediaWiki_htmlEmitter' ) ) {
                                children[ i ] = children[ i ].contents();
                        }
                }
         * @return {string} Textual value of input
         */
        function textify( input ) {
 -              if ( input instanceof jQuery ) {
 +              if ( input instanceof $ ) {
                        input = input.text();
                }
                return String( input );
                 *
                 * @param {Array} nodes List of one element, integer, n >= 0
                 * @param {Array} replacements List of at least n strings
-                * @return {string} replacement
+                * @return {string|jQuery} replacement
                 */
                replace: function ( nodes, replacements ) {
                        var index = parseInt( nodes[ 0 ], 10 );
                 * Handles an (already-validated) HTML element.
                 *
                 * @param {Array} nodes Nodes to process when creating element
-                * @return {jQuery|Array} jQuery node for valid HTML or array for disallowed element
+                * @return {jQuery}
                 */
                htmlelement: function ( nodes ) {
                        var tagName, attributes, contents, $element;
                        var $el,
                                arg = nodes[ 0 ],
                                contents = nodes[ 1 ];
 -                      if ( arg instanceof jQuery && !arg.hasClass( 'mediaWiki_htmlEmitter' ) ) {
 +                      if ( arg instanceof $ && !arg.hasClass( 'mediaWiki_htmlEmitter' ) ) {
                                $el = arg;
                        } else {
                                $el = $( '<a>' );
                 * So convert it back with the current language's convertNumber.
                 *
                 * @param {Array} nodes List of nodes, [ {string|number}, {string}, {string} ... ]
-                * @return {string} selected pluralized form according to current language
+                * @return {string|jQuery} selected pluralized form according to current language
                 */
                plural: function ( nodes ) {
                        var forms, firstChild, firstChildText, explicitPluralFormNumber, formIndex, form, count,
                                explicitPluralForms = {};
  
-                       count = parseFloat( this.language.convertNumber( nodes[ 0 ], true ) );
+                       count = parseFloat( this.language.convertNumber( textify( nodes[ 0 ] ), true ) );
                        forms = nodes.slice( 1 );
                        for ( formIndex = 0; formIndex < forms.length; formIndex++ ) {
                                form = forms[ formIndex ];
  
 -                              if ( form instanceof jQuery && form.hasClass( 'mediaWiki_htmlEmitter' ) ) {
 +                              if ( form instanceof $ && form.hasClass( 'mediaWiki_htmlEmitter' ) ) {
                                        // This is a nested node, may be an explicit plural form like 5=[$2 linktext]
                                        firstChild = form.contents().get( 0 );
                                        if ( firstChild && firstChild.nodeType === Node.TEXT_NODE ) {
                 * - a gender string ('male', 'female' or 'unknown')
                 *
                 * @param {Array} nodes List of nodes, [ {string|mw.user}, {string}, {string}, {string} ]
-                * @return {string} Selected gender form according to current language
+                * @return {string|jQuery} Selected gender form according to current language
                 */
                gender: function ( nodes ) {
                        var gender,
                        if ( maybeUser && maybeUser.options instanceof mw.Map ) {
                                gender = maybeUser.options.get( 'gender' );
                        } else {
-                               gender = maybeUser;
+                               gender = textify( maybeUser );
                        }
  
                        return this.language.gender( gender, forms );
                 * Invoked by putting `{{grammar:form|word}}` in a message
                 *
                 * @param {Array} nodes List of nodes [{Grammar case eg: genitive}, {string word}]
-                * @return {string} selected grammatical form according to current language
+                * @return {string|jQuery} selected grammatical form according to current language
                 */
                grammar: function ( nodes ) {
                        var form = nodes[ 0 ],
                                word = nodes[ 1 ];
-                       return word && form && this.language.convertGrammar( word, form );
+                       // These could be jQuery objects (passed as message parameters),
+                       // in which case we can't transform them (like rawParams() in PHP).
+                       if ( typeof form === 'string' && typeof word === 'string' ) {
+                               return this.language.convertGrammar( word, form );
+                       }
+                       return word;
                },
  
                /**
                 * Tranform parsed structure into a int: (interface language) message include
                 * Invoked by putting `{{int:othermessage}}` into a message
                 *
+                * TODO Syntax in the included message is not parsed, this seems like a bug?
+                *
                 * @param {Array} nodes List of nodes
                 * @return {string} Other message
                 */
                'int': function ( nodes ) {
-                       var msg = nodes[ 0 ];
+                       var msg = textify( nodes[ 0 ] );
                        return mw.jqueryMsg.getMessageFunction()( msg.charAt( 0 ).toLowerCase() + msg.slice( 1 ) );
                },
  
                 * separator, according to the current language.
                 *
                 * @param {Array} nodes List of nodes
-                * @return {number|string} Formatted number
+                * @return {number|string|jQuery} Formatted number
                 */
                formatnum: function ( nodes ) {
                        var isInteger = !!nodes[ 1 ] && nodes[ 1 ] === 'R',
                                number = nodes[ 0 ];
  
-                       return this.language.convertNumber( number, isInteger );
+                       // These could be jQuery objects (passed as message parameters),
+                       // in which case we can't transform them (like rawParams() in PHP).
+                       if ( typeof number === 'string' || typeof number === 'number' ) {
+                               return this.language.convertNumber( number, isInteger );
+                       }
+                       return number;
                },
  
                /**
                };
        }() );
  
 -}( mediaWiki, jQuery ) );
 +}() );
@@@ -1,4 -1,4 +1,4 @@@
 -( function ( mw, $ ) {
 +( function () {
        /* eslint-disable camelcase */
        var formatText, formatParse, formatnumTests, specialCharactersPageName, expectedListUsers,
                expectedListUsersSitename, expectedLinkPagenamee, expectedEntrypoints,
        QUnit.test( 'Non-string parameters to various functions', function ( assert ) {
                var i, cases;
  
+               // For jquery-param-int
+               mw.messages.set( 'x', 'y' );
                // For jquery-param-grammar
                mw.language.setData( 'en', 'grammarTransformations', {
                        test: [
                        {
                                key: 'jquery-param-grammar',
                                msg: '{{GRAMMAR:test|$1}}',
-                               expected: '{{GRAMMAR:test|$1}}'
+                               expected: '<b>x</b>'
                        },
                        {
                                key: 'jquery-param-int',
                                msg: '{{int:$1}}',
-                               expected: '{{int:$1}}'
+                               expected: 'y'
                        },
                        {
                                key: 'jquery-param-ns',
                        {
                                key: 'jquery-param-formatnum',
                                msg: '{{formatnum:$1}}',
-                               expected: '[object Object]'
+                               expected: '<b>x</b>'
                        },
                        {
                                key: 'jquery-param-case',
                        'setParserDefaults is deep if requested'
                );
        } );
 -}( mediaWiki, jQuery ) );
 +}() );