diff options
Diffstat (limited to 'resources/src/mediawiki/mediawiki.jqueryMsg.js')
-rw-r--r-- | resources/src/mediawiki/mediawiki.jqueryMsg.js | 363 |
1 files changed, 173 insertions, 190 deletions
diff --git a/resources/src/mediawiki/mediawiki.jqueryMsg.js b/resources/src/mediawiki/mediawiki.jqueryMsg.js index 79939f64..d179c825 100644 --- a/resources/src/mediawiki/mediawiki.jqueryMsg.js +++ b/resources/src/mediawiki/mediawiki.jqueryMsg.js @@ -15,14 +15,12 @@ slice = Array.prototype.slice, parserDefaults = { magic: { - 'SITENAME': mw.config.get( 'wgSiteName' ) + SITENAME: mw.config.get( 'wgSiteName' ) }, - // This is a whitelist based on, but simpler than, Sanitizer.php. + // Whitelist for allowed HTML elements in wikitext. // Self-closing tags are not currently supported. - allowedHtmlElements: [ - 'b', - 'i' - ], + // Can be populated via setPrivateData(). + allowedHtmlElements: [], // Key tag name, value allowed attributes for that tag. // See Sanitizer::setupAttributeWhitelist allowedHtmlCommonAttributes: [ @@ -62,6 +60,9 @@ * Wrapper around jQuery append that converts all non-objects to TextNode so append will not * convert what it detects as an htmlString to an element. * + * If our own htmlEmitter jQuery object is given, its children will be unwrapped and appended to + * new parent. + * * Object elements of children (jQuery, HTMLElement, TextNode, etc.) will be left as is. * * @private @@ -73,12 +74,15 @@ var i, len; if ( !$.isArray( children ) ) { - children = [children]; + children = [ children ]; } for ( i = 0, len = children.length; i < len; i++ ) { - if ( typeof children[i] !== 'object' ) { - children[i] = document.createTextNode( children[i] ); + if ( typeof children[ i ] !== 'object' ) { + children[ i ] = document.createTextNode( children[ i ] ); + } + if ( children[ i ] instanceof jQuery && children[ i ].hasClass( 'mediaWiki_htmlEmitter' ) ) { + children[ i ] = children[ i ].contents(); } } @@ -102,11 +106,26 @@ } /** + * Turn input into a string. + * + * @private + * @param {string|jQuery} input + * @return {string} Textual value of input + */ + function textify( input ) { + if ( input instanceof jQuery ) { + input = input.text(); + } + return String( input ); + } + + /** * Given parser options, return a function that parses a key and replacements, returning jQuery object * * Try to parse a key and optional replacements, returning a jQuery object that may be a tree of jQuery nodes. * If there was an error parsing, return the key and the error message (wrapped in jQuery). This should put the error right into * the interface, without causing the page to halt script execution, and it hopefully should be clearer how to fix it. + * * @private * @param {Object} options Parser options * @return {Function} @@ -118,8 +137,8 @@ return function ( args ) { var fallback, - key = args[0], - argsArray = $.isArray( args[1] ) ? args[1] : slice.call( args, 1 ); + key = args[ 0 ], + argsArray = $.isArray( args[ 1 ] ) ? args[ 1 ] : slice.call( args, 1 ); try { return parser.parse( key, argsArray ); } catch ( e ) { @@ -133,6 +152,22 @@ mw.jqueryMsg = {}; /** + * Initialize parser defaults. + * + * ResourceLoaderJqueryMsgModule calls this to provide default values from + * Sanitizer.php for allowed HTML elements. To override this data for individual + * parsers, pass the relevant options to mw.jqueryMsg.parser. + * + * @private + * @param {Object} data + */ + mw.jqueryMsg.setParserDefaults = function ( data ) { + if ( data.allowedHtmlElements ) { + parserDefaults.allowedHtmlElements = data.allowedHtmlElements; + } + }; + + /** * Returns a function suitable for use as a global, to construct strings from the message key (and optional replacements). * e.g. * @@ -154,8 +189,7 @@ * @return {string} return.return Rendered HTML. */ mw.jqueryMsg.getMessageFunction = function ( options ) { - var failableParserFn = getFailableParserFn( options ), - format; + var failableParserFn, format; if ( options && options.format !== undefined ) { format = options.format; @@ -164,6 +198,9 @@ } return function () { + if ( !failableParserFn ) { + failableParserFn = getFailableParserFn( options ); + } var failableResult = failableParserFn( arguments ); if ( format === 'text' || format === 'escaped' ) { return failableResult.text(); @@ -196,15 +233,14 @@ * @return {jQuery} return.return */ mw.jqueryMsg.getPlugin = function ( options ) { - var failableParserFn = getFailableParserFn( options ); + var failableParserFn; return function () { + if ( !failableParserFn ) { + failableParserFn = getFailableParserFn( options ); + } var $target = this.empty(); - // TODO: Simply appendWithoutParsing( $target, failableParserFn( arguments ).contents() ) - // or Simply appendWithoutParsing( $target, failableParserFn( arguments ) ) - $.each( failableParserFn( arguments ).contents(), function ( i, node ) { - appendWithoutParsing( $target, node ); - } ); + appendWithoutParsing( $target, failableParserFn( arguments ) ); return $target; }; }; @@ -226,32 +262,10 @@ mw.jqueryMsg.parser.prototype = { /** - * Cache mapping MediaWiki message keys and the value onlyCurlyBraceTransform, to the AST of the message. - * - * In most cases, the message is a string so this is identical. - * (This is why we would like to move this functionality server-side). - * - * The two parts of the key are separated by colon. For example: - * - * "message-key:true": ast - * - * if they key is "message-key" and onlyCurlyBraceTransform is true. - * - * This cache is shared by all instances of mw.jqueryMsg.parser. - * - * NOTE: We promise, it's static - when you create this empty object - * in the prototype, each new instance of the class gets a reference - * to the same object. - * - * @static - * @property {Object} - */ - astCache: {}, - - /** * Where the magic happens. * Parses a message from the key, and swaps in replacements as necessary, wraps in jQuery * If an error is thrown, returns original key, and logs the error + * * @param {string} key Message key. * @param {Array} replacements Variable replacements for $1, $2... $n * @return {jQuery} @@ -263,21 +277,16 @@ /** * Fetch the message string associated with a key, return parsed structure. Memoized. * Note that we pass '[' + key + ']' back for a missing message here. + * * @param {string} key * @return {string|Array} string of '[key]' if message missing, simple string if possible, array of arrays if needs parsing */ getAst: function ( key ) { - var wikiText, - cacheKey = [key, this.settings.onlyCurlyBraceTransform].join( ':' ); - - if ( this.astCache[ cacheKey ] === undefined ) { - wikiText = this.settings.messages.get( key ); - if ( typeof wikiText !== 'string' ) { - wikiText = '\\[' + key + '\\]'; - } - this.astCache[ cacheKey ] = this.wikiTextToAst( wikiText ); + var wikiText = this.settings.messages.get( key ); + if ( typeof wikiText !== 'string' ) { + wikiText = '\\[' + key + '\\]'; } - return this.astCache[ cacheKey ]; + return this.wikiTextToAst( wikiText ); }, /** @@ -297,7 +306,7 @@ escapedOrLiteralWithoutSpace, escapedOrLiteralWithoutBar, escapedOrRegularLiteral, whitespace, dollar, digits, htmlDoubleQuoteAttributeValue, htmlSingleQuoteAttributeValue, htmlAttributeEquals, openHtmlStartTag, optionalForwardSlash, openHtmlEndTag, closeHtmlTag, - openExtlink, closeExtlink, wikilinkPage, wikilinkContents, openWikilink, closeWikilink, templateName, pipe, colon, + openExtlink, closeExtlink, wikilinkContents, openWikilink, closeWikilink, templateName, pipe, colon, templateContents, openTemplate, closeTemplate, nonWhitespaceExpression, paramExpression, expression, curlyBraceTransformExpression, result, settings = this.settings, @@ -313,6 +322,7 @@ /** * Try parsers until one works, if none work return null + * * @private * @param {Function[]} ps * @return {string|null} @@ -321,7 +331,7 @@ return function () { var i, result; for ( i = 0; i < ps.length; i++ ) { - result = ps[i](); + result = ps[ i ](); if ( result !== null ) { return result; } @@ -333,6 +343,7 @@ /** * Try several ps in a row, all must succeed or return null. * This is the only eager one. + * * @private * @param {Function[]} ps * @return {string|null} @@ -342,7 +353,7 @@ originalPos = pos, result = []; for ( i = 0; i < ps.length; i++ ) { - res = ps[i](); + res = ps[ i ](); if ( res === null ) { pos = originalPos; return null; @@ -355,6 +366,7 @@ /** * Run the same parser over and over until it fails. * Must succeed a minimum of n times or return null. + * * @private * @param {number} n * @param {Function} p @@ -397,6 +409,7 @@ /** * Just make parsers out of simpler JS builtin types + * * @private * @param {string} s * @return {Function} @@ -429,8 +442,8 @@ if ( matches === null ) { return null; } - pos += matches[0].length; - return matches[0]; + pos += matches[ 0 ].length; + return matches[ 0 ]; }; } @@ -470,7 +483,7 @@ backslash, anyCharacter ] ); - return result === null ? null : result[1]; + return result === null ? null : result[ 1 ]; } escapedOrLiteralWithoutSpace = choice( [ escapedLiteral, @@ -496,13 +509,6 @@ return result === null ? null : result.join( '' ); } - // Used for wikilink page names. Like literalWithoutBar, but - // without allowing escapes. - function unescapedLiteralWithoutBar() { - var result = nOrMore( 1, regularLiteralWithoutBar )(); - return result === null ? null : result.join( '' ); - } - function literal() { var result = nOrMore( 1, escapedOrRegularLiteral )(); return result === null ? null : result.join( '' ); @@ -529,48 +535,37 @@ if ( result === null ) { return null; } - return [ 'REPLACE', parseInt( result[1], 10 ) - 1 ]; + return [ 'REPLACE', parseInt( result[ 1 ], 10 ) - 1 ]; } openExtlink = makeStringParser( '[' ); closeExtlink = makeStringParser( ']' ); // this extlink MUST have inner contents, e.g. [foo] not allowed; [foo bar] [foo <i>bar</i>], etc. are allowed function extlink() { - var result, parsedResult; + var result, parsedResult, target; result = null; parsedResult = sequence( [ openExtlink, - nonWhitespaceExpression, + nOrMore( 1, nonWhitespaceExpression ), whitespace, nOrMore( 1, expression ), closeExtlink ] ); if ( parsedResult !== null ) { - result = [ 'EXTLINK', parsedResult[1] ]; - // TODO (mattflaschen, 2013-03-22): Clean this up if possible. - // It's avoiding CONCAT for single nodes, so they at least doesn't get the htmlEmitter span. - if ( parsedResult[3].length === 1 ) { - result.push( parsedResult[3][0] ); - } else { - result.push( ['CONCAT'].concat( parsedResult[3] ) ); - } + // When the entire link target is a single parameter, we can't use CONCAT, as we allow + // passing fancy parameters (like a whole jQuery object or a function) to use for the + // link. Check only if it's a single match, since we can either do CONCAT or not for + // singles with the same effect. + target = parsedResult[ 1 ].length === 1 ? + parsedResult[ 1 ][ 0 ] : + [ 'CONCAT' ].concat( parsedResult[ 1 ] ); + result = [ + 'EXTLINK', + target, + [ 'CONCAT' ].concat( parsedResult[ 3 ] ) + ]; } return result; } - // this is the same as the above extlink, except that the url is being passed on as a parameter - function extLinkParam() { - var result = sequence( [ - openExtlink, - dollar, - digits, - whitespace, - expression, - closeExtlink - ] ); - if ( result === null ) { - return null; - } - return [ 'EXTLINKPARAM', parseInt( result[2], 10 ) - 1, result[4] ]; - } openWikilink = makeStringParser( '[[' ); closeWikilink = makeStringParser( ']]' ); pipe = makeStringParser( '|' ); @@ -581,26 +576,33 @@ templateContents, closeTemplate ] ); - return result === null ? null : result[1]; + return result === null ? null : result[ 1 ]; } - wikilinkPage = choice( [ - unescapedLiteralWithoutBar, - template - ] ); - function pipedWikilink() { var result = sequence( [ - wikilinkPage, + nOrMore( 1, paramExpression ), pipe, - expression + nOrMore( 1, expression ) + ] ); + return result === null ? null : [ + [ 'CONCAT' ].concat( result[ 0 ] ), + [ 'CONCAT' ].concat( result[ 2 ] ) + ]; + } + + function unpipedWikilink() { + var result = sequence( [ + nOrMore( 1, paramExpression ) ] ); - return result === null ? null : [ result[0], result[2] ]; + return result === null ? null : [ + [ 'CONCAT' ].concat( result[ 0 ] ) + ]; } wikilinkContents = choice( [ pipedWikilink, - wikilinkPage // unpiped link + unpipedWikilink ] ); function wikilink() { @@ -613,7 +615,7 @@ closeWikilink ] ); if ( parsedResult !== null ) { - parsedLinkContents = parsedResult[1]; + parsedLinkContents = parsedResult[ 1 ]; result = [ 'WIKILINK' ].concat( parsedLinkContents ); } return result; @@ -626,7 +628,7 @@ htmlDoubleQuoteAttributeValue, doubleQuote ] ); - return parsedResult === null ? null : parsedResult[1]; + return parsedResult === null ? null : parsedResult[ 1 ]; } function singleQuotedHtmlAttributeValue() { @@ -635,7 +637,7 @@ htmlSingleQuoteAttributeValue, singleQuote ] ); - return parsedResult === null ? null : parsedResult[1]; + return parsedResult === null ? null : parsedResult[ 1 ]; } function htmlAttribute() { @@ -648,7 +650,7 @@ singleQuotedHtmlAttributeValue ] ) ] ); - return parsedResult === null ? null : [parsedResult[1], parsedResult[3]]; + return parsedResult === null ? null : [ parsedResult[ 1 ], parsedResult[ 3 ] ]; } /** @@ -670,9 +672,9 @@ } for ( i = 0, len = attributes.length; i < len; i += 2 ) { - attributeName = attributes[i]; + attributeName = attributes[ i ]; if ( $.inArray( attributeName, settings.allowedHtmlCommonAttributes ) === -1 && - $.inArray( attributeName, settings.allowedHtmlAttributesByElement[startTagName] || [] ) === -1 ) { + $.inArray( attributeName, settings.allowedHtmlAttributesByElement[ startTagName ] || [] ) === -1 ) { return false; } } @@ -683,7 +685,7 @@ function htmlAttributes() { var parsedResult = nOrMore( 0, htmlAttribute )(); // Un-nest attributes array due to structure of jQueryMsg operations (see emit). - return concat.apply( ['HTMLATTRIBUTES'], parsedResult ); + return concat.apply( [ 'HTMLATTRIBUTES' ], parsedResult ); } // Subset of allowed HTML markup. @@ -714,7 +716,7 @@ } endOpenTagPos = pos; - startTagName = parsedOpenTagResult[1]; + startTagName = parsedOpenTagResult[ 1 ]; parsedHtmlContents = nOrMore( 0, expression )(); @@ -732,8 +734,8 @@ } endCloseTagPos = pos; - endTagName = parsedCloseTagResult[1]; - wrappedAttributes = parsedOpenTagResult[2]; + endTagName = parsedCloseTagResult[ 1 ]; + wrappedAttributes = parsedOpenTagResult[ 2 ]; attributes = wrappedAttributes.slice( 1 ); if ( isAllowedHtml( startTagName, endTagName, attributes ) ) { result = [ 'HTMLELEMENT', startTagName, wrappedAttributes ] @@ -773,9 +775,9 @@ if ( result === null ) { return null; } - expr = result[1]; + expr = result[ 1 ]; // use a CONCAT operator if there are multiple nodes, otherwise return the first node, raw. - return expr.length > 1 ? [ 'CONCAT' ].concat( expr ) : expr[0]; + return expr.length > 1 ? [ 'CONCAT' ].concat( expr ) : expr[ 0 ]; } function templateWithReplacement() { @@ -784,7 +786,7 @@ colon, replacement ] ); - return result === null ? null : [ result[0], result[2] ]; + return result === null ? null : [ result[ 0 ], result[ 2 ] ]; } function templateWithOutReplacement() { var result = sequence( [ @@ -792,14 +794,14 @@ colon, paramExpression ] ); - return result === null ? null : [ result[0], result[2] ]; + return result === null ? null : [ result[ 0 ], result[ 2 ] ]; } function templateWithOutFirstParameter() { var result = sequence( [ templateName, colon ] ); - return result === null ? null : [ result[0], '' ]; + return result === null ? null : [ result[ 0 ], '' ]; } colon = makeStringParser( ':' ); templateContents = choice( [ @@ -810,7 +812,7 @@ choice( [ templateWithReplacement, templateWithOutReplacement, templateWithOutFirstParameter ] ), nOrMore( 0, templateParam ) ] ); - return res === null ? null : res[0].concat( res[1] ); + return res === null ? null : res[ 0 ].concat( res[ 1 ] ); }, function () { var res = sequence( [ @@ -820,7 +822,7 @@ if ( res === null ) { return null; } - return [ res[0] ].concat( res[1] ); + return [ res[ 0 ] ].concat( res[ 1 ] ); } ] ); openTemplate = makeStringParser( '{{' ); @@ -828,7 +830,6 @@ nonWhitespaceExpression = choice( [ template, wikilink, - extLinkParam, extlink, replacement, literalWithoutSpace @@ -836,7 +837,6 @@ paramExpression = choice( [ template, wikilink, - extLinkParam, extlink, replacement, literalWithoutBar @@ -845,7 +845,6 @@ expression = choice( [ template, wikilink, - extLinkParam, extlink, replacement, html, @@ -876,7 +875,6 @@ // I am deferring the work of turning it into prototypes & objects. It's quite fast enough // finally let's do some actual work... - // If you add another possible rootExpression, you must update the astCache key scheme. result = start( this.settings.onlyCurlyBraceTransform ? curlyBraceTransformExpression : expression ); /* @@ -907,6 +905,7 @@ /** * (We put this method definition here, and not in prototype, to make sure it's not overwritten by any magic.) * Walk entire node structure, applying replacements and template functions when appropriate + * * @param {Mixed} node Abstract syntax tree (top node or subnode) * @param {Array} replacements for $1, $2, ... $n * @return {Mixed} single-string node or array of nodes suitable for jQuery appending @@ -925,8 +924,8 @@ subnodes = $.map( node.slice( 1 ), function ( n ) { return jmsg.emit( n, replacements ); } ); - operation = node[0].toLowerCase(); - if ( typeof jmsg[operation] === 'function' ) { + operation = node[ 0 ].toLowerCase(); + if ( typeof jmsg[ operation ] === 'function' ) { ret = jmsg[ operation ]( subnodes, replacements ); } else { throw new Error( 'Unknown operation "' + operation + '"' ); @@ -956,21 +955,16 @@ * Parsing has been applied depth-first we can assume that all nodes here are single nodes * Must return a single node to parents -- a jQuery with synthetic span * However, unwrap any other synthetic spans in our children and pass them upwards + * * @param {Mixed[]} nodes Some single nodes, some arrays of nodes * @return {jQuery} */ concat: function ( nodes ) { var $span = $( '<span>' ).addClass( 'mediaWiki_htmlEmitter' ); $.each( nodes, function ( i, node ) { - if ( node instanceof jQuery && node.hasClass( 'mediaWiki_htmlEmitter' ) ) { - $.each( node.contents(), function ( j, childNode ) { - appendWithoutParsing( $span, childNode ); - } ); - } else { - // Let jQuery append nodes, arrays of nodes and jQuery objects - // other things (strings, numbers, ..) are appended as text nodes (not as HTML strings) - appendWithoutParsing( $span, node ); - } + // Let jQuery append nodes, arrays of nodes and jQuery objects + // other things (strings, numbers, ..) are appended as text nodes (not as HTML strings) + appendWithoutParsing( $span, node ); } ); return $span; }, @@ -988,10 +982,10 @@ * @return {String} replacement */ replace: function ( nodes, replacements ) { - var index = parseInt( nodes[0], 10 ); + var index = parseInt( nodes[ 0 ], 10 ); if ( index < replacements.length ) { - return replacements[index]; + return replacements[ index ]; } else { // index not found, fallback to displaying variable return '$' + ( index + 1 ); @@ -1010,12 +1004,17 @@ * from the server, since the replacement is done at save time. * It may, though, if the wikitext appears in extension-controlled content. * - * @param nodes + * @param {String[]} nodes */ wikilink: function ( nodes ) { - var page, anchor, url; + var page, anchor, url, $el; - page = nodes[0]; + page = textify( nodes[ 0 ] ); + // Strip leading ':', which is used to suppress special behavior in wikitext links, + // e.g. [[:Category:Foo]] or [[:File:Foo.jpg]] + if ( page.charAt( 0 ) === ':' ) { + page = page.slice( 1 ); + } url = mw.util.getUrl( page ); if ( nodes.length === 1 ) { @@ -1023,13 +1022,14 @@ anchor = page; } else { // [[Some Page|anchor text]] or [[Namespace:Some Page|anchor]] - anchor = nodes[1]; + anchor = nodes[ 1 ]; } - return $( '<a>' ).attr( { + $el = $( '<a>' ).attr( { title: page, href: url - } ).text( anchor ); + } ); + return appendWithoutParsing( $el, anchor ); }, /** @@ -1042,7 +1042,7 @@ htmlattributes: function ( nodes ) { var i, len, mapping = {}; for ( i = 0, len = nodes.length; i < len; i += 2 ) { - mapping[nodes[i]] = decodePrimaryHtmlEntities( nodes[i + 1] ); + mapping[ nodes[ i ] ] = decodePrimaryHtmlEntities( nodes[ i + 1 ] ); } return mapping; }, @@ -1064,11 +1064,12 @@ }, /** - * Transform parsed structure into external link - * If the href is a jQuery object, treat it as "enclosing" the link text. + * Transform parsed structure into external link. * - * - ... function, treat it as the click handler. - * - ... string, treat it as a URI. + * The "href" can be: + * - a jQuery object, treat it as "enclosing" the link text. + * - a function, treat it as the click handler. + * - a string, or our htmlEmitter jQuery object, treat it as a URI after stringifying. * * TODO: throw an error if nodes.length > 2 ? * @@ -1077,9 +1078,9 @@ */ extlink: function ( nodes ) { var $el, - arg = nodes[0], - contents = nodes[1]; - if ( arg instanceof jQuery ) { + arg = nodes[ 0 ], + contents = nodes[ 1 ]; + if ( arg instanceof jQuery && !arg.hasClass( 'mediaWiki_htmlEmitter' ) ) { $el = arg; } else { $el = $( '<a>' ); @@ -1090,39 +1091,17 @@ } ) .click( arg ); } else { - $el.attr( 'href', arg.toString() ); + $el.attr( 'href', textify( arg ) ); } } return appendWithoutParsing( $el, contents ); }, /** - * This is basically use a combination of replace + external link (link with parameter - * as url), but we don't want to run the regular replace here-on: inserting a - * url as href-attribute of a link will automatically escape it already, so - * we don't want replace to (manually) escape it as well. - * - * TODO: throw error if nodes.length > 1 ? - * - * @param {Array} nodes List of one element, integer, n >= 0 - * @param {Array} replacements List of at least n strings - * @return {string} replacement - */ - extlinkparam: function ( nodes, replacements ) { - var replacement, - index = parseInt( nodes[0], 10 ); - if ( index < replacements.length ) { - replacement = replacements[index]; - } else { - replacement = '$' + ( index + 1 ); - } - return this.extlink( [ replacement, nodes[1] ] ); - }, - - /** * Transform parsed structure into pluralization * n.b. The first node may be a non-integer (for instance, a string representing an Arabic number). * 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 */ @@ -1130,30 +1109,30 @@ var forms, firstChild, firstChildText, explicitPluralFormNumber, formIndex, form, count, explicitPluralForms = {}; - count = parseFloat( this.language.convertNumber( nodes[0], true ) ); + count = parseFloat( this.language.convertNumber( nodes[ 0 ], true ) ); forms = nodes.slice( 1 ); for ( formIndex = 0; formIndex < forms.length; formIndex++ ) { - form = forms[formIndex]; + form = forms[ formIndex ]; - if ( form.jquery && form.hasClass( 'mediaWiki_htmlEmitter' ) ) { + if ( form instanceof jQuery && 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 ) { firstChildText = firstChild.textContent; if ( /^\d+=/.test( firstChildText ) ) { - explicitPluralFormNumber = parseInt( firstChildText.split( /=/ )[0], 10 ); + explicitPluralFormNumber = parseInt( firstChildText.split( /=/ )[ 0 ], 10 ); // Use the digit part as key and rest of first text node and // rest of child nodes as value. firstChild.textContent = firstChildText.slice( firstChildText.indexOf( '=' ) + 1 ); - explicitPluralForms[explicitPluralFormNumber] = form; - forms[formIndex] = undefined; + explicitPluralForms[ explicitPluralFormNumber ] = form; + forms[ formIndex ] = undefined; } } } else if ( /^\d+=/.test( form ) ) { // Simple explicit plural forms like 12=a dozen - explicitPluralFormNumber = parseInt( form.split( /=/ )[0], 10 ); - explicitPluralForms[explicitPluralFormNumber] = form.slice( form.indexOf( '=' ) + 1 ); - forms[formIndex] = undefined; + explicitPluralFormNumber = parseInt( form.split( /=/ )[ 0 ], 10 ); + explicitPluralForms[ explicitPluralFormNumber ] = form.slice( form.indexOf( '=' ) + 1 ); + forms[ formIndex ] = undefined; } } @@ -1180,7 +1159,7 @@ */ gender: function ( nodes ) { var gender, - maybeUser = nodes[0], + maybeUser = nodes[ 0 ], forms = nodes.slice( 1 ); if ( maybeUser === '' ) { @@ -1201,35 +1180,39 @@ /** * Transform parsed structure into grammar conversion. * 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 */ grammar: function ( nodes ) { - var form = nodes[0], - word = nodes[1]; + var form = nodes[ 0 ], + word = nodes[ 1 ]; return word && form && this.language.convertGrammar( word, form ); }, /** * Tranform parsed structure into a int: (interface language) message include * Invoked by putting `{{int:othermessage}}` into a message + * * @param {Array} nodes List of nodes * @return {string} Other message */ 'int': function ( nodes ) { - return mw.jqueryMsg.getMessageFunction()( nodes[0].toLowerCase() ); + var msg = nodes[ 0 ]; + return mw.jqueryMsg.getMessageFunction()( msg.charAt( 0 ).toLowerCase() + msg.slice( 1 ) ); }, /** * Takes an unformatted number (arab, no group separators and . as decimal separator) * and outputs it in the localized digit script and formatted with decimal * separator, according to the current language. + * * @param {Array} nodes List of nodes * @return {number|string} Formatted number */ formatnum: function ( nodes ) { - var isInteger = ( nodes[1] && nodes[1] === 'R' ) ? true : false, - number = nodes[0]; + var isInteger = ( nodes[ 1 ] && nodes[ 1 ] === 'R' ) ? true : false, + number = nodes[ 0 ]; return this.language.convertNumber( number, isInteger ); } @@ -1264,9 +1247,9 @@ } messageFunction = mw.jqueryMsg.getMessageFunction( { - 'messages': this.map, + messages: this.map, // For format 'escaped', escaping part is handled by mediawiki.js - 'format': this.format + format: this.format } ); return messageFunction( this.key, this.parameters ); }; |