/**
* Simple message parser, does $N replacement and nothing else.
* This may be overridden to provide a more complex message parser.
- *
+ *
* This function will not be called for nonexistent messages.
*/
parser: function() {
return parameters[index] !== undefined ? parameters[index] : '$' + match;
} );
},
-
+
/**
* Appends (does not replace) parameters for replacement to the .parameters property.
*
text = this.parser();
text = mw.html.escape( text );
}
-
+
if ( this.format === 'parse' ) {
text = this.parser();
}
* emulates console.log in console-less environments.
*/
log: function() { },
-
+
/**
* @var constructor Make the Map constructor publicly available.
*/
* @var constructor Make the Message constructor publicly available.
*/
Message: Message,
-
+
/**
* List of configuration values
*
* in the global window object.
*/
config: null,
-
+
/**
* @var object
*
* Empty object that plugins can be installed in.
*/
libs: {},
-
+
/* Extension points */
-
+
legacy: {},
-
+
/**
* Localization system
*/
messages: new Map(),
-
+
/* Public Methods */
-
+
/**
* Gets a message object, similar to wfMessage()
*
}
return new Message( mw.messages, key, parameters );
},
-
+
/**
* Gets a message string, similar to wfMsg()
*
msg: function ( /* key, parameter_1, parameter_2, .. */ ) {
return mw.message.apply( mw.message, arguments ).toString();
},
-
+
/**
* Client-side module loader which integrates with the MediaWiki ResourceLoader
*/
loader: ( function () {
-
+
/* Private Members */
-
+
/**
* Mapping of registered modules
*
ready = false,
// Selector cache for the marker element. Use getMarker() to get/use the marker!
$marker = null;
-
+
/* Cache document ready status */
-
+
$(document).ready( function () {
ready = true;
} );
-
+
/* Private methods */
-
+
function getMarker() {
// Cached ?
if ( $marker ) {
}
return true;
}
-
+
/**
* Generates an ISO8601 "basic" string from a UNIX timestamp
*/
pad( d.getUTCHours(), d.getUTCMinutes(), d.getUTCSeconds() ), 'Z'
].join( '' );
}
-
+
/**
* Recursively resolves dependencies and detects circular references
*/
function recurse( module, resolved, unresolved ) {
var n, deps, len;
-
+
if ( registry[module] === undefined ) {
throw new Error( 'Unknown dependency: ' + module );
}
}
resolved[resolved.length] = module;
}
-
+
/**
* Gets a list of module names that a module depends on in their proper dependency order
*
*/
function resolve( module ) {
var modules, m, deps, n, resolved;
-
+
// Allow calling with an array of module names
if ( $.isArray( module ) ) {
modules = [];
throw new Error( 'Invalid module argument: ' + module );
}
-
+
/**
* Narrows a list of module names down to those matching a specific
* state (see comment on top of this scope for a list of valid states).
*/
function filter( states, modules ) {
var list, module, s, m;
-
+
// Allow states to be given as a string
if ( typeof states === 'string' ) {
states = [states];
}
return list;
}
-
+
/**
* Automatically executes jobs and modules which are pending with satistifed dependencies.
*
*/
function handlePending( module ) {
var j, r;
-
+
try {
// Run jobs whose dependencies have just been met
for ( j = 0; j < jobs.length; j += 1 ) {
throw e;
}
}
-
+
/**
* Adds a script tag to the DOM, either using document.write or low-level DOM manipulation,
* depending on whether document-ready has occured yet and whether we are in async mode.
if ( $.isFunction( callback ) ) {
// Attach handlers for all browsers (based on jQuery.ajax)
script.onload = script.onreadystatechange = function() {
-
+
if (
!done
&& (
|| /loaded|complete/.test( script.readyState )
)
) {
-
+
done = true;
-
+
callback();
-
+
// Handle memory leak in IE. This seems to fail in
// IE7 sometimes (Permission Denied error when
// accessing script.parentNode) so wrap it in
if ( script.parentNode ) {
script.parentNode.removeChild( script );
}
-
+
// Dereference the script
script = undefined;
} catch ( e ) { }
}
};
}
-
+
if ( window.opera ) {
// Appending to the <head> blocks rendering completely in Opera,
// so append to the <body> after document ready. This means the
}
}
}
-
+
/**
* Executes a loaded module, making it ready to use
*
*/
function execute( module, callback ) {
var style, media, i, script, markModuleReady, nestedAddScript;
-
+
if ( registry[module] === undefined ) {
throw new Error( 'Module has not been registered yet: ' + module );
} else if ( registry[module].state === 'registered' ) {
} else if ( registry[module].state === 'ready' ) {
throw new Error( 'Module has already been loaded: ' + module );
}
-
+
// Add styles
if ( $.isPlainObject( registry[module].style ) ) {
// 'media' type ignored, see documentation of mw.loader.implement
callback();
return;
}
-
+
addScript( arr[i], function() {
nestedAddScript( arr, callback, async, i + 1 );
}, async );
};
-
+
if ( $.isArray( script ) ) {
registry[module].state = 'loading';
nestedAddScript( script, markModuleReady, registry[module].async, 0 );
registry[module].state = 'error';
}
}
-
+
/**
* Adds a dependencies to the queue with optional callbacks to be run
* when the dependencies are ready or fail
*/
function request( dependencies, ready, error, async ) {
var regItemDeps, regItemDepLen, n;
-
+
// Allow calling by single module name
if ( typeof dependencies === 'string' ) {
dependencies = [dependencies];
// Work the queue
mw.loader.work();
}
-
+
function sortQuery(o) {
var sorted = {}, key, a = [];
for ( key in o ) {
}
return sorted;
}
-
+
/**
* Converts a module map of the form { foo: [ 'bar', 'baz' ], bar: [ 'baz, 'quux' ] }
* to a query string of the form foo.bar,baz|bar.baz,quux
}
return arr.join( '|' );
}
-
+
/**
* Asynchronously append a script tag to the end of the body
* that invokes load.php
// Append &* to avoid triggering the IE6 extension check
addScript( sourceLoadScript + '?' + $.param( request ) + '&*', null, async );
}
-
+
/* Public Methods */
return {
addStyleTag: addStyleTag,
source, group, g, i, modules, maxVersion, sourceLoadScript,
currReqBase, currReqBaseLength, moduleMap, l,
lastDotIndex, prefix, suffix, bytesAdded, async;
-
+
// Build a list of request parameters common to all requests.
reqBase = {
skin: mw.config.get( 'skin' ),
// Split module batch by source and by group.
splits = {};
maxQueryLength = mw.config.get( 'wgResourceLoaderMaxQueryLength', -1 );
-
+
// Appends a list of modules from the queue to the batch
for ( q = 0; q < queue.length; q += 1 ) {
// Only request modules which are registered
if ( !batch.length ) {
return;
}
-
+
// The queue has been processed into the batch, clear up the queue.
queue = [];
-
+
// Always order modules alphabetically to help reduce cache
// misses for otherwise identical content.
batch.sort();
-
+
// Split batch by source and by group.
for ( b = 0; b < batch.length; b += 1 ) {
bSource = registry[batch[b]].source;
bSourceGroup = splits[bSource][bGroup];
bSourceGroup[bSourceGroup.length] = batch[b];
}
-
+
// Clear the batch - this MUST happen before we append any
// script elements to the body or it's possible that a script
// will be locally cached, instantly load, and work the batch
// again, all before we've cleared it causing each request to
// include modules which are already loaded.
batch = [];
-
+
for ( source in splits ) {
-
+
sourceLoadScript = sources[source].loadScript;
-
+
for ( group in splits[source] ) {
-
+
// Cache access to currently selected list of
// modules for this group from this source.
modules = splits[source][group];
-
+
// Calculate the highest timestamp
maxVersion = 0;
for ( g = 0; g < modules.length; g += 1 ) {
maxVersion = registry[modules[g]].version;
}
}
-
+
currReqBase = $.extend( { 'version': formatVersionNumber( maxVersion ) }, reqBase );
currReqBaseLength = $.param( currReqBase ).length;
async = true;
// We may need to split up the request to honor the query string length limit,
// so build it piece by piece.
l = currReqBaseLength + 9; // '&modules='.length == 9
-
+
moduleMap = {}; // { prefix: [ suffixes ] }
-
+
for ( i = 0; i < modules.length; i += 1 ) {
// Determine how many bytes this module would add to the query string
lastDotIndex = modules[i].lastIndexOf( '.' );
bytesAdded = moduleMap[prefix] !== undefined
? suffix.length + 3 // '%2C'.length == 3
: modules[i].length + 3; // '%7C'.length == 3
-
+
// If the request would become too long, create a new one,
// but don't create empty requests
if ( maxQueryLength > 0 && !$.isEmptyObject( moduleMap ) && l + bytesAdded > maxQueryLength ) {
}
}
},
-
+
/**
* Register a source.
*
}
return true;
}
-
+
if ( sources[id] !== undefined ) {
throw new Error( 'source already registered: ' + id );
}
-
+
sources[id] = props;
-
+
return true;
},
-
+
/**
* Registers a module, letting the system know about it and its
* properties. Startup modules contain calls to this function.
registry[module].dependencies = dependencies;
}
},
-
+
/**
* Implements a module, giving the system a course of action to take
* upon loading. Results of a request for one or more modules contain
execute( module );
}
},
-
+
/**
* Executes a function as soon as one or more required modules are ready
*
request( dependencies, ready, error );
}
},
-
+
/**
* Loads an external script or one or more modules for future use
*
request( filtered, null, null, async );
return;
},
-
+
/**
* Changes the state of a module
*
registry[module].state = state;
}
},
-
+
/**
* Gets the version of a module
*
}
return null;
},
-
+
/**
* @deprecated since 1.18 use mw.loader.getVersion() instead
*/
version: function () {
return mw.loader.getVersion.apply( mw.loader, arguments );
},
-
+
/**
* Gets the state of a module
*
}
return null;
},
-
+
/**
* Get names of all registered modules.
*
return key;
} );
},
-
+
/**
* For backwards-compatibility with Squid-cached pages. Loads mw.user
*/
}
};
}() ),
-
+
/** HTML construction helper functions */
html: ( function () {
function escapeCallback( s ) {
escape: function ( s ) {
return s.replace( /['"<>&]/g, escapeCallback );
},
-
+
/**
* Wrapper object for raw HTML passed to mw.html.element().
* @constructor
Raw: function ( value ) {
this.value = value;
},
-
+
/**
* Wrapper object for CDATA element contents passed to mw.html.element()
* @constructor
Cdata: function ( value ) {
this.value = value;
},
-
+
/**
* Create an HTML element string, with safe escaping.
*
*/
element: function ( name, attrs, contents ) {
var v, attrName, s = '<' + name;
-
+
for ( attrName in attrs ) {
v = attrs[attrName];
// Convert name=true, to name=name
tokens: new Map()
}
};
-
+
}( jQuery ) );
// Alias $j to jQuery for backwards compatibility