Index: trunk/phase3/tests/qunit/suites/resources/mediawiki/mediawiki.js |
— | — | @@ -12,23 +12,66 @@ |
13 | 13 | |
14 | 14 | }); |
15 | 15 | |
16 | | -test( 'mw.Map / mw.config', function(){ |
| 16 | +test( 'mw.Map', function(){ |
17 | 17 | |
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' ); |
22 | 22 | |
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(); |
26 | 24 | |
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; |
29 | 28 | |
| 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; |
30 | 69 | }); |
31 | 70 | |
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(){ |
33 | 76 | ok( mw.message, 'mw.message defined' ); |
34 | 77 | ok( mw.msg, 'mw.msg defined' ); |
35 | 78 | ok( mw.messages, 'messages defined' ); |
— | — | @@ -36,34 +79,44 @@ |
37 | 80 | ok( mw.messages.set( 'hello', 'Hello <b>awesome</b> world' ), 'mw.messages.set: Register' ); |
38 | 81 | |
39 | 82 | var hello = mw.message( 'hello' ); |
40 | | - ok( hello, 'hello: Instance of Message' ); |
41 | 83 | |
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' ); |
43 | 86 | 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.' ); |
45 | 88 | |
| 89 | + // Todo |
| 90 | + ok( hello.params, 'Message prototype "params".' ); |
46 | 91 | |
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".' ); |
53 | 94 | |
54 | | - equal( hello.toString(), 'Hello <b>awesome</b> world', 'Message.toString() test'); |
55 | | - equal( hello.escaped(), 'Hello <b>awesome</b> world', 'Message.escaped() test'); |
56 | | - deepEqual( hello.exists(), true, 'Message.exists() test'); |
| 95 | + equal( hello.escaped(), 'Hello <b>awesome</b> world', 'Message.escaped() returns the escaped message.' ); |
| 96 | + equal( hello.format, 'escaped', 'Message.escaped() correctly updated the "format" property.' ); |
57 | 97 | |
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.' ); |
62 | 110 | }); |
63 | 111 | |
| 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 | + |
64 | 117 | test( 'mw.loader', function(){ |
65 | 118 | expect(5); |
66 | 119 | |
67 | | - // Regular expression to extract the path for the QUnit tests |
| 120 | + // Regular expression to extract the path for the QUnit tests |
68 | 121 | // Takes into account that tests could be run from a file:// URL |
69 | 122 | // by excluding the 'index.html' part from the URL |
70 | 123 | var rePath = /(?:[^#\?](?!index.html))*\/?/; |
— | — | @@ -105,7 +158,7 @@ |
106 | 159 | |
107 | 160 | }, function(){ |
108 | 161 | start(); |
109 | | - deepEqual( true, false, 'Implementing a module, error callback fired!'); |
| 162 | + deepEqual( true, false, 'Implementing a module, error callback fired!' ); |
110 | 163 | }); |
111 | 164 | |
112 | 165 | }); |
— | — | @@ -113,23 +166,23 @@ |
114 | 167 | test( 'mw.html', function(){ |
115 | 168 | |
116 | 169 | equal( mw.html.escape( '<mw awesome="awesome" value=\'test\' />' ), |
117 | | - '<mw awesome="awesome" value='test' />', 'html.escape()' ); |
| 170 | + '<mw awesome="awesome" value='test' />', 'html.escape()' ); |
118 | 171 | |
119 | 172 | equal( mw.html.element( 'div' ), '<div/>', 'mw.html.element() DIV (simple)' ); |
120 | 173 | |
121 | 174 | 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)' ); |
125 | 178 | |
126 | 179 | 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)' ); |
130 | 183 | |
131 | 184 | 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&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&action=history">a</a>', |
| 187 | + 'mw.html.element() DIV (attribs + content)' ); |
135 | 188 | |
136 | 189 | }); |
Index: trunk/phase3/resources/mediawiki/mediawiki.js |
— | — | @@ -5,36 +5,45 @@ |
6 | 6 | // Attach to window |
7 | 7 | window.mediaWiki = new ( function( $ ) { |
8 | 8 | |
9 | | - /* Constants */ |
10 | | - |
11 | 9 | /* Private Members */ |
12 | 10 | |
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 | + */ |
14 | 14 | var messageQueue = {}; |
15 | 15 | |
16 | | - /* Prototypes */ |
| 16 | + /* Object constructors */ |
17 | 17 | |
18 | 18 | /** |
19 | | - * An object which allows single and multiple get/set/exists functionality |
20 | | - * on a list of key / value pairs. |
| 19 | + * Map |
21 | 20 | * |
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 |
24 | 27 | */ |
25 | 28 | function Map( global ) { |
26 | 29 | this.values = ( global === true ) ? window : {}; |
| 30 | + return this; |
27 | 31 | } |
28 | 32 | |
29 | 33 | /** |
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. |
31 | 35 | * |
32 | 36 | * If called with no arguments, all values will be returned. |
33 | 37 | * |
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 |
36 | 45 | */ |
37 | 46 | Map.prototype.get = function( selection, fallback ) { |
38 | | - if ( typeof selection === 'object' ) { |
| 47 | + if ( $.isArray( selection ) ) { |
39 | 48 | selection = $.makeArray( selection ); |
40 | 49 | var results = {}; |
41 | 50 | for ( var i = 0; i < selection.length; i++ ) { |
— | — | @@ -42,7 +51,7 @@ |
43 | 52 | } |
44 | 53 | return results; |
45 | 54 | } else if ( typeof selection === 'string' ) { |
46 | | - if ( typeof this.values[selection] === 'undefined' ) { |
| 55 | + if ( this.values[selection] === undefined ) { |
47 | 56 | if ( typeof fallback !== 'undefined' ) { |
48 | 57 | return fallback; |
49 | 58 | } |
— | — | @@ -56,11 +65,12 @@ |
57 | 66 | /** |
58 | 67 | * Sets one or multiple key/value pairs. |
59 | 68 | * |
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. |
61 | 70 | * @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. |
62 | 72 | */ |
63 | 73 | Map.prototype.set = function( selection, value ) { |
64 | | - if ( typeof selection === 'object' ) { |
| 74 | + if ( $.isPlainObject( selection ) ) { |
65 | 75 | for ( var s in selection ) { |
66 | 76 | this.values[s] = selection[s]; |
67 | 77 | } |
— | — | @@ -75,7 +85,7 @@ |
76 | 86 | /** |
77 | 87 | * Checks if one or multiple keys exist. |
78 | 88 | * |
79 | | - * @param selection mixed Key or array of keys to check |
| 89 | + * @param selection mixed String key or array of keys to check |
80 | 90 | * @return boolean Existence of key(s) |
81 | 91 | */ |
82 | 92 | Map.prototype.exists = function( selection ) { |
— | — | @@ -92,31 +102,41 @@ |
93 | 103 | }; |
94 | 104 | |
95 | 105 | /** |
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 |
97 | 115 | */ |
98 | 116 | function Message( map, key, parameters ) { |
99 | 117 | this.format = 'parse'; |
100 | 118 | this.map = map; |
101 | 119 | this.key = key; |
102 | 120 | this.parameters = typeof parameters === 'undefined' ? [] : $.makeArray( parameters ); |
| 121 | + return this; |
103 | 122 | } |
104 | 123 | |
105 | 124 | /** |
106 | | - * Appends parameters for replacement |
| 125 | + * Appends (does not replace) parameters for replacement to the .parameters property. |
107 | 126 | * |
108 | | - * @param parameters mixed First in a list of variadic arguments to append as message parameters |
| 127 | + * @param parameters Array |
| 128 | + * @return Message |
109 | 129 | */ |
110 | 130 | Message.prototype.params = function( parameters ) { |
111 | 131 | for ( var i = 0; i < parameters.length; i++ ) { |
112 | | - this.parameters[this.parameters.length] = parameters[i]; |
| 132 | + this.parameters.push( parameters[i] ); |
113 | 133 | } |
114 | 134 | return this; |
115 | 135 | }; |
116 | 136 | |
117 | 137 | /** |
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. |
119 | 139 | * |
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. |
121 | 141 | */ |
122 | 142 | Message.prototype.toString = function() { |
123 | 143 | if ( !this.map.exists( this.key ) ) { |
— | — | @@ -190,7 +210,7 @@ |
191 | 211 | |
192 | 212 | /* |
193 | 213 | * 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. |
195 | 215 | */ |
196 | 216 | this.log = function() { }; |
197 | 217 | |
— | — | @@ -219,12 +239,13 @@ |
220 | 240 | * Gets a message object, similar to wfMessage() |
221 | 241 | * |
222 | 242 | * @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 |
225 | 246 | */ |
226 | | - this.message = function( key, parameters ) { |
| 247 | + this.message = function( key, parameter_1 /* [, parameter_2] */ ) { |
227 | 248 | // Support variadic arguments |
228 | | - if ( typeof parameters !== 'undefined' ) { |
| 249 | + if ( parameter_1 !== undefined ) { |
229 | 250 | parameters = $.makeArray( arguments ); |
230 | 251 | parameters.shift(); |
231 | 252 | } else { |
— | — | @@ -237,8 +258,9 @@ |
238 | 259 | * Gets a message string, similar to wfMsg() |
239 | 260 | * |
240 | 261 | * @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. |
243 | 265 | */ |
244 | 266 | this.msg = function( key, parameters ) { |
245 | 267 | return mw.message.apply( mw.message, arguments ).toString(); |