Adding or adjusting front-end function and variable documentation per our conventions.
authorKrinkle <krinkle@users.mediawiki.org>
Sat, 28 May 2011 22:38:59 +0000 (22:38 +0000)
committerKrinkle <krinkle@users.mediawiki.org>
Sat, 28 May 2011 22:38:59 +0000 (22:38 +0000)
* Adding "return this;" in object constructor functions.
* Added test suites for Map and Message object constructors to match the @return descriptions.

Also did some trivial clean up and performance optimizations while at it. (per http://www.mediawiki.org/wiki/JavaScript_performance )

/me has been infected by Reedy and will be doing more of this tonight.

resources/mediawiki/mediawiki.js
tests/qunit/suites/resources/mediawiki/mediawiki.js

index 1c3e4d6..f36d21c 100644 (file)
@@ -5,36 +5,45 @@
 // Attach to window
 window.mediaWiki = new ( function( $ ) {
 
-       /* Constants */
-
        /* Private Members */
 
-       // List of messages that have been requested to be loaded
+       /**
+        * @var object List of messages that have been requested to be loaded.
+        */
        var messageQueue = {};
 
-       /* Prototypes */
+       /* Object constructors */
 
        /**
-        * An object which allows single and multiple get/set/exists functionality
-        * on a list of key / value pairs.
+        * Map
         *
-        * @param {boolean} global Whether to get/set/exists values on the window
-        *   object or a private object
+        * Creates an object that can be read from or written to from prototype functions
+        * that allow both single and multiple variables at once.
+        *
+        * @param global boolean Whether to store the values in the global window
+        * object or a exclusively in the object property 'values'.
+        * @return Map
         */
        function Map( global ) {
                this.values = ( global === true ) ? window : {};
+               return this;
        }
 
        /**
-        * Gets the value of a key, or a list of key/value pairs for an array of keys.
+        * Get the value of one or multiple a keys.
         *
         * If called with no arguments, all values will be returned.
         *
-        * @param selection mixed Key or array of keys to get values for
-        * @param fallback mixed Value to use in case key(s) do not exist (optional)
+        * @param selection mixed String key or array of keys to get values for.
+        * @param fallback mixed Value to use in case key(s) do not exist (optional).
+        * @return mixed If selection was a string returns the value or null,
+        * If selection was an array, returns an object of key/values (value is null if not found),
+        * If selection was not passed or invalid, will return the 'values' object member (be careful as
+        * objects are always passed by reference in JavaScript!).
+        * @return Map
         */
        Map.prototype.get = function( selection, fallback ) {
-               if ( typeof selection === 'object' ) {
+               if ( $.isArray( selection ) ) {
                        selection = $.makeArray( selection );
                        var results = {};
                        for ( var i = 0; i < selection.length; i++ ) {
@@ -42,7 +51,7 @@ window.mediaWiki = new ( function( $ ) {
                        }
                        return results;
                } else if ( typeof selection === 'string' ) {
-                       if ( typeof this.values[selection] === 'undefined' ) {
+                       if ( this.values[selection] === undefined ) {
                                if ( typeof fallback !== 'undefined' ) {
                                        return fallback;
                                }
@@ -56,11 +65,12 @@ window.mediaWiki = new ( function( $ ) {
        /**
         * Sets one or multiple key/value pairs.
         *
-        * @param selection mixed Key or object of key/value pairs to set
+        * @param selection mixed String key or array of keys to set values for.
         * @param value mixed Value to set (optional, only in use when key is a string)
+        * @return bool This returns true on success, false on failure.
         */
        Map.prototype.set = function( selection, value ) {
-               if ( typeof selection === 'object' ) {
+               if ( $.isPlainObject( selection ) ) {
                        for ( var s in selection ) {
                                this.values[s] = selection[s];
                        }
@@ -75,7 +85,7 @@ window.mediaWiki = new ( function( $ ) {
        /**
         * Checks if one or multiple keys exist.
         *
-        * @param selection mixed Key or array of keys to check
+        * @param selection mixed String key or array of keys to check
         * @return boolean Existence of key(s)
         */
        Map.prototype.exists = function( selection ) {
@@ -92,31 +102,41 @@ window.mediaWiki = new ( function( $ ) {
        };
 
        /**
-        * Message object, similar to Message in PHP
+        * Message
+        *
+        * Object constructor for messages,
+        * similar to the Message class in MediaWiki PHP.
+        *
+        * @param map Map Instance of mw.Map
+        * @param key String
+        * @param parameters Array
+        * @return Message
         */
        function Message( map, key, parameters ) {
                this.format = 'parse';
                this.map = map;
                this.key = key;
                this.parameters = typeof parameters === 'undefined' ? [] : $.makeArray( parameters );
+               return this;
        }
 
        /**
-        * Appends parameters for replacement
+        * Appends (does not replace) parameters for replacement to the .parameters property.
         *
-        * @param parameters mixed First in a list of variadic arguments to append as message parameters
+        * @param parameters Array
+        * @return Message
         */
        Message.prototype.params = function( parameters ) {
                for ( var i = 0; i < parameters.length; i++ ) {
-                       this.parameters[this.parameters.length] = parameters[i];
+                       this.parameters.push( parameters[i] );
                }
                return this;
        };
 
        /**
-        * Converts message object to it's string form based on the state of format
+        * Converts message object to it's string form based on the state of format.
         *
-        * @return {string} String form of message
+        * @return string Message as a string in the current form or <key> if key does not exist.
         */
        Message.prototype.toString = function() {
                if ( !this.map.exists( this.key ) ) {
@@ -190,7 +210,7 @@ window.mediaWiki = new ( function( $ ) {
 
        /*
         * Dummy function which in debug mode can be replaced with a function that
-        * does something clever
+        * emulates console.log in console-less environments. 
         */
        this.log = function() { };
 
@@ -219,12 +239,13 @@ window.mediaWiki = new ( function( $ ) {
         * Gets a message object, similar to wfMessage()
         *
         * @param key string Key of message to get
-        * @param parameters mixed First argument in a list of variadic arguments, each a parameter for $
-        * replacement
+        * @param parameters mixed First argument in a list of variadic arguments,
+        * each a parameter for $N replacement in messages.
+        * @return Message
         */
-       this.message = function( key, parameters ) {
+       this.message = function( key, parameter_1 /* [, parameter_2] */ ) {
                // Support variadic arguments
-               if ( typeof parameters !== 'undefined' ) {
+               if ( parameter_1 !== undefined ) {
                        parameters = $.makeArray( arguments );
                        parameters.shift();
                } else {
@@ -237,8 +258,9 @@ window.mediaWiki = new ( function( $ ) {
         * Gets a message string, similar to wfMsg()
         *
         * @param key string Key of message to get
-        * @param parameters mixed First argument in a list of variadic arguments, each a parameter for $
-        * replacement
+        * @param parameters mixed First argument in a list of variadic arguments,
+        * each a parameter for $N replacement in messages.
+        * @return String.
         */
        this.msg = function( key, parameters ) {
                return mw.message.apply( mw.message, arguments ).toString();
index e3fc18a..810fd42 100644 (file)
@@ -12,23 +12,66 @@ test( '-- Initial check', function(){
 
 });
 
-test( 'mw.Map / mw.config', function(){
-
-       ok( mw.config instanceof mw.Map, 'mw.config instance of mw.Map' );
-       ok( mw.config.get, 'get' );
-       ok( mw.config.set, 'set' );
-       ok( mw.config.exists, 'exists' );
-
-       ok( !mw.config.exists( 'lipsum' ), 'exists: lipsum (inexistant)' );
-       ok( mw.config.set( 'lipsum', 'Lorem ipsum' ), 'set: lipsum' );
-       ok( mw.config.exists( 'lipsum' ), 'exists: lipsum (existant)' );
-
-       equal( mw.config.get( 'lipsum' ), 'Lorem ipsum', 'get: lipsum' );
-       equal( mw.config.get( ['lipsum'] ).lipsum, 'Lorem ipsum', 'get: lipsum (multiple)' );
+test( 'mw.Map', function(){
+
+       ok( mw.Map, 'mw.Map defined' );
+       ok( mw.Map.prototype.get, 'get prototype defined' );
+       ok( mw.Map.prototype.set, 'set prototype defined' );
+       ok( mw.Map.prototype.exists, 'exists prototype defined' );
+
+       var conf = new mw.Map();
+
+       var funky = function(){};
+       var arry = [];
+       var nummy = 7;
+
+       deepEqual( conf.get( 'inexistantKey' ), null, 'Map.get() returns null if selection was a string and the key was not found.' );
+       deepEqual( conf.set( 'myKey', 'myValue' ), true, 'Map.set() returns boolean true if a value was set for a valid key string.' );
+       deepEqual( conf.set( funky, 'Funky' ), false, 'Map.set() returns boolean false if key was invalid (Function).' );
+       deepEqual( conf.set( arry, 'Arry' ), false, 'Map.set() returns boolean false if key was invalid (Array).' );
+       deepEqual( conf.set( nummy, 'Nummy' ), false, 'Map.set() returns boolean false if key was invalid (Number).' );
+       equal( conf.get( 'myKey' ), 'myValue', 'Map.get() returns a single value value correctly.' );
+
+       var someValues = {
+               'foo': 'bar',
+               'lorem': 'ipsum',
+               'MediaWiki': true
+       };
+       deepEqual( conf.set( someValues ), true, 'Map.set() returns boolean true if multiple values were set by passing an object.' );
+       deepEqual( conf.get( ['foo', 'lorem'] ), {
+               'foo': 'bar',
+               'lorem': 'ipsum'
+       }, 'Map.get() returns multiple values correctly as an object.' );
+
+       deepEqual( conf.get( ['foo', 'notExist'] ), {
+               'foo': 'bar',
+               'notExist': null
+       }, 'Map.get() return includes keys that were not found as null values' );
+
+       deepEqual( conf.exists( 'foo' ), true, 'Map.exists() returns boolean true if a key exists.' );
+       deepEqual( conf.exists( 'notExist' ), false, 'Map.exists() returns boolean false if a key does not exists.' );
+       deepEqual( conf.get() === conf.values, true, 'Map.get() returns the entire values object by reference (if called without arguments).' );
+
+       conf.set( 'globalMapChecker', 'Hi' );
+
+       deepEqual( 'globalMapChecker' in window, false, 'new mw.Map() did not store its values in the global window object by default.' );
+       ok( !window.globalMapChecker, 'new mw.Map() did not store its values in the global window object by default.' );
+
+       var globalConf = new mw.Map( true );
+       globalConf.set( 'anotherGlobalMapChecker', 'Hello' );
+
+       deepEqual( 'anotherGlobalMapChecker' in window, true, 'new mw.Map( true ) did store its values in the global window object.' )
+       ok( window.anotherGlobalMapChecker, 'new mw.Map( true ) did store its values in the global window object.' )
+
+       // Clean up
+       delete window.anotherGlobalMapChecker;
+});
 
+test( 'mw.config', function(){
+       deepEqual( mw.config instanceof mw.Map, true, 'mw.config instance of mw.Map' );
 });
 
-test( 'mw.message / mw.msg / mw.messages', function(){
+test( 'mw.messages / mw.message / mw.msg', function(){
        ok( mw.message, 'mw.message defined' );
        ok( mw.msg, 'mw.msg defined' );
        ok( mw.messages, 'messages defined' );
@@ -36,34 +79,44 @@ test( 'mw.message / mw.msg / mw.messages', function(){
        ok( mw.messages.set( 'hello', 'Hello <b>awesome</b> world' ), 'mw.messages.set: Register' );
 
        var hello = mw.message( 'hello' );
-       ok( hello, 'hello: Instance of Message' );
 
-       equal( hello.format, 'parse', 'Message property "format" (default value)' );
+       equal( hello.format, 'parse', 'Message property "format" defaults to "parse".' );
+       deepEqual( hello.map === mw.messages, true, 'Message property "map" defaults to the global instance in mw.messages' );
        equal( hello.key, 'hello', 'Message property "key" (currect key)' );
-       deepEqual( hello.parameters, [], 'Message property "parameters" (default value)' );
+       deepEqual( hello.parameters, [], 'Message property "parameters" defaults to an empty array.' );
+
+       // Todo
+       ok( hello.params, 'Message prototype "params".' );
 
+       hello.format = 'plain';
+       equal( hello.toString(), 'Hello <b>awesome</b> world', 'Message.toString() returns the message as a string with the current "format".' );
 
-       ok( hello.params, 'Message prototype "params"');
-       ok( hello.toString, 'Message prototype "toString"');
-       ok( hello.parse, 'Message prototype "parse"');
-       ok( hello.plain, 'Message prototype "plain"');
-       ok( hello.escaped, 'Message prototype "escaped"');
-       ok( hello.exists, 'Message prototype "exists"');
+       equal( hello.escaped(), 'Hello &lt;b&gt;awesome&lt;/b&gt; world', 'Message.escaped() returns the escaped message.' );
+       equal( hello.format, 'escaped', 'Message.escaped() correctly updated the "format" property.' );
 
-       equal( hello.toString(), 'Hello <b>awesome</b> world', 'Message.toString() test');
-       equal( hello.escaped(), 'Hello &lt;b&gt;awesome&lt;/b&gt; world', 'Message.escaped() test');
-       deepEqual( hello.exists(), true, 'Message.exists() test');
+       hello.parse()
+       equal( hello.format, 'parse', 'Message.parse() correctly updated the "format" property.' );
+
+       hello.plain();
+       equal( hello.format, 'plain', 'Message.plain() correctly updated the "format" property.' );
+
+       deepEqual( hello.exists(), true, 'Message.exists() returns true for existing messages.' );
+
+       var goodbye = mw.message( 'goodbye' );
+       deepEqual( goodbye.exists(), false, 'Message.exists() returns false for inexisting messages.' );
+
+       equal( goodbye.toString(), '<goodbye>', 'Message.toString() returns <key> if key does not exist.' );
+});
 
-       equal( mw.msg( 'random' ), '<random>', 'square brackets around inexistant messages' );
-       equal( mw.msg( 'hello' ), 'Hello <b>awesome</b> world', 'get message with default options' );
-       
-// params, toString, parse, plain, escaped, exists
+test( 'mw.msg', function(){
+       equal( mw.msg( 'hello' ), 'Hello <b>awesome</b> world', 'Gets message with default options (existing message)' );
+       equal( mw.msg( 'goodbye' ), '<goodbye>', 'Gets message with default options (inexisting message).' );
 });
 
 test( 'mw.loader', function(){
        expect(5);
 
-       // Regular expression to extract the path for the QUnit tests   
+       // Regular expression to extract the path for the QUnit tests
        // Takes into account that tests could be run from a file:// URL
        // by excluding the 'index.html' part from the URL
        var rePath = /(?:[^#\?](?!index.html))*\/?/;
@@ -105,7 +158,7 @@ test( 'mw.loader', function(){
 
        }, function(){
                start();
-               deepEqual( true, false, 'Implementing a module, error callback fired!');
+               deepEqual( true, false, 'Implementing a module, error callback fired!' );
        });
 
 });
@@ -113,23 +166,23 @@ test( 'mw.loader', function(){
 test( 'mw.html', function(){
 
        equal( mw.html.escape( '<mw awesome="awesome" value=\'test\' />' ),
-        '&lt;mw awesome=&quot;awesome&quot; value=&#039;test&#039; /&gt;', 'html.escape()' );
+               '&lt;mw awesome=&quot;awesome&quot; value=&#039;test&#039; /&gt;', 'html.escape()' );
 
        equal( mw.html.element( 'div' ), '<div/>', 'mw.html.element() DIV (simple)' );
 
        equal( mw.html.element( 'div',
-        { id: 'foobar' } ),
-        '<div id="foobar"/>',
-        'mw.html.element() DIV (attribs)' );
+                       { id: 'foobar' } ),
+               '<div id="foobar"/>',
+               'mw.html.element() DIV (attribs)' );
 
        equal( mw.html.element( 'div',
-        null, 'a' ),
-        '<div>a</div>',
-        'mw.html.element() DIV (content)' );
+                       null, 'a' ),
+               '<div>a</div>',
+               'mw.html.element() DIV (content)' );
 
        equal( mw.html.element( 'a',
-         { href: 'http://mediawiki.org/w/index.php?title=RL&action=history' }, 'a' ),
-         '<a href="http://mediawiki.org/w/index.php?title=RL&amp;action=history">a</a>',
-         'mw.html.element() DIV (attribs + content)' );
+                       { href: 'http://mediawiki.org/w/index.php?title=RL&action=history' }, 'a' ),
+               '<a href="http://mediawiki.org/w/index.php?title=RL&amp;action=history">a</a>',
+               'mw.html.element() DIV (attribs + content)' );
 
 });