From: jenkins-bot Date: Fri, 14 Sep 2018 01:40:56 +0000 (+0000) Subject: Merge "mediawiki.language: Use the 'mw' global" X-Git-Tag: 1.34.0-rc.0~4092 X-Git-Url: https://git.cyclocoop.org/%7B%24admin_url%7Dmembres/cotisations/rappels.php?a=commitdiff_plain;h=bf24c891968c184295ba9fa13291e8e386d0df0a;hp=8889c6a80c22db0687f7ed8f9cc7f9f5f985b584;p=lhc%2Fweb%2Fwiklou.git Merge "mediawiki.language: Use the 'mw' global" --- diff --git a/maintenance/resources/foreign-resources.yaml b/maintenance/resources/foreign-resources.yaml index a54f1fd790..6ac354a051 100644 --- a/maintenance/resources/foreign-resources.yaml +++ b/maintenance/resources/foreign-resources.yaml @@ -39,6 +39,22 @@ CLDRPluralRuleParser: src: https://raw.githubusercontent.com/santhoshtr/CLDRPluralRuleParser/v1.1.3/src/CLDRPluralRuleParser.js integrity: sha384-Y0qxTEDVQgh+N5In+vLbZLL2H7PEROnicj8vxof0mxR8kXcGysGE6OcF+cS+Ao0u +easy-deflate: + type: multi-file + files: + deflate.js: + src: https://raw.githubusercontent.com/edg2s/Easy-Deflate/7a6056e5302f6f385ff2efa60afda45b4ad81e51/deflate.js + integrity: sha384-sHnZLDSWMUhA2w9ygkzCK8YFvoh/fQKY6lXMbvmrYzjuNURiLB0DZFCDNMpGyZ77 + easydeflate.js: + src: https://raw.githubusercontent.com/edg2s/Easy-Deflate/7a6056e5302f6f385ff2efa60afda45b4ad81e51/easydeflate.js + integrity: sha384-EwPfP2RMkDPa1HkzQsXgzTsy1KEjcIzQPA1HDS/JPHjvEMvVUsCxWwm1oXql/jk2 + inflate.js: + src: https://raw.githubusercontent.com/edg2s/Easy-Deflate/7a6056e5302f6f385ff2efa60afda45b4ad81e51/inflate.js + integrity: sha384-hMg44Hw424mUYvmzKl0JT4J8UU/1YYhTiGRtR0YX/MXNLK9qWTK0d62FBCDGxmxw + README.md: + src: https://raw.githubusercontent.com/edg2s/Easy-Deflate/7a6056e5302f6f385ff2efa60afda45b4ad81e51/README.md + integrity: sha384-6kwcfCLivvqXBZy2ATyya+mTVWLk3eaQyBdC6tbpBtkygnBrM2SNkq3jz/l7IkvP + html5shiv: type: file src: https://raw.githubusercontent.com/aFarkas/html5shiv/3.7.3/src/html5shiv.js diff --git a/resources/src/mediawiki.language/mediawiki.language.js b/resources/src/mediawiki.language/mediawiki.language.js index 45863a3e33..7cf3eaef16 100644 --- a/resources/src/mediawiki.language/mediawiki.language.js +++ b/resources/src/mediawiki.language/mediawiki.language.js @@ -8,34 +8,6 @@ */ $.extend( mw.language, { - /** - * Process the PLURAL template substitution - * - * @private - * @param {Object} template Template object - * @param {string} template.title - * @param {Array} template.parameters - * @return {string} - */ - procPLURAL: function ( template ) { - var count; - if ( template.title && template.parameters && mw.language.convertPlural ) { - // Check if we have forms to replace - if ( template.parameters.length === 0 ) { - return ''; - } - // Restore the count into a Number ( if it got converted earlier ) - count = mw.language.convertNumber( template.title, true ); - // Do convertPlural call - return mw.language.convertPlural( parseInt( count, 10 ), template.parameters ); - } - // Could not process plural return first form or nothing - if ( template.parameters[ 0 ] ) { - return template.parameters[ 0 ]; - } - return ''; - }, - /** * Plural form transformations, needed for some languages. * diff --git a/resources/src/startup/mediawiki.js b/resources/src/startup/mediawiki.js index ba8869bd28..c16948703b 100644 --- a/resources/src/startup/mediawiki.js +++ b/resources/src/startup/mediawiki.js @@ -569,8 +569,8 @@ * The contents are then stashed in the registry via mw.loader#implement. * - `loaded`: * The module has been loaded from the server and stashed via mw.loader#implement. - * If the module has no more dependencies in-flight, the module will be executed - * immediately. Otherwise execution is deferred, controlled via #handlePending. + * Once the module has no more dependencies in-flight, the module will be executed, + * controlled via #requestPropagation and #doPropagation. * - `executing`: * The module is being executed. * - `ready`: @@ -605,8 +605,7 @@ /** * List of callback jobs waiting for modules to be ready. * - * Jobs are created by #enqueue() and run by #handlePending(). - * + * Jobs are created by #enqueue() and run by #doPropagation(). * Typically when a job is created for a module, the job's dependencies contain * both the required module and all its recursive dependencies. * @@ -623,6 +622,10 @@ */ jobs = [], + // For #requestPropagation() and #doPropagation() + willPropagate = false, + errorModules = [], + /** * @private * @property {Array} baseModules @@ -781,86 +784,133 @@ } /** - * A module has entered state 'ready', 'error', or 'missing'. Automatically update - * pending jobs and modules that depend upon this module. If the given module failed, - * propagate the 'error' state up the dependency tree. Otherwise, go ahead and execute - * all jobs/modules now having their dependencies satisfied. + * Handle propagation of module state changes and reactions to them. * - * Jobs that depend on a failed module, will have their error callback ran (if any). + * - When a module reaches a failure state, this should be propagated to + * modules that depend on the failed module. + * - When a module reaches a final state, pending job callbacks for the + * module from mw.loader.using() should be called. + * - When a module reaches the 'ready' state from #execute(), consider + * executing dependant modules now having their dependencies satisfied. + * - When a module reaches the 'loaded' state from mw.loader.implement, + * consider executing it, if it has no unsatisfied dependencies. * * @private - * @param {string} module Name of module that entered one of the states 'ready', 'error', or 'missing'. */ - function handlePending( module ) { - var j, job, hasErrors, m, stateChange, fromBaseModule; - - if ( registry[ module ].state === 'error' || registry[ module ].state === 'missing' ) { - fromBaseModule = baseModules.indexOf( module ) !== -1; - // If the current module failed, mark all dependent modules also as failed. - // Iterate until steady-state to propagate the error state upwards in the - // dependency tree. - do { - stateChange = false; - for ( m in registry ) { - if ( registry[ m ].state !== 'error' && registry[ m ].state !== 'missing' ) { - // Always propagate errors from base modules to regular modules (implicit dependency). - // Between base modules or regular modules, consider direct dependencies only. - if ( - ( fromBaseModule && baseModules.indexOf( m ) === -1 ) || - anyFailed( registry[ m ].dependencies ) - ) { - registry[ m ].state = 'error'; - stateChange = true; + function doPropagation() { + var errorModule, baseModuleError, module, i, failed, job, + didPropagate = true; + + // Keep going until the last iteration performed no actions. + do { + didPropagate = false; + + // Stage 1: Propagate failures + while ( errorModules.length ) { + errorModule = errorModules.shift(); + baseModuleError = baseModules.indexOf( errorModule ) !== -1; + for ( module in registry ) { + if ( registry[ module ].state !== 'error' && registry[ module ].state !== 'missing' ) { + if ( baseModuleError && baseModules.indexOf( module ) === -1 ) { + // Propate error from base module to all regular (non-base) modules + registry[ module ].state = 'error'; + didPropagate = true; + } else if ( registry[ module ].dependencies.indexOf( errorModule ) !== -1 ) { + // Propagate error from dependency to depending module + registry[ module ].state = 'error'; + // .. and propagate it further + errorModules.push( module ); + didPropagate = true; } } } - } while ( stateChange ); - } + } - // Execute all jobs whose dependencies are either all satisfied or contain at least one failed module. - for ( j = 0; j < jobs.length; j++ ) { - hasErrors = anyFailed( jobs[ j ].dependencies ); - if ( hasErrors || allReady( jobs[ j ].dependencies ) ) { - // All dependencies satisfied, or some have errors - job = jobs[ j ]; - jobs.splice( j, 1 ); - j -= 1; - try { - if ( hasErrors ) { - if ( typeof job.error === 'function' ) { - job.error( new Error( 'Module ' + module + ' has failed dependencies' ), [ module ] ); - } - } else { - if ( typeof job.ready === 'function' ) { + // Stage 2: Execute 'loaded' modules with no unsatisfied dependencies + for ( module in registry ) { + if ( registry[ module ].state === 'loaded' && allWithImplicitReady( module ) ) { + // Recursively execute all dependent modules that were already loaded + // (waiting for execution) and no longer have unsatisfied dependencies. + // Base modules may have dependencies amongst eachother to ensure correct + // execution order. Regular modules wait for all base modules. + // eslint-disable-next-line no-use-before-define + execute( module ); + didPropagate = true; + } + } + + // Stage 3: Invoke job callbacks that are no longer blocked + for ( i = 0; i < jobs.length; i++ ) { + job = jobs[ i ]; + failed = anyFailed( job.dependencies ); + if ( failed || allReady( job.dependencies ) ) { + jobs.splice( i, 1 ); + i -= 1; + try { + if ( failed && job.error ) { + job.error( new Error( 'Module has failed dependencies' ), job.dependencies ); + } else if ( !failed && job.ready ) { job.ready(); } + } catch ( e ) { + // A user-defined callback raised an exception. + // Swallow it to protect our state machine! + mw.trackError( 'resourceloader.exception', { + exception: e, + source: 'load-callback' + } ); } - } catch ( e ) { - // A user-defined callback raised an exception. - // Swallow it to protect our state machine! - mw.trackError( 'resourceloader.exception', { - exception: e, - module: module, - source: 'load-callback' - } ); + didPropagate = true; } } + } while ( didPropagate ); + + willPropagate = false; + } + + /** + * Request a (debounced) call to doPropagation(). + * + * @private + */ + function requestPropagation() { + if ( willPropagate ) { + // Already scheduled, or, we're already in a doPropagation stack. + return; } + willPropagate = true; + // Yield for two reasons: + // * Allow successive calls to mw.loader.implement() from the same + // load.php response, or from the same asyncEval() to be in the + // propagation batch. + // * Allow the browser to breathe between the reception of + // module source code and the execution of it. + // + // Use a high priority because the user may be waiting for interactions + // to start being possible. But, first provide a moment (up to 'timeout') + // for native input event handling (e.g. scrolling/typing/clicking). + mw.requestIdleCallback( doPropagation, { timeout: 1 } ); + } - // The current module became 'ready'. - if ( registry[ module ].state === 'ready' ) { - // Queue it for later syncing to the module store. - mw.loader.store.add( module ); - // Recursively execute all dependent modules that were already loaded - // (waiting for execution) and no longer have unsatisfied dependencies. - for ( m in registry ) { - // Base modules may have dependencies amongst eachother to ensure correct - // execution order. Regular modules wait for all base modules. - if ( registry[ m ].state === 'loaded' && allWithImplicitReady( m ) ) { - // eslint-disable-next-line no-use-before-define - execute( m ); - } + /** + * Update a module's state in the registry and make sure any neccesary + * propagation will occur. See #doPropagation for more about propagation. + * See #registry for more about how states are used. + * + * @private + * @param {string} module + * @param {string} state + */ + function setAndPropagate( module, state ) { + registry[ module ].state = state; + if ( state === 'loaded' || state === 'ready' || state === 'error' || state === 'missing' ) { + if ( state === 'ready' ) { + // Queue to later be synced to the local module store. + mw.loader.store.add( module ); + } else if ( state === 'error' || state === 'missing' ) { + errorModules.push( module ); } + requestPropagation(); } } @@ -892,8 +942,7 @@ if ( skip() ) { registry[ module ].skipped = true; registry[ module ].dependencies = []; - registry[ module ].state = 'ready'; - handlePending( module ); + setAndPropagate( module, 'ready' ); return; } } @@ -1127,8 +1176,7 @@ // 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' ) { - registry[ module ].state = 'error'; - handlePending( module ); + setAndPropagate( module, 'error' ); return; } queue.push( module ); @@ -1165,8 +1213,7 @@ script = registry[ module ].script; markModuleReady = function () { $CODE.profileScriptEnd(); - registry[ module ].state = 'ready'; - handlePending( module ); + setAndPropagate( module, 'ready' ); }; nestedAddScript = function ( arr, callback, i ) { // Recursively call queueModuleScript() in its own callback @@ -1216,13 +1263,13 @@ } catch ( e ) { // Use mw.track instead of mw.log because these errors are common in production mode // (e.g. undefined variable), and mw.log is only enabled in debug mode. - registry[ module ].state = 'error'; + setAndPropagate( module, 'error' ); $CODE.profileScriptEnd(); mw.trackError( 'resourceloader.exception', { - exception: e, module: - module, source: 'module-execute' + exception: e, + module: module, + source: 'module-execute' } ); - handlePending( module ); } }; @@ -1855,10 +1902,7 @@ registry[ name ].templates = templates || null; // The module may already have been marked as erroneous if ( registry[ name ].state !== 'error' && registry[ name ].state !== 'missing' ) { - registry[ name ].state = 'loaded'; - if ( allWithImplicitReady( name ) ) { - execute( name ); - } + setAndPropagate( name, 'loaded' ); } }, @@ -1929,12 +1973,7 @@ if ( !hasOwn.call( registry, module ) ) { mw.loader.register( module ); } - registry[ module ].state = state; - if ( state === 'ready' || state === 'error' || state === 'missing' ) { - // Make sure pending modules depending on this one get executed if their - // dependencies are now fulfilled! - handlePending( module ); - } + setAndPropagate( module, state ); } },