http://www.mediawiki.org/wiki/Special:Code/MediaWiki/83616

Revision: 83616
Author:   neilk
Date:     2011-03-09 23:34:07 +0000 (Wed, 09 Mar 2011)
Log Message:
-----------
factored better

Modified Paths:
--------------
    trunk/extensions/UploadWizard/resources/mediawiki.language.parser.js

Modified: trunk/extensions/UploadWizard/resources/mediawiki.language.parser.js
===================================================================
--- trunk/extensions/UploadWizard/resources/mediawiki.language.parser.js        
2011-03-09 23:24:37 UTC (rev 83615)
+++ trunk/extensions/UploadWizard/resources/mediawiki.language.parser.js        
2011-03-09 23:34:07 UTC (rev 83616)
@@ -17,30 +17,7 @@
                return $j.isArray( args[offset] ) ? args[offset] : 
$j.makeArray( args ).slice( offset ); 
        }
 
-
        /**
-        * The parser itself.
-        * Describes an object, whose primary duty is to .parse() message keys.
-        * TODO encapsulate language rather than picking it up from globals
-        * @param {Array} options
-        */
-       mw.language.parser = function( options ) {
-               var defaults = { 
-                       'magic' : {},
-                       'messages' : mw.messages
-               };
-               
-               this.settings = $j.extend( {}, defaults, options );
-               
-               var _this = this;
-               $j.each( this.settings.magic, function( key, val ) { 
-                       _this.op[ key.toLowerCase() ] = function() { return 
val; };
-               } );
-
-       };
-
-
-       /**
         * Class method. 
         * Returns a function suitable for use as a global, to construct 
strings from the message key (and optional replacements).
         * e.g.  
@@ -97,121 +74,45 @@
        };
                
 
-       mw.language.parser.prototype = {
 
-               // Parser functions -- 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.
-               //
-               // A parse function takes the parent node, the array of 
subnodes and the array of replacements (the values that $1, $2... should 
translate to).
-               // Note: all such functions must be totally pure. Their output 
depends entirely on input and on no other thing, not even 'this'.
-               op: {
+       var parserDefaults = { 
+               'magic' : {},
+               'messages' : mw.messages,
+               'language' : mw.language
+       };
 
-                       /**
-                        * 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 {Array} nodes - mixed, some single nodes, 
some arrays of nodes
-                        * @return {jQuery}
-                        */
-                       concat: function( nodes ) {
-                               var span = $j( '<span>' ).addClass( 
'mediaWiki_parser' );
-                               $j.each( nodes, function( i, node ) { 
-                                       if ( node instanceof jQuery && 
node.hasClass( 'mediaWiki_parser' ) ) {
-                                               $j.each( node.contents(), 
function( j, childNode ) {
-                                                       span.append( childNode 
);
-                                               } );
-                                       } else {
-                                               // strings, integers, anything 
else
-                                               span.append( node );
-                                       }
-                               } );
-                               return span;
-                       },
+       /**
+        * The parser itself.
+        * Describes an object, whose primary duty is to .parse() message keys.
+        * @param {Array} options
+        */
+       mw.language.parser = function( options ) {
+               this.settings = $j.extend( {}, parserDefaults, options );
+               this.emitter = new mw.language.parser.htmlEmitter( 
settings.language, settings.magic );
+       };
 
