From: Krinkle Date: Sat, 28 May 2011 22:38:59 +0000 (+0000) Subject: Adding or adjusting front-end function and variable documentation per our conventions. X-Git-Tag: 1.31.0-rc.0~29879 X-Git-Url: https://git.cyclocoop.org/%242?a=commitdiff_plain;h=6a408d444c1c425e95adce307b3400550c691231;p=lhc%2Fweb%2Fwiklou.git Adding or adjusting front-end function and variable documentation per our conventions. * 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. --- diff --git a/resources/mediawiki/mediawiki.js b/resources/mediawiki/mediawiki.js index 1c3e4d6e33..f36d21cbd9 100644 --- a/resources/mediawiki/mediawiki.js +++ b/resources/mediawiki/mediawiki.js @@ -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 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(); diff --git a/tests/qunit/suites/resources/mediawiki/mediawiki.js b/tests/qunit/suites/resources/mediawiki/mediawiki.js index e3fc18acd0..810fd42da6 100644 --- a/tests/qunit/suites/resources/mediawiki/mediawiki.js +++ b/tests/qunit/suites/resources/mediawiki/mediawiki.js @@ -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 awesome 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 awesome 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 <b>awesome</b> world', 'Message.escaped() returns the escaped message.' ); + equal( hello.format, 'escaped', 'Message.escaped() correctly updated the "format" property.' ); - equal( hello.toString(), 'Hello awesome world', 'Message.toString() test'); - equal( hello.escaped(), 'Hello <b>awesome</b> 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(), '', 'Message.toString() returns if key does not exist.' ); +}); - equal( mw.msg( 'random' ), '', 'square brackets around inexistant messages' ); - equal( mw.msg( 'hello' ), 'Hello awesome world', 'get message with default options' ); - -// params, toString, parse, plain, escaped, exists +test( 'mw.msg', function(){ + equal( mw.msg( 'hello' ), 'Hello awesome world', 'Gets message with default options (existing message)' ); + equal( mw.msg( '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' />', 'html.escape()' ); + '<mw awesome="awesome" value='test' />', 'html.escape()' ); equal( mw.html.element( 'div' ), '
', 'mw.html.element() DIV (simple)' ); equal( mw.html.element( 'div', - { id: 'foobar' } ), - '
', - 'mw.html.element() DIV (attribs)' ); + { id: 'foobar' } ), + '
', + 'mw.html.element() DIV (attribs)' ); equal( mw.html.element( 'div', - null, 'a' ), - '
a
', - 'mw.html.element() DIV (content)' ); + null, 'a' ), + '
a
', + 'mw.html.element() DIV (content)' ); equal( mw.html.element( 'a', - { href: 'http://mediawiki.org/w/index.php?title=RL&action=history' }, 'a' ), - 'a', - 'mw.html.element() DIV (attribs + content)' ); + { href: 'http://mediawiki.org/w/index.php?title=RL&action=history' }, 'a' ), + 'a', + 'mw.html.element() DIV (attribs + content)' ); });