* values with microsecond precision that are guaranteed to be monotonic. On all other browsers,
* it will fall back to using `Date`.
*
- * @returns {number} Current time
+ * @return {number} Current time
*/
now: ( function () {
var perf = window.performance,
} );
},
- /**
- * Dummy placeholder for {@link mw.log}
- * @method
- */
- log: ( function () {
- var log = function () {};
- log.warn = function () {};
- log.deprecate = function ( obj, key, val ) {
- obj[key] = val;
- };
- return log;
- }() ),
-
// Make the Map constructor publicly available.
Map: Map,
return mw.message.apply( mw.message, arguments ).toString();
},
+ /**
+ * Dummy placeholder for {@link mw.log}
+ * @method
+ */
+ log: ( function () {
+ // Also update the restoration of methods in mediawiki.log.js
+ // when adding or removing methods here.
+ var log = function () {};
+
+ /**
+ * @class mw.log
+ * @singleton
+ */
+
+ /**
+ * Write a message the console's warning channel.
+ * Also logs a stacktrace for easier debugging.
+ * Each action is silently ignored if the browser doesn't support it.
+ *
+ * @param {string...} msg Messages to output to console
+ */
+ log.warn = function () {
+ var console = window.console;
+ if ( console && console.warn ) {
+ console.warn.apply( console, arguments );
+ if ( console.trace ) {
+ console.trace();
+ }
+ }
+ };
+
+ /**
+ * Create a property in a host object that, when accessed, will produce
+ * a deprecation warning in the console with backtrace.
+ *
+ * @param {Object} obj Host object of deprecated property
+ * @param {string} key Name of property to create in `obj`
+ * @param {Mixed} val The value this property should return when accessed
+ * @param {string} [msg] Optional text to include in the deprecation message.
+ */
+ log.deprecate = !Object.defineProperty ? function ( obj, key, val ) {
+ obj[key] = val;
+ } : function ( obj, key, val, msg ) {
+ msg = 'Use of "' + key + '" is deprecated.' + ( msg ? ( ' ' + msg ) : '' );
+ try {
+ Object.defineProperty( obj, key, {
+ configurable: true,
+ enumerable: true,
+ get: function () {
+ mw.track( 'mw.deprecate', key );
+ mw.log.warn( msg );
+ return val;
+ },
+ set: function ( newVal ) {
+ mw.track( 'mw.deprecate', key );
+ mw.log.warn( msg );
+ val = newVal;
+ }
+ } );
+ } catch ( err ) {
+ // IE8 can throw on Object.defineProperty
+ obj[key] = val;
+ }
+ };
+
+ return log;
+ }() ),
+
/**
* Client-side module loader which integrates with the MediaWiki ResourceLoader
* @class mw.loader
return;
}
- // By default, always create a new <style>. Appending text
- // to a <style> tag means the contents have to be re-parsed (bug 45810).
- // Except, of course, in IE below 9, in there we default to
- // re-using and appending to a <style> tag due to the
- // IE stylesheet limit (bug 31676).
+ // By default, always create a new <style>. Appending text to a <style>
+ // tag is bad as it means the contents have to be re-parsed (bug 45810).
+ //
+ // Except, of course, in IE 9 and below. In there we default to re-using and
+ // appending to a <style> tag due to the IE stylesheet limit (bug 31676).
if ( 'documentMode' in document && document.documentMode <= 9 ) {
$style = getMarker().prev();
* @private
* @param {string} src URL to script, will be used as the src attribute in the script tag
* @param {Function} [callback] Callback which will be run when the script is done
+ * @param {boolean} [async=false] Whether to load modules asynchronously.
+ * Ignored (and defaulted to `true`) if the document-ready event has already occurred.
*/
function addScript( src, callback, async ) {
/*jshint evil:true */
*/
function addLink( media, url ) {
var el = document.createElement( 'link' );
- getMarker().before( el ); // IE: Insert in dom before setting href
+ // For IE: Insert in document *before* setting href
+ getMarker().before( el );
el.rel = 'stylesheet';
if ( media && media !== 'all' ) {
el.media = media;
}
+ // If you end up here from an IE exception "SCRIPT: Invalid property value.",
+ // see #addEmbeddedCSS, bug 31676, and bug 47277 for details.
el.href = url;
}
* @param {string|string[]} dependencies Module name or array of string module names
* @param {Function} [ready] Callback to execute when all dependencies are ready
* @param {Function} [error] Callback to execute when any dependency fails
- * @param {boolean} [async] If true, load modules asynchronously even if
- * document ready has not yet occurred.
+ * @param {boolean} [async=false] Whether to load modules asynchronously.
+ * Ignored (and defaulted to `true`) if the document-ready event has already occurred.
*/
function request( dependencies, ready, error, async ) {
var n;
* @param {Object} moduleMap Module map, see #buildModulesString
* @param {Object} currReqBase Object with other parameters (other than 'modules') to use in the request
* @param {string} sourceLoadScript URL of load.php
- * @param {boolean} async If true, use an asynchronous request even if document ready has not yet occurred
+ * @param {boolean} async Whether to load modules asynchronously.
+ * Ignored (and defaulted to `true`) if the document-ready event has already occurred.
*/
function doRequest( moduleMap, currReqBase, sourceLoadScript, async ) {
var request = $.extend(
currReqBase
);
request = sortQuery( request );
- // Asynchronously append a script tag to the end of the body
// Append &* to avoid triggering the IE6 extension check
addScript( sourceLoadScript + '?' + $.param( request ) + '&*', null, async );
}
*/
work: function () {
var reqBase, splits, maxQueryLength, q, b, bSource, bGroup, bSourceGroup,
- source, concatSource, group, g, i, modules, maxVersion, sourceLoadScript,
+ source, concatSource, origBatch, group, g, i, modules, maxVersion, sourceLoadScript,
currReqBase, currReqBaseLength, moduleMap, l,
lastDotIndex, prefix, suffix, bytesAdded, async;
mw.loader.store.init();
if ( mw.loader.store.enabled ) {
concatSource = [];
+ origBatch = batch;
batch = $.grep( batch, function ( module ) {
var source = mw.loader.store.get( module );
if ( source ) {
}
return true;
} );
- $.globalEval( concatSource.join( ';' ) );
+ try {
+ $.globalEval( concatSource.join( ';' ) );
+ } catch ( err ) {
+ // Not good, the cached mw.loader.implement calls failed! This should
+ // never happen, barring ResourceLoader bugs, browser bugs and PEBKACs.
+ // Depending on how corrupt the string is, it is likely that some
+ // modules' implement() succeeded while the ones after the error will
+ // never run and leave their modules in the 'loading' state forever.
+
+ // Since this is an error not caused by an individual module but by
+ // something that infected the implement call itself, don't take any
+ // risks and clear everything in this cache.
+ mw.loader.store.clear();
+ // Re-add the ones still pending back to the batch and let the server
+ // repopulate these modules to the cache.
+ // This means that at most one module will be useless (the one that had
+ // the error) instead of all of them.
+ log( 'Error while evaluating data from mw.loader.store', err );
+ origBatch = $.grep( origBatch, function ( module ) {
+ return registry[module].state === 'loading';
+ } );
+ batch = batch.concat( origBatch );
+ }
}
// Early exit if there's nothing to load...
* @param {string} [type='text/javascript'] mime-type to use if calling with a URL of an
* external script or style; acceptable values are "text/css" and
* "text/javascript"; if no type is provided, text/javascript is assumed.
- * @param {boolean} [async] If true, load modules asynchronously
- * even if document ready has not yet occurred. If false, block before
- * document ready and load async after. If not set, true will be
- * assumed if loading a URL, and false will be assumed otherwise.
+ * @param {boolean} [async] Whether to load modules asynchronously.
+ * Ignored (and defaulted to `true`) if the document-ready event has already occurred.
+ * Defaults to `true` if loading a URL, `false` otherwise.
*/
load: function ( modules, type, async ) {
var filtered, m, module, l;
}
},
+ /**
+ * Clear the entire module store right now.
+ */
+ clear: function () {
+ mw.loader.store.items = {};
+ localStorage.removeItem( mw.loader.store.getStoreKey() );
+ },
+
/**
* Sync modules to localStorage.
*
}( jQuery ) );
// Alias $j to jQuery for backwards compatibility
-window.$j = jQuery;
+// @deprecated since 1.23 Use $ or jQuery instead
+mw.log.deprecate( window, '$j', jQuery, 'Use $ or jQuery instead.' );
// Attach to window and globally alias
window.mw = window.mediaWiki = mw;