/* eslint-enable no-bitwise */
}
- StringSet = window.Set || ( function () {
- /**
- * @private
- * @class
- */
- function StringSet() {
- this.set = {};
- }
- StringSet.prototype.add = function ( value ) {
- this.set[ value ] = true;
- };
- StringSet.prototype.has = function ( value ) {
- return this.set.hasOwnProperty( value );
- };
- return StringSet;
- }() );
+ function defineFallbacks() {
+ // <https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Global_Objects/Set>
+ StringSet = window.Set || ( function () {
+ /**
+ * @private
+ * @class
+ */
+ function StringSet() {
+ this.set = {};
+ }
+ StringSet.prototype.add = function ( value ) {
+ this.set[ value ] = true;
+ };
+ StringSet.prototype.has = function ( value ) {
+ return hasOwn.call( this.set, value );
+ };
+ return StringSet;
+ }() );
+ }
/**
* Create an object that can be read from or written to via methods that allow
* copied in one direction only. Changes to globals do not reflect in the map.
*/
function Map( global ) {
- this.internalValues = {};
+ this.values = {};
if ( global === true ) {
-
// Override #set to also set the global variable
this.set = function ( selection, value ) {
var s;
return false;
};
}
-
- // Deprecated since MediaWiki 1.28
- log.deprecate(
- this,
- 'values',
- this.internalValues,
- 'mw.Map#values is deprecated. Use mw.Map#get() instead.',
- 'Map-values'
- );
}
/**
* @param {Mixed} value
*/
function setGlobalMapValue( map, key, value ) {
- map.internalValues[ key ] = value;
+ map.values[ key ] = value;
log.deprecate(
window,
key,
*
* @param {string|Array} [selection] Key or array of keys to retrieve values for.
* @param {Mixed} [fallback=null] Value for keys that don't exist.
- * @return {Mixed|Object| null} If selection was a string, returns the value,
+ * @return {Mixed|Object|null} If selection was a string, returns the value,
* If selection was an array, returns an object of key/values.
- * If no selection is passed, the internal container is returned. (Beware that,
- * as is the default in JavaScript, the object is returned by reference.)
+ * If no selection is passed, a new object with all key/values is returned.
*/
get: function ( selection, fallback ) {
var results, i;
- // If we only do this in the `return` block, it'll fail for the
- // call to get() from the mutli-selection block.
fallback = arguments.length > 1 ? fallback : null;
- if ( $.isArray( selection ) ) {
- selection = slice.call( selection );
+ if ( Array.isArray( selection ) ) {
results = {};
for ( i = 0; i < selection.length; i++ ) {
- results[ selection[ i ] ] = this.get( selection[ i ], fallback );
+ if ( typeof selection[ i ] === 'string' ) {
+ results[ selection[ i ] ] = hasOwn.call( this.values, selection[ i ] ) ?
+ this.values[ selection[ i ] ] :
+ fallback;
+ }
}
return results;
}
if ( typeof selection === 'string' ) {
- if ( !hasOwn.call( this.internalValues, selection ) ) {
- return fallback;
- }
- return this.internalValues[ selection ];
+ return hasOwn.call( this.values, selection ) ?
+ this.values[ selection ] :
+ fallback;
}
if ( selection === undefined ) {
- return this.internalValues;
+ results = {};
+ for ( i in this.values ) {
+ results[ i ] = this.values[ i ];
+ }
+ return results;
}
// Invalid selection key
- return null;
+ return fallback;
},
/**
if ( $.isPlainObject( selection ) ) {
for ( s in selection ) {
- this.internalValues[ s ] = selection[ s ];
+ this.values[ s ] = selection[ s ];
}
return true;
}
if ( typeof selection === 'string' && arguments.length > 1 ) {
- this.internalValues[ selection ] = value;
+ this.values[ selection ] = value;
return true;
}
return false;
* @return {boolean} True if the key(s) exist
*/
exists: function ( selection ) {
- var s;
-
- if ( $.isArray( selection ) ) {
- for ( s = 0; s < selection.length; s++ ) {
- if ( typeof selection[ s ] !== 'string' || !hasOwn.call( this.internalValues, selection[ s ] ) ) {
+ var i;
+ if ( Array.isArray( selection ) ) {
+ for ( i = 0; i < selection.length; i++ ) {
+ if ( typeof selection[ i ] !== 'string' || !hasOwn.call( this.values, selection[ i ] ) ) {
return false;
}
}
return true;
}
- return typeof selection === 'string' && hasOwn.call( this.internalValues, selection );
+ return typeof selection === 'string' && hasOwn.call( this.values, selection );
}
};
}
};
+ defineFallbacks();
+
/* eslint-disable no-console */
log = ( function () {
- // Also update the restoration of methods in mediawiki.log.js
- // when adding or removing methods here.
+ /**
+ * Write a verbose message to the browser's console in debug mode.
+ *
+ * This method is mainly intended for verbose logging. It is a no-op in production mode.
+ * In ResourceLoader debug mode, it will use the browser's console if available, with
+ * fallback to creating a console interface in the DOM and logging messages there.
+ *
+ * See {@link mw.log} for other logging methods.
+ *
+ * @member mw
+ * @param {...string} msg Messages to output to console.
+ */
var log = function () {},
console = window.console;
+ // Note: Keep list of methods in sync with restoration in mediawiki.log.js
+ // when adding or removing mw.log methods below!
+
/**
+ * Collection of methods to help log messages to the console.
+ *
* @class mw.log
* @singleton
*/
/**
- * Write a message to the console's warning channel.
- * Actions not supported by the browser console are silently ignored.
+ * Write a message to the browser console's warning channel.
+ *
+ * This method is a no-op in browsers that don't implement the Console API.
*
* @param {...string} msg Messages to output to console
*/
$.noop;
/**
- * Write a message to the console's error channel.
+ * Write a message to the browser console's error channel.
*
- * Most browsers provide a stacktrace by default if the argument
- * is a caught Error object.
+ * Most browsers also print a stacktrace when calling this method if the
+ * argument is an Error object.
+ *
+ * This method is a no-op in browsers that don't implement the Console API.
*
* @since 1.26
* @param {Error|...string} msg Messages to output to console
$.noop;
/**
- * Create a property in a host object that, when accessed, will produce
+ * Create a property on a host object that, when accessed, will produce
* a deprecation warning in the console.
*
* @param {Object} obj Host object of deprecated property
* @class mw
*/
mw = {
+ redefineFallbacksForTest: function () {
+ if ( !window.QUnit ) {
+ throw new Error( 'Reset not allowed outside unit tests' );
+ }
+ defineFallbacks();
+ },
/**
* Get the current time, measured in milliseconds since January 1, 1970 (UTC).
return mw.message.apply( mw.message, arguments ).toString();
},
- /**
- * No-op dummy placeholder for {@link mw.log} in debug mode.
- *
- * @method
- */
+ // Expose mw.log
log: log,
/**
cssBuffer = '',
cssBufferTimer = null,
cssCallbacks = $.Callbacks(),
- isIE9 = document.documentMode === 9,
rAF = window.requestAnimationFrame || setTimeout;
function getMarker() {
* @param {Function} [callback]
*/
function addEmbeddedCSS( cssText, callback ) {
- var $style, styleEl;
-
function fireCallbacks() {
var oldCallbacks = cssCallbacks;
// Reset cssCallbacks variable so it's not polluted by any calls to
cssBuffer = '';
}
- // By default, always create a new <style>. Appending text to a <style> tag is
- // is a performance anti-pattern as it requires CSS to be reparsed (T47810).
- //
- // Support: IE 6-9
- // Try to re-use existing <style> tags due to the IE stylesheet limit (T33676).
- if ( isIE9 ) {
- $style = $( getMarker() ).prev();
- // Verify that the element before the marker actually is a <style> tag created
- // by mw.loader (not some other style tag, or e.g. a <meta> tag).
- if ( $style.data( 'ResourceLoaderDynamicStyleTag' ) ) {
- styleEl = $style[ 0 ];
- styleEl.appendChild( document.createTextNode( cssText ) );
- fireCallbacks();
- return;
- }
- // Else: No existing tag to reuse. Continue below and create the first one.
- }
-
- $style = $( newStyleTag( cssText, getMarker() ) );
-
- if ( isIE9 ) {
- $style.data( 'ResourceLoaderDynamicStyleTag', true );
- }
+ $( newStyleTag( cssText, getMarker() ) );
fireCallbacks();
}
* @return {string} Hash of concatenated version hashes.
*/
function getCombinedVersion( modules ) {
- var hashes = $.map( modules, function ( module ) {
+ var hashes = modules.map( function ( module ) {
return registry[ module ].version;
} );
return fnv132( hashes.join( '' ) );
el.media = media;
}
// If you end up here from an IE exception "SCRIPT: Invalid property value.",
- // see #addEmbeddedCSS, T33676, and T49277 for details.
+ // see #addEmbeddedCSS, T33676, T43331, and T49277 for details.
el.href = url;
$( getMarker() ).before( el );
legacyWait.always( function () {
try {
- if ( $.isArray( script ) ) {
+ if ( Array.isArray( script ) ) {
nestedAddScript( script, markModuleReady, 0 );
} else if ( typeof script === 'function' ) {
// Pass jQuery twice so that the signature of the closure which wraps
// Array of css strings in key 'css',
// or back-compat array of urls from media-type
- if ( $.isArray( value ) ) {
+ if ( Array.isArray( value ) ) {
for ( i = 0; i < value.length; i++ ) {
if ( key === 'bc-url' ) {
// back-compat: { <media>: [url, ..] }
// "https://example.org/x.js", "http://example.org/x.js", "//example.org/x.js", "/x.js"
if ( /^(https?:)?\/?\//.test( modules ) ) {
if ( type === 'text/css' ) {
- // Support: IE 7-8
- // Use properties instead of attributes as IE throws security
- // warnings when inserting a <link> tag with a protocol-relative
- // URL set though attributes - when on HTTPS. See T43331.
l = document.createElement( 'link' );
l.rel = 'stylesheet';
l.href = modules;
* @return {Array}
*/
getModuleNames: function () {
- return $.map( registry, function ( i, key ) {
- return key;
- } );
+ return Object.keys( registry );
},
/**
// for all loading modules. If one fails, fall back to tracking each module
// separately via $.when(), this is expensive.
loading = mw.loader.using( loading ).then( null, function () {
- var all = $.map( loading, function ( module ) {
+ var all = loading.map( function ( module ) {
return mw.loader.using( module ).then( null, function () {
return $.Deferred().resolve();
} );