And workaround <https://github.com/jshint/jshint/issues/2656>.
Bug: T111380
Change-Id: Ie478813fb8c39b4abfc46a92ed2d4e83af5abc88
hooks,
placeholder;
+ function safeActiveElement() {
+ // Avoid IE9 `document.activeElement` of death
+ // https://github.com/mathiasbynens/jquery-placeholder/pull/99
+ try {
+ return document.activeElement;
+ } catch (err) {}
+ }
+
+ function args(elem) {
+ // Return an object of element attributes
+ var newAttrs = {},
+ rinlinejQuery = /^jQuery\d+$/;
+ $.each(elem.attributes, function (i, attr) {
+ if (attr.specified && !rinlinejQuery.test(attr.name)) {
+ newAttrs[attr.name] = attr.value;
+ }
+ });
+ return newAttrs;
+ }
+
+ function clearPlaceholder(event, value) {
+ var input = this,
+ $input = $(input);
+ if (input.value === $input.attr('placeholder') && $input.hasClass('placeholder')) {
+ if ($input.data('placeholder-password')) {
+ $input = $input.hide().next().show().attr('id', $input.removeAttr('id').data('placeholder-id'));
+ // If `clearPlaceholder` was called from `$.valHooks.input.set`
+ if (event === true) {
+ $input[0].value = value;
+ return value;
+ }
+ $input.focus();
+ } else {
+ input.value = '';
+ $input.removeClass('placeholder');
+ if (input === safeActiveElement()) {
+ input.select();
+ }
+ }
+ }
+ }
+
+ function setPlaceholder() {
+ var $replacement,
+ input = this,
+ $input = $(input),
+ id = this.id;
+ if (!input.value) {
+ if (input.type === 'password') {
+ if (!$input.data('placeholder-textinput')) {
+ try {
+ $replacement = $input.clone().attr({ 'type': 'text' });
+ } catch (e) {
+ $replacement = $('<input>').attr($.extend(args(this), { 'type': 'text' }));
+ }
+ $replacement
+ .removeAttr('name')
+ .data({
+ 'placeholder-password': $input,
+ 'placeholder-id': id
+ })
+ .bind('focus.placeholder drop.placeholder', clearPlaceholder);
+ $input
+ .data({
+ 'placeholder-textinput': $replacement,
+ 'placeholder-id': id
+ })
+ .before($replacement);
+ }
+ $input = $input.removeAttr('id').hide().prev().attr('id', id).show();
+ // Note: `$input[0] != input` now!
+ }
+ $input.addClass('placeholder');
+ $input[0].value = $input.attr('placeholder');
+ } else {
+ $input.removeClass('placeholder');
+ }
+ }
+
+ function changePlaceholder(text) {
+ var hasArgs = arguments.length,
+ $input = this;
+ if (hasArgs) {
+ if ($input.attr('placeholder') !== text) {
+ $input.prop('placeholder', text);
+ if ($input.hasClass('placeholder')) {
+ $input[0].value = text;
+ }
+ }
+ }
+ }
+
if (isInputSupported && isTextareaSupported) {
placeholder = prototype.placeholder = function (text) {
});
}
-
- function args(elem) {
- // Return an object of element attributes
- var newAttrs = {},
- rinlinejQuery = /^jQuery\d+$/;
- $.each(elem.attributes, function (i, attr) {
- if (attr.specified && !rinlinejQuery.test(attr.name)) {
- newAttrs[attr.name] = attr.value;
- }
- });
- return newAttrs;
- }
-
- function clearPlaceholder(event, value) {
- var input = this,
- $input = $(input);
- if (input.value === $input.attr('placeholder') && $input.hasClass('placeholder')) {
- if ($input.data('placeholder-password')) {
- $input = $input.hide().next().show().attr('id', $input.removeAttr('id').data('placeholder-id'));
- // If `clearPlaceholder` was called from `$.valHooks.input.set`
- if (event === true) {
- $input[0].value = value;
- return value;
- }
- $input.focus();
- } else {
- input.value = '';
- $input.removeClass('placeholder');
- if (input === safeActiveElement()) {
- input.select();
- }
- }
- }
- }
-
- function setPlaceholder() {
- var $replacement,
- input = this,
- $input = $(input),
- id = this.id;
- if (!input.value) {
- if (input.type === 'password') {
- if (!$input.data('placeholder-textinput')) {
- try {
- $replacement = $input.clone().attr({ 'type': 'text' });
- } catch (e) {
- $replacement = $('<input>').attr($.extend(args(this), { 'type': 'text' }));
- }
- $replacement
- .removeAttr('name')
- .data({
- 'placeholder-password': $input,
- 'placeholder-id': id
- })
- .bind('focus.placeholder drop.placeholder', clearPlaceholder);
- $input
- .data({
- 'placeholder-textinput': $replacement,
- 'placeholder-id': id
- })
- .before($replacement);
- }
- $input = $input.removeAttr('id').hide().prev().attr('id', id).show();
- // Note: `$input[0] != input` now!
- }
- $input.addClass('placeholder');
- $input[0].value = $input.attr('placeholder');
- } else {
- $input.removeClass('placeholder');
- }
- }
-
- function safeActiveElement() {
- // Avoid IE9 `document.activeElement` of death
- // https://github.com/mathiasbynens/jquery-placeholder/pull/99
- try {
- return document.activeElement;
- } catch (err) {}
- }
-
- function changePlaceholder(text) {
- var hasArgs = arguments.length,
- $input = this;
- if (hasArgs) {
- if ($input.attr('placeholder') !== text) {
- $input.prop('placeholder', text);
- if ($input.hasClass('placeholder')) {
- $input[0].value = text;
- }
- }
- }
- }
-
}(jQuery));
// Make the spy inherit from the original so that its static methods are also
// visible in the spy (e.g. when we inject a check into mw.log, mw.log.warn
// must remain accessible).
+ // XXX: https://github.com/jshint/jshint/issues/2656
+ /*jshint ignore:start */
/*jshint proto:true */
spy.__proto__ = val;
+ /*jshint ignore:end */
// Objects are by reference, members (unless objects) are not.
obj[ key ] = spy;
}
}
+ function uniqueElements( array ) {
+ var uniques = [];
+ $.each( array, function ( index, elem ) {
+ if ( elem !== undefined && $.inArray( elem, uniques ) === -1 ) {
+ uniques.push( elem );
+ }
+ } );
+ return uniques;
+ }
+
function buildHeaders( table, msg ) {
var config = $( table ).data( 'tablesorter' ).config,
maxSeen = 0,
}
+ function isValueInArray( v, a ) {
+ var i,
+ len = a.length;
+ for ( i = 0; i < len; i++ ) {
+ if ( a[i][0] === v ) {
+ return true;
+ }
+ }
+ return false;
+ }
+
/**
* Sets the sort count of the columns that are not affected by the sorting to have them sorted
* in default (ascending) order when their header cell is clicked the next time.
} );
}
- function isValueInArray( v, a ) {
- var i,
- len = a.length;
- for ( i = 0; i < len; i++ ) {
- if ( a[i][0] === v ) {
- return true;
- }
- }
- return false;
- }
-
- function uniqueElements( array ) {
- var uniques = [];
- $.each( array, function ( index, elem ) {
- if ( elem !== undefined && $.inArray( elem, uniques ) === -1 ) {
- uniques.push( elem );
- }
- } );
- return uniques;
- }
-
function setHeadersCss( table, $headers, list, css, msg, columnToHeader ) {
// Remove all header information and reset titles to default message
$headers.removeClass( css[0] ).removeClass( css[1] ).attr( 'title', msg[1] );
cookieVal = mw.cookie.get( cookieKey ),
$div, id;
+ function removeConfirmation() {
+ $div.remove();
+ mw.hook( 'postEdit.afterRemoval' ).fire();
+ }
+
+ function fadeOutConfirmation() {
+ clearTimeout( id );
+ $div.find( '.postedit' ).addClass( 'postedit postedit-faded' );
+ setTimeout( removeConfirmation, 500 );
+
+ return false;
+ }
+
function showConfirmation( data ) {
data = data || {};
if ( data.message === undefined ) {
id = setTimeout( fadeOutConfirmation, 3000 );
}
- function fadeOutConfirmation() {
- clearTimeout( id );
- $div.find( '.postedit' ).addClass( 'postedit postedit-faded' );
- setTimeout( removeConfirmation, 500 );
-
- return false;
- }
-
- function removeConfirmation() {
- $div.remove();
- mw.hook( 'postEdit.afterRemoval' ).fire();
- }
-
mw.hook( 'postEdit' ).add( showConfirmation );
if ( config.wgAction === 'view' && cookieVal ) {
* @class mw.language
*/
+ /**
+ * Replicate a string 'n' times.
+ *
+ * @private
+ * @param {string} str The string to replicate
+ * @param {number} num Number of times to replicate the string
+ * @return {string}
+ */
+ function replicate( str, num ) {
+ if ( num <= 0 || !str ) {
+ return '';
+ }
+
+ var buf = [];
+ while ( num-- ) {
+ buf.push( str );
+ }
+ return buf.join( '' );
+ }
+
/**
* Pad a string to guarantee that it is at least `size` length by
* filling with the character `ch` at either the start or end of the
return end ? out + padStr : padStr + out;
}
- /**
- * Replicate a string 'n' times.
- *
- * @private
- * @param {string} str The string to replicate
- * @param {number} num Number of times to replicate the string
- * @return {string}
- */
- function replicate( str, num ) {
- if ( num <= 0 || !str ) {
- return '';
- }
-
- var buf = [];
- while ( num-- ) {
- buf.push( str );
- }
- return buf.join( '' );
- }
-
/**
* Apply numeric pattern to absolute value using options. Gives no
* consideration to local customs.
* See https://www.mediawiki.org/wiki/ResourceLoader/Legacy_JavaScript#wikibits.js
*/
- function importScript( page ) {
- var uri = mw.config.get( 'wgScript' ) + '?title=' +
- mw.util.wikiUrlencode( page ) +
- '&action=raw&ctype=text/javascript';
- return importScriptURI( uri );
- }
-
/**
* @deprecated since 1.17 Use mw.loader instead. Warnings added in 1.25.
*/
return s;
}
- function importStylesheet( page ) {
+ function importScript( page ) {
var uri = mw.config.get( 'wgScript' ) + '?title=' +
mw.util.wikiUrlencode( page ) +
- '&action=raw&ctype=text/css';
- return importStylesheetURI( uri );
+ '&action=raw&ctype=text/javascript';
+ return importScriptURI( uri );
}
/**
return l;
}
+ function importStylesheet( page ) {
+ var uri = mw.config.get( 'wgScript' ) + '?title=' +
+ mw.util.wikiUrlencode( page ) +
+ '&action=raw&ctype=text/css';
+ return importStylesheetURI( uri );
+ }
+
msg = 'Use mw.loader instead.';
mw.log.deprecate( win, 'loadedScripts', loadedScripts, msg );
mw.log.deprecate( win, 'importScriptURI', importScriptURI, msg );
* Implement AJAX navigation for multi-page images so the user may browse without a full page reload.
*/
( function ( mw, $ ) {
+ /*jshint latedef:false */
var jqXhr, $multipageimage, $spinner,
cache = {},
cacheOrder = [];
* @singleton
*/
( function ( mw, $ ) {
+ /*jshint latedef:false */
var uploadWarning, uploadLicense,
ajaxUploadDestCheck = mw.config.get( 'wgAjaxUploadDestCheck' ),
$license = $( '#wpLicense' );
return ( $.inArray( file.type, known ) !== -1 ) && file.size > 0 && file.size < tooHuge;
}
+ /**
+ * Format a file size attractively.
+ *
+ * TODO: Match numeric formatting
+ *
+ * @param {number} s
+ * @return {string}
+ */
+ function prettySize( s ) {
+ var sizeMsgs = ['size-bytes', 'size-kilobytes', 'size-megabytes', 'size-gigabytes'];
+ while ( s >= 1024 && sizeMsgs.length > 1 ) {
+ s /= 1024;
+ sizeMsgs = sizeMsgs.slice( 1 );
+ }
+ return mw.msg( sizeMsgs[0], Math.round( s ) );
+ }
+
/**
* Show a thumbnail preview of PNG, JPEG, GIF, and SVG files prior to upload
* in browsers supporting HTML5 FileAPI.
}
}
- /**
- * Format a file size attractively.
- *
- * TODO: Match numeric formatting
- *
- * @param {number} s
- * @return {string}
- */
- function prettySize( s ) {
- var sizeMsgs = ['size-bytes', 'size-kilobytes', 'size-megabytes', 'size-gigabytes'];
- while ( s >= 1024 && sizeMsgs.length > 1 ) {
- s /= 1024;
- sizeMsgs = sizeMsgs.slice( 1 );
- }
- return mw.msg( sizeMsgs[0], Math.round( s ) );
- }
-
/**
* Clear the file upload preview area.
*/
* @since 1.18
*/
( function ( mw, $ ) {
+ /*jshint latedef:false */
/**
* @class mw.Title
if ( val === undefined || val === null || val === '' ) {
return '';
}
+ /* jshint latedef:false */
return pre + ( raw ? val : mw.Uri.encode( val ) ) + post;
+ /* jshint latedef:true */
}
/**
* @param {boolean} [options.overrideKeys=false] Whether to let duplicate query parameters
* override each other (`true`) or automagically convert them to an array (`false`).
*/
+ /* jshint latedef:false */
function Uri( uri, options ) {
var prop,
defaultUri = getDefaultUri();
* @alternateClassName mediaWiki
* @singleton
*/
+/*jshint latedef:false */
/*global sha1 */
( function ( $ ) {
'use strict';
function setGlobalMapValue( map, key, value ) {
map.values[key] = value;
mw.log.deprecate(
- window,
- key,
- value,
- // Deprecation notice for mw.config globals (T58550, T72470)
- map === mw.config && 'Use mw.config instead.'
+ window,
+ key,
+ value,
+ // Deprecation notice for mw.config globals (T58550, T72470)
+ map === mw.config && 'Use mw.config instead.'
);
}
return sha1( hashes.join( '' ) ).slice( 0, 12 );
}
- /**
- * Resolve dependencies and detect circular references.
- *
- * @private
- * @param {string} module Name of the top-level module whose dependencies shall be
- * resolved and sorted.
- * @param {Array} resolved Returns a topological sort of the given module and its
- * dependencies, such that later modules depend on earlier modules. The array
- * contains the module names. If the array contains already some module names,
- * this function appends its result to the pre-existing array.
- * @param {Object} [unresolved] Hash used to track the current dependency
- * chain; used to report loops in the dependency graph.
- * @throws {Error} If any unregistered module or a dependency loop is encountered
- */
- function sortDependencies( module, resolved, unresolved ) {
- var n, deps, len, skip;
-
- if ( !hasOwn.call( registry, module ) ) {
- throw new Error( 'Unknown dependency: ' + module );
- }
-
- if ( registry[module].skip !== null ) {
- /*jshint evil:true */
- skip = new Function( registry[module].skip );
- registry[module].skip = null;
- if ( skip() ) {
- registry[module].skipped = true;
- registry[module].dependencies = [];
- registry[module].state = 'ready';
- handlePending( module );
- return;
- }
- }
-
- // Resolves dynamic loader function and replaces it with its own results
- if ( $.isFunction( registry[module].dependencies ) ) {
- registry[module].dependencies = registry[module].dependencies();
- // Ensures the module's dependencies are always in an array
- if ( typeof registry[module].dependencies !== 'object' ) {
- registry[module].dependencies = [registry[module].dependencies];
- }
- }
- if ( $.inArray( module, resolved ) !== -1 ) {
- // Module already resolved; nothing to do
- return;
- }
- // Create unresolved if not passed in
- if ( !unresolved ) {
- unresolved = {};
- }
- // Tracks down dependencies
- deps = registry[module].dependencies;
- len = deps.length;
- for ( n = 0; n < len; n += 1 ) {
- if ( $.inArray( deps[n], resolved ) === -1 ) {
- if ( unresolved[deps[n]] ) {
- throw new Error(
- 'Circular reference detected: ' + module +
- ' -> ' + deps[n]
- );
- }
-
- // Add to unresolved
- unresolved[module] = true;
- sortDependencies( deps[n], resolved, unresolved );
- delete unresolved[module];
- }
- }
- resolved[resolved.length] = module;
- }
-
- /**
- * Get a list of module names that a module depends on in their proper dependency
- * order.
- *
- * @private
- * @param {string[]} module Array of string module names
- * @return {Array} List of dependencies, including 'module'.
- */
- function resolve( modules ) {
- var resolved = [];
- $.each( modules, function ( idx, module ) {
- sortDependencies( module, resolved );
- } );
- return resolved;
- }
-
/**
* Determine whether all dependencies are in state 'ready', which means we may
* execute the module or job now.
}
}
+ /**
+ * Resolve dependencies and detect circular references.
+ *
+ * @private
+ * @param {string} module Name of the top-level module whose dependencies shall be
+ * resolved and sorted.
+ * @param {Array} resolved Returns a topological sort of the given module and its
+ * dependencies, such that later modules depend on earlier modules. The array
+ * contains the module names. If the array contains already some module names,
+ * this function appends its result to the pre-existing array.
+ * @param {Object} [unresolved] Hash used to track the current dependency
+ * chain; used to report loops in the dependency graph.
+ * @throws {Error} If any unregistered module or a dependency loop is encountered
+ */
+ function sortDependencies( module, resolved, unresolved ) {
+ var n, deps, len, skip;
+
+ if ( !hasOwn.call( registry, module ) ) {
+ throw new Error( 'Unknown dependency: ' + module );
+ }
+
+ if ( registry[module].skip !== null ) {
+ /*jshint evil:true */
+ skip = new Function( registry[module].skip );
+ registry[module].skip = null;
+ if ( skip() ) {
+ registry[module].skipped = true;
+ registry[module].dependencies = [];
+ registry[module].state = 'ready';
+ handlePending( module );
+ return;
+ }
+ }
+
+ // Resolves dynamic loader function and replaces it with its own results
+ if ( $.isFunction( registry[module].dependencies ) ) {
+ registry[module].dependencies = registry[module].dependencies();
+ // Ensures the module's dependencies are always in an array
+ if ( typeof registry[module].dependencies !== 'object' ) {
+ registry[module].dependencies = [registry[module].dependencies];
+ }
+ }
+ if ( $.inArray( module, resolved ) !== -1 ) {
+ // Module already resolved; nothing to do
+ return;
+ }
+ // Create unresolved if not passed in
+ if ( !unresolved ) {
+ unresolved = {};
+ }
+ // Tracks down dependencies
+ deps = registry[module].dependencies;
+ len = deps.length;
+ for ( n = 0; n < len; n += 1 ) {
+ if ( $.inArray( deps[n], resolved ) === -1 ) {
+ if ( unresolved[deps[n]] ) {
+ throw new Error(
+ 'Circular reference detected: ' + module +
+ ' -> ' + deps[n]
+ );
+ }
+
+ // Add to unresolved
+ unresolved[module] = true;
+ sortDependencies( deps[n], resolved, unresolved );
+ delete unresolved[module];
+ }
+ }
+ resolved[resolved.length] = module;
+ }
+
+ /**
+ * Get a list of module names that a module depends on in their proper dependency
+ * order.
+ *
+ * @private
+ * @param {string[]} module Array of string module names
+ * @return {Array} List of dependencies, including 'module'.
+ */
+ function resolve( modules ) {
+ var resolved = [];
+ $.each( modules, function ( idx, module ) {
+ sortDependencies( module, resolved );
+ } );
+ return resolved;
+ }
+
/**
* Load and execute a script with callback.
*
* @param {string} module Module name to execute
*/
function execute( module ) {
- var key, value, media, i, urls, cssHandle, checkCssHandles,
+ var key, value, media, i, urls, cssHandle, checkCssHandles, runScript,
cssHandlesRegistered = false;
if ( !hasOwn.call( registry, module ) ) {
el.href = url;
}
- function runScript() {
+ runScript = function () {
var script, markModuleReady, nestedAddScript, legacyWait,
// Expand to include dependencies since we have to exclude both legacy modules
// and their dependencies from the legacyWait (to prevent a circular dependency).
mw.track( 'resourceloader.exception', { exception: e, module: module, source: 'module-execute' } );
handlePending( module );
}
- }
+ };
// This used to be inside runScript, but since that is now fired asychronously
// (after CSS is loaded) we need to set it here right away. It is crucial that
* @return
*/
function process( tasks, complete ) {
+ /*jshint latedef:false */
function abort() {
tasks.splice( 0, tasks.length );
next();