r89076 MediaWiki - Code Review archive

Repository:MediaWiki
Revision:r89075‎ | r89076 | r89077 >
Date:22:38, 28 May 2011
Author:krinkle
Status:ok
Tags:
Comment:
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.
Modified paths:
  • /trunk/phase3/resources/mediawiki/mediawiki.js (modified) (history)
  • /trunk/phase3/tests/qunit/suites/resources/mediawiki/mediawiki.js (modified) (history)

Diff [purge]

Index: trunk/phase3/tests/qunit/suites/resources/mediawiki/mediawiki.js
@@ -12,23 +12,66 @@
1313
1414 });
1515
16 -test( 'mw.Map / mw.config', function(){
 16+test( 'mw.Map', function(){
1717
18 - ok( mw.config instanceof mw.Map, 'mw.config instance of mw.Map' );
19 - ok( mw.config.get, 'get' );
20 - ok( mw.config.set, 'set' );
21 - ok( mw.config.exists, 'exists' );
 18+ ok( mw.Map, 'mw.Map defined' );
 19+ ok( mw.Map.prototype.get, 'get prototype defined' );
 20+ ok( mw.Map.prototype.set, 'set prototype defined' );
 21+ ok( mw.Map.prototype.exists, 'exists prototype defined' );
2222
23 - ok( !mw.config.exists( 'lipsum' ), 'exists: lipsum (inexistant)' );
24 - ok( mw.config.set( 'lipsum', 'Lorem ipsum' ), 'set: lipsum' );
25 - ok( mw.config.exists( 'lipsum' ), 'exists: lipsum (existant)' );
 23+ var conf = new mw.Map();
2624
27 - equal( mw.config.get( 'lipsum' ), 'Lorem ipsum', 'get: lipsum' );
28 - equal( mw.config.get( ['lipsum'] ).lipsum, 'Lorem ipsum', 'get: lipsum (multiple)' );
 25+ var funky = function(){};
 26+ var arry = [];
 27+ var nummy = 7;
2928
 29+ deepEqual( conf.get( 'inexistantKey' ), null, 'Map.get() returns null if selection was a string and the key was not found.' );
 30+ deepEqual( conf.set( 'myKey', 'myValue' ), true, 'Map.set() returns boolean true if a value was set for a valid key string.' );
 31+ deepEqual( conf.set( funky, 'Funky' ), false, 'Map.set() returns boolean false if key was invalid (Function).' );
 32+ deepEqual( conf.set( arry, 'Arry' ), false, 'Map.set() returns boolean false if key was invalid (Array).' );
 33+ deepEqual( conf.set( nummy, 'Nummy' ), false, 'Map.set() returns boolean false if key was invalid (Number).' );
 34+ equal( conf.get( 'myKey' ), 'myValue', 'Map.get() returns a single value value correctly.' );
 35+
 36+ var someValues = {
 37+ 'foo': 'bar',
 38+ 'lorem': 'ipsum',
 39+ 'MediaWiki': true
 40+ };
 41+ deepEqual( conf.set( someValues ), true, 'Map.set() returns boolean true if multiple values were set by passing an object.' );
 42+ deepEqual( conf.get( ['foo', 'lorem'] ), {
 43+ 'foo': 'bar',
 44+ 'lorem': 'ipsum'
 45+ }, 'Map.get() returns multiple values correctly as an object.' );
 46+
 47+ deepEqual( conf.get( ['foo', 'notExist'] ), {
 48+ 'foo': 'bar',
 49+ 'notExist': null
 50+ }, 'Map.get() return includes keys that were not found as null values' );
 51+
 52+ deepEqual( conf.exists( 'foo' ), true, 'Map.exists() returns boolean true if a key exists.' );
 53+ deepEqual( conf.exists( 'notExist' ), false, 'Map.exists() returns boolean false if a key does not exists.' );
 54+ deepEqual( conf.get() === conf.values, true, 'Map.get() returns the entire values object by reference (if called without arguments).' );
 55+
 56+ conf.set( 'globalMapChecker', 'Hi' );
 57+
 58+ deepEqual( 'globalMapChecker' in window, false, 'new mw.Map() did not store its values in the global window object by default.' );
 59+ ok( !window.globalMapChecker, 'new mw.Map() did not store its values in the global window object by default.' );
 60+
 61+ var globalConf = new mw.Map( true );
 62+ globalConf.set( 'anotherGlobalMapChecker', 'Hello' );
 63+
 64+ deepEqual( 'anotherGlobalMapChecker' in window, true, 'new mw.Map( true ) did store its values in the global window object.' )
 65+ ok( window.anotherGlobalMapChecker, 'new mw.Map( true ) did store its values in the global window object.' )
 66+
 67+ // Clean up
 68+ delete window.anotherGlobalMapChecker;
3069 });
3170
32 -test( 'mw.message / mw.msg / mw.messages', function(){
 71+test( 'mw.config', function(){
 72+ deepEqual( mw.config instanceof mw.Map, true, 'mw.config instance of mw.Map' );
 73+});
 74+
 75+test( 'mw.messages / mw.message / mw.msg', function(){
3376 ok( mw.message, 'mw.message defined' );
3477 ok( mw.msg, 'mw.msg defined' );
3578 ok( mw.messages, 'messages defined' );
@@ -36,34 +79,44 @@
3780 ok( mw.messages.set( 'hello', 'Hello <b>awesome</b> world' ), 'mw.messages.set: Register' );
3881
3982 var hello = mw.message( 'hello' );
40 - ok( hello, 'hello: Instance of Message' );
4183
42 - equal( hello.format, 'parse', 'Message property "format" (default value)' );
 84+ equal( hello.format, 'parse', 'Message property "format" defaults to "parse".' );
 85+ deepEqual( hello.map === mw.messages, true, 'Message property "map" defaults to the global instance in mw.messages' );
4386 equal( hello.key, 'hello', 'Message property "key" (currect key)' );
44 - deepEqual( hello.parameters, [], 'Message property "parameters" (default value)' );
 87+ deepEqual( hello.parameters, [], 'Message property "parameters" defaults to an empty array.' );
4588
 89+ // Todo
 90+ ok( hello.params, 'Message prototype "params".' );
4691
47 - ok( hello.params, 'Message prototype "params"');
48 - ok( hello.toString, 'Message prototype "toString"');
49 - ok( hello.parse, 'Message prototype "parse"');
50 - ok( hello.plain, 'Message prototype "plain"');
51 - ok( hello.escaped, 'Message prototype "escaped"');
52 - ok( hello.exists, 'Message prototype "exists"');
 92+ hello.format = 'plain';
 93+ equal( hello.toString(), 'Hello <b>awesome</b> world', 'Message.toString() returns the message as a string with the current "format".' );
5394
54 - equal( hello.toString(), 'Hello <b>awesome</b> world', 'Message.toString() test');
55 - equal( hello.escaped(), 'Hello &lt;b&gt;awesome&lt;/b&gt; world', 'Message.escaped() test');
56 - deepEqual( hello.exists(), true, 'Message.exists() test');
 95+ equal( hello.escaped(), 'Hello &lt;b&gt;awesome&lt;/b&gt; world', 'Message.escaped() returns the escaped message.' );
 96+ equal( hello.format, 'escaped', 'Message.escaped() correctly updated the "format" property.' );
5797
58 - equal( mw.msg( 'random' ), '<random>', 'square brackets around inexistant messages' );
59 - equal( mw.msg( 'hello' ), 'Hello <b>awesome</b> world', 'get message with default options' );
60 -
61 -// params, toString, parse, plain, escaped, exists
 98+ hello.parse()
 99+ equal( hello.format, 'parse', 'Message.parse() correctly updated the "format" property.' );
 100+
 101+ hello.plain();
 102+ equal( hello.format, 'plain', 'Message.plain() correctly updated the "format" property.' );
 103+
 104+ deepEqual( hello.exists(), true, 'Message.exists() returns true for existing messages.' );
 105+
 106+ var goodbye = mw.message( 'goodbye' );
 107+ deepEqual( goodbye.exists(), false, 'Message.exists() returns false for inexisting messages.' );
 108+
 109+ equal( goodbye.toString(), '<goodbye>', 'Message.toString() returns <key> if key does not exist.' );
62110 });
63111
 112+test( 'mw.msg', function(){
 113+ equal( mw.msg( 'hello' ), 'Hello <b>awesome</b> world', 'Gets message with default options (existing message)' );
 114+ equal( mw.msg( 'goodbye' ), '<goodbye>', 'Gets message with default options (inexisting message).' );
 115+});
 116+
64117 test( 'mw.loader', function(){
65118 expect(5);
66119
67 - // Regular expression to extract the path for the QUnit tests
 120+ // Regular expression to extract the path for the QUnit tests
68121 // Takes into account that tests could be run from a file:// URL
69122 // by excluding the 'index.html' part from the URL
70123 var rePath = /(?:[^#\?](?!index.html))*\/?/;
@@ -105,7 +158,7 @@
106159
107160 }, function(){
108161 start();
109 - deepEqual( true, false, 'Implementing a module, error callback fired!');
 162+ deepEqual( true, false, 'Implementing a module, error callback fired!' );
110163 });
111164
112165 });
@@ -113,23 +166,23 @@
114167 test( 'mw.html', function(){
115168
116169 equal( mw.html.escape( '<mw awesome="awesome" value=\'test\' />' ),
117 - '&lt;mw awesome=&quot;awesome&quot; value=&#039;test&#039; /&gt;', 'html.escape()' );
 170+ '&lt;mw awesome=&quot;awesome&quot; value=&#039;test&#039; /&gt;', 'html.escape()' );
118171
119172 equal( mw.html.element( 'div' ), '<div/>', 'mw.html.element() DIV (simple)' );
120173
121174 equal( mw.html.element( 'div',
122 - { id: 'foobar' } ),
123 - '<div id="foobar"/>',
124 - 'mw.html.element() DIV (attribs)' );
 175+ { id: 'foobar' } ),
 176+ '<div id="foobar"/>',
 177+ 'mw.html.element() DIV (attribs)' );
125178
126179 equal( mw.html.element( 'div',
127 - null, 'a' ),
128 - '<div>a</div>',
129 - 'mw.html.element() DIV (content)' );
 180+ null, 'a' ),
 181+ '<div>a</div>',
 182+ 'mw.html.element() DIV (content)' );
130183
131184 equal( mw.html.element( 'a',
132 - { href: 'http://mediawiki.org/w/index.php?title=RL&action=history' }, 'a' ),
133 - '<a href="http://mediawiki.org/w/index.php?title=RL&amp;action=history">a</a>',
134 - 'mw.html.element() DIV (attribs + content)' );
 185+ { href: 'http://mediawiki.org/w/index.php?title=RL&action=history' }, 'a' ),
 186+ '<a href="http://mediawiki.org/w/index.php?title=RL&amp;action=history">a</a>',
 187+ 'mw.html.element() DIV (attribs + content)' );
