* @class mw
*/
mw = {
- redefineFallbacksForTest: function () {
- if ( !window.QUnit ) {
- throw new Error( 'Not allowed' );
- }
- defineFallbacks();
- },
+ redefineFallbacksForTest: window.QUnit && defineFallbacks,
/**
* Get the current time, measured in milliseconds since January 1, 1970 (UTC).
*/
config: new Map( $VARS.wgLegacyJavaScriptGlobals ),
- /**
- * Empty object for third-party libraries, for cases where you don't
- * want to add a new global, or the global is bad and needs containment
- * or wrapping.
- *
- * @property
- */
- libs: {},
-
/**
* Store for messages.
*
* // From mw.loader.register()
* 'version': '########' (hash)
* 'dependencies': ['required.foo', 'bar.also', ...]
- * 'group': 'somegroup', (or) null
+ * 'group': string, integer, (or) null
* 'source': 'local', (or) 'anotherwiki'
* 'skip': 'return !!window.Example', (or) null, (or) boolean result of skip
* 'module': export Object
}
if ( !hasOwn.call( scriptFiles, fileName ) ) {
- throw new Error( 'Cannot require() undefined file ' + fileName );
+ throw new Error( 'Cannot require undefined file ' + fileName );
}
if ( hasOwn.call( moduleObj.packageExports, fileName ) ) {
// File has already been executed, return the cached result
dependencies.forEach( function ( module ) {
// Only queue modules that are still in the initial 'registered' state
- // (not ones already loading, ready or error).
+ // (e.g. not ones already loading or loaded etc.).
if ( registry[ module ].state === 'registered' && queue.indexOf( module ) === -1 ) {
- // Private modules must be embedded in the page. Don't bother queuing
- // these as the server will deny them anyway (T101806).
- if ( registry[ module ].group === 'private' ) {
- setAndPropagate( module, 'error' );
- } else {
- queue.push( module );
- }
+ queue.push( module );
}
} );
cssPending = 0;
if ( registry[ module ].state !== 'loaded' ) {
- throw new Error( 'Module in state "' + registry[ module ].state + '" may not be executed: ' + module );
+ throw new Error( 'Module in state "' + registry[ module ].state + '" may not execute: ' + module );
}
registry[ module ].state = 'executing';
} else {
mainScript = script.files[ script.main ];
if ( typeof mainScript !== 'function' ) {
- throw new Error( 'Main file ' + script.main + ' in module ' + module +
- ' must be of type function, found ' + typeof mainScript );
+ throw new Error( 'Main file in module ' + module + ' must be a function' );
}
// jQuery parameters are not passed for multi-file modules
mainScript(
// Optimisation: Inherit (Object.create), not copy ($.extend)
currReqBase = Object.create( reqBase );
// User modules require a user name in the query string.
- if ( group === 'user' && mw.config.get( 'wgUserName' ) !== null ) {
+ if ( group === $VARS.groupUser && mw.config.get( 'wgUserName' ) !== null ) {
currReqBase.user = mw.config.get( 'wgUserName' );
}
packageExports: {},
version: String( version || '' ),
dependencies: dependencies || [],
- group: typeof group === 'string' ? group : null,
+ group: typeof group === 'undefined' ? null : group,
source: typeof source === 'string' ? source : 'local',
state: 'registered',
skip: typeof skip === 'string' ? skip : null
* @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.
+ * @throws {Error} If type is invalid
*/
load: function ( modules, type ) {
if ( typeof modules === 'string' && /^(https?:)?\/?\//.test( modules ) ) {
addScript( modules );
} else {
// Unknown type
- throw new Error( 'type must be text/css or text/javascript, found ' + type );
+ throw new Error( 'Invalid type ' + type );
}
} else {
// One or more modules
// Whether the store is in use on this page.
enabled: null,
- // Modules whose string representation exceeds 100 kB are
- // ineligible for storage. See bug T66721.
- MODULE_SIZE_MAX: 100 * 1000,
+ // Modules whose serialised form exceeds 100 kB won't be stored (T66721).
+ MODULE_SIZE_MAX: 1e5,
// The contents of the store, mapping '[name]@[version]' keys
// to module implementations.
* @return {Object} Module store contents.
*/
toJSON: function () {
- return { items: mw.loader.store.items, vary: mw.loader.store.vary };
+ return {
+ items: mw.loader.store.items,
+ vary: mw.loader.store.vary,
+ // Store with 1e7 ms accuracy (1e4 seconds, or ~ 2.7 hours),
+ // which is enough for the purpose of expiring after ~ 30 days.
+ asOf: Math.ceil( Date.now() / 1e7 )
+ };
},
/**
this.enabled = true;
// If null, JSON.parse() will cast to string and re-parse, still null.
data = JSON.parse( raw );
- if ( data && typeof data.items === 'object' && data.vary === this.vary ) {
+ if ( data &&
+ typeof data.items === 'object' &&
+ data.vary === this.vary &&
+ // Only use if it's been less than 30 days since the data was written
+ // 30 days = 2,592,000 s = 2,592,000,000 ms = ± 259e7 ms
+ Date.now() < ( data.asOf * 1e7 ) + 259e7
+ ) {
+ // The data is not corrupt, matches our vary context, and has not expired.
this.items = data.items;
return;
}
descriptor.state !== 'ready' ||
// Unversioned, private, or site-/user-specific
!descriptor.version ||
- descriptor.group === 'private' ||
- descriptor.group === 'user' ||
+ descriptor.group === $VARS.groupPrivate ||
+ descriptor.group === $VARS.groupUser ||
// Partial descriptor
// (e.g. skipped module, or style module with state=ready)
[ descriptor.script, descriptor.style, descriptor.messages,
* @property {mw.Map}
*/
tokens: new Map()
- },
-
- // OOUI widgets specific to MediaWiki
- widgets: {}
+ }
};