// 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++ ) {
}
return results;
} else if ( typeof selection === 'string' ) {
- if ( typeof this.values[selection] === 'undefined' ) {
+ if ( this.values[selection] === undefined ) {
if ( typeof fallback !== 'undefined' ) {
return fallback;
}
/**
* 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];
}
/**
* 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 ) {
};
/**
- * 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 ) ) {
/*
* 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() { };
* 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 {
* 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();
});
-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' );
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 <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 <b>awesome</b> 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(), '<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))*\/?/;
}, function(){
start();
- deepEqual( true, false, 'Implementing a module, error callback fired!');
+ deepEqual( true, false, 'Implementing a module, error callback fired!' );
});
});
test( 'mw.html', function(){
equal( mw.html.escape( '<mw awesome="awesome" value=\'test\' />' ),
- '<mw awesome="awesome" value='test' />', 'html.escape()' );
+ '<mw awesome="awesome" value='test' />', '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&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&action=history">a</a>',
+ 'mw.html.element() DIV (attribs + content)' );
});