-                       /**
-                        * Return replacement of correct index, or string if 
unavailable.
-                        * Note that we expect the parsed parameter to be 
zero-based. i.e. $1 should have become [ 0 ].
-                        * if the specified parameter is not found return the 
same string
-                        * (e.g. "$99" -> parameter 98 -> not found -> return 
"$99" )
-                        * TODO throw error if nodes.length > 1 ?
-                        * @param {Array} of one element, integer, n >= 0
-                        * @return {String} replacement
-                        */
-                       replace: function( nodes, replacements ) {
-                               var index = parseInt( nodes[0], 10 );
-                               return index < replacements.length ? 
replacements[index] : '$' + ( index + 1 ); 
-                       },
+       mw.language.parser.prototype = {
 
-                       /** 
-                        * Transform wiki-link
-                        * TODO unimplemented 
-                        */
-                       wlink: function( nodes ) {
-                               return "unimplemented"
-                       },
-
-                       /**
-                        * Transform parsed structure into external link
-                        * If the href is a jQuery object, treat it as 
"enclosing" the link text.
-                        *              ... function, treat it as the click 
handler
-                        *              ... string, treat it as a URI
-                        * TODO: throw an error if nodes.length > 2 ? 
-                        * @param {Array} of two elements, 
{jQuery|Function|String} and {String}
-                        * @return {jQuery}
-                        */
-                       link: function( nodes ) {
-                               var arg = nodes[0];
-                               var contents = nodes[1];
-                               var $el; 
-                               if ( arg instanceof jQuery ) {
-                                       $el = arg;
-                               } else {
-                                       $el = $j( '<a>' );
-                                       if ( typeof arg === 'function' ) {
-                                               $el.click( arg ).attr( 'href', 
'#' );
-                                       } else {
-                                               $el.attr( 'href', 
arg.toString() );
-                                       }
-                               }
-                               $el.append( contents ); 
-                               return $el;
-                       },
-
-                       /**
-                        * 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} of nodes, [ {String|Number}, 
{String}, {String} ... ] 
-                        * @return {String} selected pluralized form according 
to current language
-                        */
-                       plural: function( nodes ) { 
-                               var count = parseInt( 
mw.language.convertNumber( nodes[0], true ), 10 );
-                               var forms = nodes.slice(1);
-                               return forms.length ? 
mw.language.convertPlural( count, forms ) : '';
-                       }
-                       
-               },
-
                // cache, map of mediaWiki message key 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).
                astCache: {},
 
                /**
                 * Where the magic happens.
-                * Parses a message from the key, and swaps in replacements as 
necessary
+                * Parses a message from the key, and swaps in replacements as 
necessary, wraps in jQuery
                 * @param {String} message key
                 * @param {Array} replacements for $1, $2... $n
-                * @return {Array} array of jQuery|string
+                * @return {jQuery}
                 */
                parse: function( key, replacements ) {
-                       return this.compile( this.getAst( key ), replacements );
+                       return this.emitter.emit( this.getAst( key ), 
replacements );
                },
 
                /**
                 * 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} simple string if message is simple, 
array of arrays if needs parsing
+                * @return {String|Array} string of '[key]' if message missing, 
simple string if possible, array of arrays if needs parsing
                 */
                getAst: function( key ) {
                        if ( typeof this.astCache[ key ] === 'undefined' ) { 
@@ -224,44 +125,6 @@
                        return this.astCache[ key ];    
                },
 
-
-               /**
-                * walk entire node structure, applying replacements and 
template functions when appropriate
-                * @param {Mixed} 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
-                */
-               compile: function( node, replacements ) {
-                       var ret = null;
-                       var _this = this;
-                       switch( typeof node ) {
-                               case 'string':
-                               case 'number':
-                                       ret = node;
-                                       break;
-                               case 'object':
-                                       var opKey = node[0].toLowerCase();
-                                       var operation = _this.op[ opKey ];
-                                       if ( typeof operation !== 'function' ) {
-                                               throw new Error( 'AST is 
malformed or operations not configured: no function for ' + opKey );
-                                       }
-                                       var subnodes = $j.map( node.slice( 1 ), 
function( element ) { 
-                                               return _this.compile( element, 
replacements );
-                                       } );
-                                       ret = operation( subnodes, replacements 
);
-                                       break;
-                               case 'undefined':
-                                       // Parsing the empty string (as an 
entire expression, or as a paramExpression in a template) results in undefined
-                                       // Perhaps a more clever parser can 
detect this, and return the empty string? Or is that useful information?
-                                       // The logical thing is probably to 
return the empty string here when we encounter undefined.
-                                       ret = '';
-                                       break;
-                               default:
-                                       throw new Error( 'unexpected type in 
AST: ' + typeof node );
-                       }
-                       return ret;
-               },
-
                /*
                 * Parses the input wikiText into an abstract syntax tree, 
essentially an s-expression.
                 *
@@ -632,4 +495,146 @@
                        
        };
 
+       /**
+        * htmlEmitter - object which primarily exists to emit HTML from parser 
ASTs
+        */
+       mw.language.parser.htmlEmitter = function( language, magic ) {
+               this.language = language;
+               var _this = this;
+
+               $j.each( magic, function( key, val ) { 
+                       _this[ key.toLowerCase() ] = function() { 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 {Array} replacements for $1, $2, ... $n
+                * @return {Mixed} single-string node or array of nodes 
suitable for jQuery appending
+                */
+               this.emit = function( node, replacements ) {
+                       var ret = null;
+                       var _this = this;
+                       switch( typeof node ) {
+                               case 'string':
+                               case 'number':
+                                       ret = node;
+                                       break;
+                               case 'object': // node is an array of nodes
+                                       var subnodes = $j.map( node.slice( 1 ), 
function( n ) { 
+                                               return _this.emit( n, 
replacements );
+                                       } );
+                                       var operation = node[0].toLowerCase();
+                                       ret = _this[ operation ]( subnodes, 
replacements );
+                                       break;
+                               case 'undefined':
+                                       // Parsing the empty string (as an 
entire expression, or as a paramExpression in a template) results in undefined
+                                       // Perhaps a more clever parser can 
detect this, and return the empty string? Or is that useful information?
+                                       // The logical thing is probably to 
return the empty string here when we encounter undefined.
+                                       ret = '';
+                                       break;
+                               default:
+                                       throw new Error( 'unexpected type in 
AST: ' + typeof node );
+                       }
+                       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.
+       //
+       // An emitter method takes the parent node, the array of subnodes and 
the array of replacements (the values that $1, $2... should translate to).
+       // Note: all such functions must be pure, with the exception of 
referring to other pure functions via this.language (convertPlural and so on)
+       mw.language.parser.htmlEmitter.prototype = {
+
+               /**
+                * 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 {Array} nodes - mixed, some single nodes, some arrays 
of nodes
+                * @return {jQuery}
+                */
+               concat: function( nodes ) {
+                       var span = $j( '<span>' ).addClass( 
'mediaWiki_htmlEmitter' );
+                       $j.each( nodes, function( i, node ) { 
+                               if ( node instanceof jQuery && node.hasClass( 
'mediaWiki_htmlEmitter' ) ) {
+                                       $j.each( node.contents(), function( j, 
childNode ) {
+                                               span.append( childNode );
+                                       } );
+                               } else {
+                                       // strings, integers, anything else
+                                       span.append( node );
+                               }
+                       } );
+                       return span;
+               },
+
+               /**
+                * Return replacement of correct index, or string if 
unavailable.
+                * Note that we expect the parsed parameter to be zero-based. 
i.e. $1 should have become [ 0 ].
+                * if the specified parameter is not found return the same 
string
+                * (e.g. "$99" -> parameter 98 -> not found -> return "$99" )
+                * TODO throw error if nodes.length > 1 ?
+                * @param {Array} of one element, integer, n >= 0
+                * @return {String} replacement
+                */
+               replace: function( nodes, replacements ) {
+                       var index = parseInt( nodes[0], 10 );
+                       return index < replacements.length ? 
replacements[index] : '$' + ( index + 1 ); 
+               },
+
+               /** 
+                * Transform wiki-link
+                * TODO unimplemented 
+                */
+               wlink: function( nodes ) {
+                       return "unimplemented";
+               },
+
+               /**
+                * Transform parsed structure into external link
+                * If the href is a jQuery object, treat it as "enclosing" the 
link text.
+                *              ... function, treat it as the click handler
+                *              ... string, treat it as a URI
+                * TODO: throw an error if nodes.length > 2 ? 
+                * @param {Array} of two elements, {jQuery|Function|String} and 
{String}
+                * @return {jQuery}
+                */
+               link: function( nodes ) {
+                       var arg = nodes[0];
+                       var contents = nodes[1];
+                       var $el; 
+                       if ( arg instanceof jQuery ) {
+                               $el = arg;
+                       } else {
+                               $el = $j( '<a>' );
+                               if ( typeof arg === 'function' ) {
+                                       $el.click( arg ).attr( 'href', '#' );
+                               } else {
+                                       $el.attr( 'href', arg.toString() );
+                               }
+                       }
+                       $el.append( contents ); 
+                       return $el;
+               },
+
+               /**
+                * 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} of nodes, [ {String|Number}, {String}, 
{String} ... ] 
+                * @return {String} selected pluralized form according to 
current language
+                */
+               plural: function( nodes ) { 
+                       var count = parseInt( this.language.convertNumber( 
nodes[0], true ), 10 );
+                       var forms = nodes.slice(1);
+                       return forms.length ? this.language.convertPlural( 
count, forms ) : '';
+               }
+               
+       };
+
+
 } )( mediaWiki, jQuery );


_______________________________________________
MediaWiki-CVS mailing list
MediaWiki-CVS@lists.wikimedia.org
https://lists.wikimedia.org/mailman/listinfo/mediawiki-cvs

Reply via email to