$links[] = "\n" . $this->mScripts;
// Add user JS if enabled
+ // This must use TYPE_COMBINED instead of only=scripts so that its request is handled by
+ // mw.loader.implement() which ensures that execution is scheduled after the "site" module.
if ( $this->getConfig()->get( 'AllowUserJs' )
&& $this->getUser()->isLoggedIn()
&& $this->getTitle()
&& $this->getTitle()->isJsSubpage()
&& $this->userCanPreview()
) {
- # XXX: additional security check/prompt?
- // We're on a preview of a JS subpage
- // Exclude this page from the user module in case it's in there (bug 26283)
- $links[] = $this->makeResourceLoaderLink( 'user', ResourceLoaderModule::TYPE_SCRIPTS, false,
+ // We're on a preview of a JS subpage. Exclude this page from the user module (T28283)
+ // and include the draft contents as a raw script instead.
+ $links[] = $this->makeResourceLoaderLink( 'user', ResourceLoaderModule::TYPE_COMBINED, false,
array( 'excludepage' => $this->getTitle()->getPrefixedDBkey() ), $inHead
);
// Load the previewed JS
- $links[] = Html::inlineScript( "\n"
- . $this->getRequest()->getText( 'wpTextbox1' ) . "\n" ) . "\n";
+ $links[] = ResourceLoader::makeInlineScript(
+ Xml::encodeJsCall( 'mw.loader.using', array(
+ array( 'user', 'site' ),
+ new XmlJsCode(
+ 'function () {'
+ . Xml::encodeJsCall( '$.globalEval', array(
+ $this->getRequest()->getText( 'wpTextbox1' )
+ ) )
+ . '}'
+ )
+ ) )
+ );
// FIXME: If the user is previewing, say, ./vector.js, his ./common.js will be loaded
// asynchronously and may arrive *after* the inline script here. So the previewed code
- // may execute before ./common.js runs. Normally, ./common.js runs before ./vector.js...
+ // may execute before ./common.js runs. Normally, ./common.js runs before ./vector.js.
+ // Similarly, when previewing ./common.js and the user module does arrive first, it will
+ // arrive without common.js and the inline script runs after. Thus running common after
+ // the excluded subpage.
} else {
// Include the user module normally, i.e., raw to avoid it being wrapped in a closure.
- $links[] = $this->makeResourceLoaderLink( 'user', ResourceLoaderModule::TYPE_SCRIPTS,
+ $links[] = $this->makeResourceLoaderLink( 'user', ResourceLoaderModule::TYPE_COMBINED,
/* $useESI = */ false, /* $extraQuery = */ array(), /* $loadCall = */ $inHead
);
}
$name, $scripts, $styles, $messages, $templates
) {
if ( is_string( $scripts ) ) {
- // Site module is a legacy script that runs in the global scope (no closure).
+ // Site and user module are a legacy scripts that run in the global scope (no closure).
// Transportation as string instructs mw.loader.implement to use globalEval.
- if ( $name !== 'site' ) {
+ if ( $name !== 'site' && $name !== 'user' ) {
$scripts = new XmlJsCode( "function ( $, jQuery ) {\n{$scripts}\n}" );
}
} elseif ( !is_array( $scripts ) ) {
script( $, $ );
handlePending( module );
} else if ( typeof script === 'string' ) {
- // Site module is a legacy script that runs in the global scope. This is transported
- // as a string instead of a function to avoid needing to use string manipulation to
- // undo the function wrapper.
- registry[module].state = 'ready';
- $.globalEval( script );
- handlePending( module );
+ // Site and user modules are a legacy scripts that run in the global scope.
+ // This is transported as a string instead of a function to avoid needing
+ // to use string manipulation to undo the function wrapper.
+ if ( module === 'user' ) {
+ // Implicit dependency on the site module. Not real dependency because
+ // it should run after 'site' regardless of whether it succeeds or fails.
+ mw.loader.using( 'site' ).always( function () {
+ registry[module].state = 'ready';
+ $.globalEval( script );
+ handlePending( module );
+ } );
+ } else {
+ registry[module].state = 'ready';
+ $.globalEval( script );
+ handlePending( module );
+ }
}
} catch ( e ) {
// This needs to NOT use mw.log because these errors are common in production mode