/*!
* Experimental advanced wikitext parser-emitter.
-* See: http://www.mediawiki.org/wiki/Extension:UploadWizard/MessageParser for docs
+* See: https://www.mediawiki.org/wiki/Extension:UploadWizard/MessageParser for docs
*
* @author neilk@wikimedia.org
* @author mflaschen@wikimedia.org
var oldParser,
slice = Array.prototype.slice,
parserDefaults = {
- magic : {
- 'SITENAME' : mw.config.get( 'wgSiteName' )
+ magic: {
+ 'SITENAME': mw.config.get( 'wgSiteName' )
},
// This is a whitelist based on, but simpler than, Sanitizer.php.
// Self-closing tags are not currently supported.
- allowedHtmlElements : [
+ allowedHtmlElements: [
'b',
'i'
],
// Key tag name, value allowed attributes for that tag.
// See Sanitizer::setupAttributeWhitelist
- allowedHtmlCommonAttributes : [
+ allowedHtmlCommonAttributes: [
// HTML
'id',
'class',
// Attributes allowed for specific elements.
// Key is element name in lower case
// Value is array of allowed attributes for that element
- allowedHtmlAttributesByElement : {},
- messages : mw.messages,
- language : mw.language,
+ allowedHtmlAttributesByElement: {},
+ messages: mw.messages,
+ language: mw.language,
// Same meaning as in mediawiki.js.
//
* Decodes the main HTML entities, those encoded by mw.html.escape.
*
* @private
- * @param {string} encode Encoded string
+ * @param {string} encoded Encoded string
* @return {string} String with those entities decoded
*/
function decodePrimaryHtmlEntities( encoded ) {
* 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} parser options
+ * @param {Object} options Parser options
* @return {Function}
* @return {Array} return.args First element is the key, replacements may be in array in 2nd element, or remaining elements.
* @return {jQuery} return.return
if ( parsedCloseTagResult === null ) {
// Closing tag failed. Return the start tag and contents.
- return [ 'CONCAT', input.substring( startOpenTagPos, endOpenTagPos ) ].concat( parsedHtmlContents );
+ return [ 'CONCAT', input.substring( startOpenTagPos, endOpenTagPos ) ]
+ .concat( parsedHtmlContents );
}
endCloseTagPos = pos;
wrappedAttributes = parsedOpenTagResult[2];
attributes = wrappedAttributes.slice( 1 );
if ( isAllowedHtml( startTagName, endTagName, attributes ) ) {
- result = [ 'HTMLELEMENT', startTagName, wrappedAttributes ].concat( parsedHtmlContents );
+ result = [ 'HTMLELEMENT', startTagName, wrappedAttributes ]
+ .concat( parsedHtmlContents );
} else {
// HTML is not allowed, so contents will remain how
// it was, while HTML markup at this level will be
// parsed HTML link.
//
// Concatenate everything from the tag, flattening the contents.
- result = [ 'CONCAT', input.substring( startOpenTagPos, endOpenTagPos ) ].concat( parsedHtmlContents, input.substring( startCloseTagPos, endCloseTagPos ) );
+ result = [ 'CONCAT', input.substring( startOpenTagPos, endOpenTagPos ) ]
+ .concat( parsedHtmlContents, input.substring( startCloseTagPos, endCloseTagPos ) );
}
return result;
] );
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] );
curlyBraceTransformExpressionLiteral
] );
-
/**
* Starts the parse
*
}
};
+
/**
* htmlEmitter - object which primarily exists to emit HTML from parser ASTs
*/
return val;
};
} );
+
/**
* (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} abstract syntax tree (top node or subnode)
+ * @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
*/
return ret;
};
};
+
// For everything in input that follows double-open-curly braces, there should be an equivalent parser
// function. For instance {{PLURAL ... }} will be processed by 'plural'.
// If you have 'magic words' then configure the parser to have them upon creation.
* TODO: Throw error if nodes.length > 1 ?
*
* @param {Array} nodes List of one element, integer, n >= 0
- * @param {Array} replacements
+ * @param {Array} replacements List of at least n strings
* @return {String} replacement
*/
replace: function ( nodes, replacements ) {
anchor = nodes[1];
}
- return $( '<a />' ).attr( {
+ return $( '<a>' ).attr( {
title: page,
href: url
} ).text( anchor );
* 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 ) {
/**
* 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 );
},
return this.language.convertNumber( number, isInteger );
}
};
+
// Deprecated! don't rely on gM existing.
// The window.gM ought not to be required - or if required, not required here.
// But moving it to extensions breaks it (?!)
// Need to fix plugin so it could do attributes as well, then will be okay to remove this.
- window.gM = mw.jqueryMsg.getMessageFunction();
+ // @deprecated since 1.23
+ mw.log.deprecate( window, 'gM', mw.jqueryMsg.getMessageFunction(), 'Use mw.message( ... ).parse() instead.' );
/**
* @method