From 9cbf26450df16fcdb068d69e09c82eb5272bf428 Mon Sep 17 00:00:00 2001 From: =?utf8?q?Bartosz=20Dziewo=C5=84ski?= Date: Thu, 13 Feb 2014 14:10:17 +0100 Subject: [PATCH] mediawiki.jqueryMsg: Support {{GENDER:}} with empty first parameter MIME-Version: 1.0 Content-Type: text/plain; charset=utf8 Content-Transfer-Encoding: 8bit (That is, gender for the user viewing the page.) This is a bit hacky – it would be cleaner to allow empty parameters instead of creating a separate construction for first-parameter-less brace expansion – but this one works and the cleaner one was throwing exceptions all over when I tried to do that. Bug: 61320 Change-Id: I0f273951b2f8cebd50dffc6ef23520bb6fa72ccf --- resources/mediawiki/mediawiki.jqueryMsg.js | 41 ++++++++++++----- resources/mediawiki/mediawiki.jqueryMsg.peg | 4 ++ .../mediawiki/mediawiki.jqueryMsg.test.js | 45 ++++++++++++++----- 3 files changed, 68 insertions(+), 22 deletions(-) diff --git a/resources/mediawiki/mediawiki.jqueryMsg.js b/resources/mediawiki/mediawiki.jqueryMsg.js index e4a9316fde..56060977b6 100644 --- a/resources/mediawiki/mediawiki.jqueryMsg.js +++ b/resources/mediawiki/mediawiki.jqueryMsg.js @@ -785,13 +785,20 @@ ] ); return result === null ? null : [ result[0], result[2] ]; } + function templateWithOutFirstParameter() { + var result = sequence( [ + templateName, + colon + ] ); + return result === null ? null : [ result[0], '' ]; + } colon = makeStringParser( ':' ); templateContents = choice( [ function () { var res = sequence( [ // templates can have placeholders for dynamic replacement eg: {{PLURAL:$1|one car|$1 cars}} // or no placeholders eg: {{GRAMMAR:genitive|{{SITENAME}}} - choice( [ templateWithReplacement, templateWithOutReplacement ] ), + choice( [ templateWithReplacement, templateWithOutReplacement, templateWithOutFirstParameter ] ), nOrMore( 0, templateParam ) ] ); return res === null ? null : res[0].concat( res[1] ); @@ -1117,23 +1124,33 @@ /** * Transform parsed structure according to gender. - * Usage {{gender:[ gender | mw.user object ] | masculine form|feminine form|neutral form}}. - * The first node is either a string, which can be "male" or "female", - * or a User object (not a username). * - * @param {Array} nodes List of nodes, [ {string|mw.User}, {string}, {string}, {string} ] - * @return {string} selected gender form according to current language + * Usage: {{gender:[ mw.user object | '' | 'male' | 'female' | 'unknown' ] | masculine form | feminine form | neutral form}}. + * + * The first node must be one of: + * - the mw.user object (or a compatible one) + * - an empty string - indicating the current user, same effect as passing the mw.user object + * - 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 */ gender: function ( nodes ) { - var gender, forms; + var gender, + maybeUser = nodes[0], + forms = nodes.slice( 1 ); - if ( nodes[0] && nodes[0].options instanceof mw.Map ) { - gender = nodes[0].options.get( 'gender' ); - } else { - gender = nodes[0]; + if ( maybeUser === '' ) { + maybeUser = mw.user; } - forms = nodes.slice( 1 ); + // If we are passed a mw.user-like object, check their gender. + // Otherwise, assume the gender string itself was passed . + if ( maybeUser && maybeUser.options instanceof mw.Map ) { + gender = maybeUser.options.get( 'gender' ); + } else { + gender = maybeUser; + } return this.language.gender( gender, forms ); }, diff --git a/resources/mediawiki/mediawiki.jqueryMsg.peg b/resources/mediawiki/mediawiki.jqueryMsg.peg index 7879d6fa22..716c326190 100644 --- a/resources/mediawiki/mediawiki.jqueryMsg.peg +++ b/resources/mediawiki/mediawiki.jqueryMsg.peg @@ -23,6 +23,7 @@ template templateContents = twr:templateWithReplacement p:templateParam* { return twr.concat(p) } / twr:templateWithOutReplacement p:templateParam* { return twr.concat(p) } + / twr:templateWithOutFirstParameter p:templateParam* { return twr.concat(p) } / t:templateName p:templateParam* { return p.length ? [ t, p ] : [ t ] } templateWithReplacement @@ -31,6 +32,9 @@ templateWithReplacement templateWithOutReplacement = t:templateName ":" p:paramExpression { return [ t, p ] } +templateWithOutFirstParameter + = t:templateName ":" { return [ t, "" ] } + templateParam = "|" e:paramExpression* { return e.length > 1 ? [ "CONCAT" ].concat(e) : e[0]; } diff --git a/tests/qunit/suites/resources/mediawiki/mediawiki.jqueryMsg.test.js b/tests/qunit/suites/resources/mediawiki/mediawiki.jqueryMsg.test.js index 6e13e13601..292c5761f4 100644 --- a/tests/qunit/suites/resources/mediawiki/mediawiki.jqueryMsg.test.js +++ b/tests/qunit/suites/resources/mediawiki/mediawiki.jqueryMsg.test.js @@ -17,6 +17,7 @@ // The values for gender are not significant, // what matters is which of the values is choosen by the parser 'gender-msg': '$1: {{GENDER:$2|blue|pink|green}}', + 'gender-msg-currentuser': '{{GENDER:|blue|pink|green}}', 'plural-msg': 'Found $1 {{PLURAL:$1|item|items}}', @@ -141,32 +142,49 @@ assert.equal( formatParse( 'plural-msg', 2 ), 'Found 2 items', 'Plural test for english' ); } ); - QUnit.test( 'Gender', 11, function ( assert ) { + QUnit.test( 'Gender', 15, function ( assert ) { + var originalGender = mw.user.options.get( 'gender' ); + // TODO: These tests should be for mw.msg once mw.msg integrated with mw.jqueryMsg // TODO: English may not be the best language for these tests. Use a language like Arabic or Russian - var user = mw.user; - - user.options.set( 'gender', 'male' ); + mw.user.options.set( 'gender', 'male' ); assert.equal( formatParse( 'gender-msg', 'Bob', 'male' ), 'Bob: blue', 'Masculine from string "male"' ); assert.equal( - formatParse( 'gender-msg', 'Bob', user ), + formatParse( 'gender-msg', 'Bob', mw.user ), 'Bob: blue', 'Masculine from mw.user object' ); - - user.options.set( 'gender', 'unknown' ); assert.equal( - formatParse( 'gender-msg', 'Foo', user ), - 'Foo: green', - 'Neutral from mw.user object' ); + formatParse( 'gender-msg-currentuser' ), + 'blue', + 'Masculine for current user' + ); + + mw.user.options.set( 'gender', 'female' ); assert.equal( formatParse( 'gender-msg', 'Alice', 'female' ), 'Alice: pink', 'Feminine from string "female"' ); + assert.equal( + formatParse( 'gender-msg', 'Alice', mw.user ), + 'Alice: pink', + 'Feminine from mw.user object' + ); + assert.equal( + formatParse( 'gender-msg-currentuser' ), + 'pink', + 'Feminine for current user' + ); + + mw.user.options.set( 'gender', 'unknown' ); + assert.equal( + formatParse( 'gender-msg', 'Foo', mw.user ), + 'Foo: green', + 'Neutral from mw.user object' ); assert.equal( formatParse( 'gender-msg', 'User' ), 'User: green', @@ -176,6 +194,11 @@ 'User: green', 'Neutral from string "unknown"' ); + assert.equal( + formatParse( 'gender-msg-currentuser' ), + 'green', + 'Neutral for current user' + ); mw.messages.set( 'gender-msg-one-form', '{{GENDER:$1|User}}: $2 {{PLURAL:$2|edit|edits}}' ); @@ -208,6 +231,8 @@ ' test', 'Invalid syntax should result in {{gender}} simply being stripped away' ); + + mw.user.options.set( 'gender', originalGender ); } ); QUnit.test( 'Grammar', 2, function ( assert ) { -- 2.20.1