135188
136189 });
Index: trunk/phase3/resources/mediawiki/mediawiki.js
@@ -5,36 +5,45 @@
66 // Attach to window
77 window.mediaWiki = new ( function( $ ) {
88
9 - /* Constants */
10 -
119 /* Private Members */
1210
13 - // List of messages that have been requested to be loaded
 11+ /**
 12+ * @var object List of messages that have been requested to be loaded.
 13+ */
1414 var messageQueue = {};
1515
16 - /* Prototypes */
 16+ /* Object constructors */
1717
1818 /**
19 - * An object which allows single and multiple get/set/exists functionality
20 - * on a list of key / value pairs.
 19+ * Map
2120 *
22 - * @param {boolean} global Whether to get/set/exists values on the window
23 - * object or a private object
 21+ * Creates an object that can be read from or written to from prototype functions
 22+ * that allow both single and multiple variables at once.
 23+ *
 24+ * @param global boolean Whether to store the values in the global window
 25+ * object or a exclusively in the object property 'values'.
 26+ * @return Map
2427 */
2528 function Map( global ) {
2629 this.values = ( global === true ) ? window : {};
 30+ return this;
2731 }
2832
2933 /**
30 - * Gets the value of a key, or a list of key/value pairs for an array of keys.
 34+ * Get the value of one or multiple a keys.
3135 *
3236 * If called with no arguments, all values will be returned.
3337 *
34 - * @param selection mixed Key or array of keys to get values for
35 - * @param fallback mixed Value to use in case key(s) do not exist (optional)
 38+ * @param selection mixed String key or array of keys to get values for.
 39+ * @param fallback mixed Value to use in case key(s) do not exist (optional).
 40+ * @return mixed If selection was a string returns the value or null,
 41+ * If selection was an array, returns an object of key/values (value is null if not found),
 42+ * If selection was not passed or invalid, will return the 'values' object member (be careful as
 43+ * objects are always passed by reference in JavaScript!).
 44+ * @return Map
3645 */
3746 Map.prototype.get = function( selection, fallback ) {
38 - if ( typeof selection === 'object' ) {
 47+ if ( $.isArray( selection ) ) {
3948 selection = $.makeArray( selection );
4049 var results = {};
4150 for ( var i = 0; i < selection.length; i++ ) {
@@ -42,7 +51,7 @@
4352 }
4453 return results;
4554 } else if ( typeof selection === 'string' ) {
46 - if ( typeof this.values[selection] === 'undefined' ) {
 55+ if ( this.values[selection] === undefined ) {
4756 if ( typeof fallback !== 'undefined' ) {
4857 return fallback;
4958 }
@@ -56,11 +65,12 @@
5766 /**
5867 * Sets one or multiple key/value pairs.
5968 *
60 - * @param selection mixed Key or object of key/value pairs to set
 69+ * @param selection mixed String key or array of keys to set values for.
6170 * @param value mixed Value to set (optional, only in use when key is a string)
 71+ * @return bool This returns true on success, false on failure.
6272 */
6373 Map.prototype.set = function( selection, value ) {
64 - if ( typeof selection === 'object' ) {
 74+ if ( $.isPlainObject( selection ) ) {
6575 for ( var s in selection ) {
6676 this.values[s] = selection[s];
6777 }
@@ -75,7 +85,7 @@
7686 /**
7787 * Checks if one or multiple keys exist.
7888 *
79 - * @param selection mixed Key or array of keys to check
 89+ * @param selection mixed String key or array of keys to check
8090 * @return boolean Existence of key(s)
8191 */
8292 Map.prototype.exists = function( selection ) {
@@ -92,31 +102,41 @@
93103 };
94104
95105 /**
96 - * Message object, similar to Message in PHP
 106+ * Message
 107+ *
 108+ * Object constructor for messages,
 109+ * similar to the Message class in MediaWiki PHP.
 110+ *
 111+ * @param map Map Instance of mw.Map
 112+ * @param key String
 113+ * @param parameters Array
 114+ * @return Message
97115 */
98116 function Message( map, key, parameters ) {
99117 this.format = 'parse';
100118 this.map = map;
101119 this.key = key;
102120 this.parameters = typeof parameters === 'undefined' ? [] : $.makeArray( parameters );
 121+ return this;
103122 }
104123
105124 /**
106 - * Appends parameters for replacement
 125+ * Appends (does not replace) parameters for replacement to the .parameters property.
107126 *
108 - * @param parameters mixed First in a list of variadic arguments to append as message parameters
 127+ * @param parameters Array
 128+ * @return Message
109129 */
110130 Message.prototype.params = function( parameters ) {
111131 for ( var i = 0; i < parameters.length; i++ ) {
112 - this.parameters[this.parameters.length] = parameters[i];
 132+ this.parameters.push( parameters[i] );
113133 }
114134 return this;
115135 };
116136
117137 /**
118 - * Converts message object to it's string form based on the state of format
 138+ * Converts message object to it's string form based on the state of format.
119139 *
120 - * @return {string} String form of message
 140+ * @return string Message as a string in the current form or <key> if key does not exist.
121141 */
122142 Message.prototype.toString = function() {
123143 if ( !this.map.exists( this.key ) ) {
@@ -190,7 +210,7 @@
191211
192212 /*
193213 * Dummy function which in debug mode can be replaced with a function that
194 - * does something clever
 214+ * emulates console.log in console-less environments.
195215 */
196216 this.log = function() { };
197217
@@ -219,12 +239,13 @@
220240 * Gets a message object, similar to wfMessage()
221241 *
222242 * @param key string Key of message to get
223 - * @param parameters mixed First argument in a list of variadic arguments, each a parameter for $
224 - * replacement
 243+ * @param parameters mixed First argument in a list of variadic arguments,
 244+ * each a parameter for $N replacement in messages.
 245+ * @return Message
225246 */
226 - this.message = function( key, parameters ) {
 247+ this.message = function( key, parameter_1 /* [, parameter_2] */ ) {
227248 // Support variadic arguments
228 - if ( typeof parameters !== 'undefined' ) {
 249+ if ( parameter_1 !== undefined ) {
229250 parameters = $.makeArray( arguments );
230251 parameters.shift();
231252 } else {
@@ -237,8 +258,9 @@
238259 * Gets a message string, similar to wfMsg()
239260 *
240261 * @param key string Key of message to get
241 - * @param parameters mixed First argument in a list of variadic arguments, each a parameter for $
242 - * replacement
 262+ * @param parameters mixed First argument in a list of variadic arguments,
 263+ * each a parameter for $N replacement in messages.
 264+ * @return String.
243265 */
244266 this.msg = function( key, parameters ) {
245267 return mw.message.apply( mw.message, arguments ).toString();

Sign-offs

UserFlagDate
Hasharinspected08:16, 6 June 2011
Nikerabbitinspected12:38, 14 June 2011

Status & tagging log