X-Git-Url: https://git.cyclocoop.org/?a=blobdiff_plain;f=includes%2FOutputPage.php;h=0b6e616b33c26fae7909f8cf35cdb14bb24bfa4e;hb=a01d8be82c6eb6a39b9715b40b71f78817161a2a;hp=37527cf100a5e67770de86eb59923375603dda35;hpb=984381d6d9420baf5afbbe957e1bda99e9feec27;p=lhc%2Fweb%2Fwiklou.git diff --git a/includes/OutputPage.php b/includes/OutputPage.php index 37527cf100..0b6e616b33 100644 --- a/includes/OutputPage.php +++ b/includes/OutputPage.php @@ -20,6 +20,7 @@ * @file */ +use MediaWiki\Linker\LinkTarget; use MediaWiki\Logger\LoggerFactory; use MediaWiki\MediaWikiServices; use MediaWiki\Session\SessionManager; @@ -155,9 +156,6 @@ class OutputPage extends ContextSource { /** @var ResourceLoaderContext */ private $rlClientContext; - /** @var string */ - private $rlUserModuleState; - /** @var array */ private $rlExemptStyleModules; @@ -295,6 +293,12 @@ class OutputPage extends ContextSource { /** @var array Profiling data */ private $limitReportJSData = []; + /** @var array Map Title to Content */ + private $contentOverrides = []; + + /** @var callable[] */ + private $contentOverrideCallbacks = []; + /** * Link: header contents */ @@ -622,6 +626,39 @@ class OutputPage extends ContextSource { $this->mTarget = $target; } + /** + * Add a mapping from a LinkTarget to a Content, for things like page preview. + * @see self::addContentOverrideCallback() + * @since 1.32 + * @param LinkTarget $target + * @param Content $content + */ + public function addContentOverride( LinkTarget $target, Content $content ) { + if ( !$this->contentOverrides ) { + // Register a callback for $this->contentOverrides on the first call + $this->addContentOverrideCallback( function ( LinkTarget $target ) { + $key = $target->getNamespace() . ':' . $target->getDBkey(); + return isset( $this->contentOverrides[$key] ) + ? $this->contentOverrides[$key] + : null; + } ); + } + + $key = $target->getNamespace() . ':' . $target->getDBkey(); + $this->contentOverrides[$key] = $content; + } + + /** + * Add a callback for mapping from a Title to a Content object, for things + * like page preview. + * @see ResourceLoaderContext::getContentOverrideCallback() + * @since 1.32 + * @param callable $callback + */ + public function addContentOverrideCallback( callable $callback ) { + $this->contentOverrideCallbacks[] = $callback; + } + /** * Get an array of head items * @@ -2294,6 +2331,23 @@ class OutputPage extends ContextSource { } } + /** + * Transfer styles and JavaScript modules from skin. + * + * @param Skin $sk to load modules for + */ + public function loadSkinModules( $sk ) { + foreach ( $sk->getDefaultModules() as $group => $modules ) { + if ( $group === 'styles' ) { + foreach ( $modules as $key => $moduleMembers ) { + $this->addModuleStyles( $moduleMembers ); + } + } else { + $this->addModules( $modules ); + } + } + } + /** * Finally, all the text has been munged and accumulated into * the object, let's actually output it: @@ -2387,9 +2441,7 @@ class OutputPage extends ContextSource { } $sk = $this->getSkin(); - foreach ( $sk->getDefaultModules() as $group ) { - $this->addModules( $group ); - } + $this->loadSkinModules( $sk ); MWDebug::addModules( $this ); @@ -2723,6 +2775,18 @@ class OutputPage extends ContextSource { $this->getResourceLoader(), new FauxRequest( $query ) ); + if ( $this->contentOverrideCallbacks ) { + $this->rlClientContext = new DerivativeResourceLoaderContext( $this->rlClientContext ); + $this->rlClientContext->setContentOverrideCallback( function ( Title $title ) { + foreach ( $this->contentOverrideCallbacks as $callback ) { + $content = call_user_func( $callback, $title ); + if ( $content !== null ) { + return $content; + } + } + return null; + } ); + } } return $this->rlClientContext; } @@ -2743,6 +2807,7 @@ class OutputPage extends ContextSource { $context = $this->getRlClientContext(); $rl = $this->getResourceLoader(); $this->addModules( [ + 'user', 'user.options', 'user.tokens', ] ); @@ -2771,11 +2836,6 @@ class OutputPage extends ContextSource { function ( $name ) use ( $rl, $context, &$exemptGroups, &$exemptStates ) { $module = $rl->getModule( $name ); if ( $module ) { - if ( $name === 'user.styles' && $this->isUserCssPreview() ) { - $exemptStates[$name] = 'ready'; - // Special case in buildExemptModules() - return false; - } $group = $module->getGroup(); if ( isset( $exemptGroups[$group] ) ) { $exemptStates[$name] = 'ready'; @@ -2791,18 +2851,6 @@ class OutputPage extends ContextSource { ); $this->rlExemptStyleModules = $exemptGroups; - $isUserModuleFiltered = !$this->filterModules( [ 'user' ] ); - // If this page filters out 'user', makeResourceLoaderLink will drop it. - // Avoid indefinite "loading" state or untrue "ready" state (T145368). - if ( !$isUserModuleFiltered ) { - // Manually handled by getBottomScripts() - $userModule = $rl->getModule( 'user' ); - $userState = $userModule->isKnownEmpty( $context ) && !$this->isUserJsPreview() - ? 'ready' - : 'loading'; - $this->rlUserModuleState = $exemptStates['user'] = $userState; - } - $rlClient = new ResourceLoaderClientHtml( $context, [ 'target' => $this->getTarget(), ] ); @@ -2959,20 +3007,6 @@ class OutputPage extends ContextSource { return WrappedString::join( "\n", $chunks ); } - private function isUserJsPreview() { - return $this->getConfig()->get( 'AllowUserJs' ) - && $this->getTitle() - && $this->getTitle()->isUserJsConfigPage() - && $this->userCanPreview(); - } - - protected function isUserCssPreview() { - return $this->getConfig()->get( 'AllowUserCss' ) - && $this->getTitle() - && $this->getTitle()->isUserCssConfigPage() - && $this->userCanPreview(); - } - /** * JS stuff to put at the bottom of the ``. * These are legacy scripts ($this->mScripts), and user JS. @@ -2986,40 +3020,6 @@ class OutputPage extends ContextSource { // Legacy non-ResourceLoader scripts $chunks[] = $this->mScripts; - // Exempt 'user' module - // - May need excludepages for live preview. (T28283) - // - Must use TYPE_COMBINED so its response is handled by mw.loader.implement() which - // ensures execution is scheduled after the "site" module. - // - Don't load if module state is already resolved as "ready". - if ( $this->rlUserModuleState === 'loading' ) { - if ( $this->isUserJsPreview() ) { - $chunks[] = $this->makeResourceLoaderLink( 'user', ResourceLoaderModule::TYPE_COMBINED, - [ 'excludepage' => $this->getTitle()->getPrefixedDBkey() ] - ); - $chunks[] = ResourceLoader::makeInlineScript( - Xml::encodeJsCall( 'mw.loader.using', [ - [ 'user', 'site' ], - new XmlJsCode( - 'function () {' - . Xml::encodeJsCall( '$.globalEval', [ - $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. - // 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 { - // Load normally - $chunks[] = $this->makeResourceLoaderLink( 'user', ResourceLoaderModule::TYPE_COMBINED ); - } - } - if ( $this->limitReportJSData ) { $chunks[] = ResourceLoader::makeInlineScript( ResourceLoader::makeConfigSetScript( @@ -3193,7 +3193,7 @@ class OutputPage extends ContextSource { /** * To make it harder for someone to slip a user a fake - * user-JavaScript or user-CSS preview, a random token + * JavaScript or CSS preview, a random token * is associated with the login session. If it's not * passed back with the preview request, we won't render * the code. @@ -3204,7 +3204,6 @@ class OutputPage extends ContextSource { $request = $this->getRequest(); if ( $request->getVal( 'action' ) !== 'submit' || - !$request->getCheck( 'wpPreview' ) || !$request->wasPosted() ) { return false; @@ -3221,17 +3220,6 @@ class OutputPage extends ContextSource { } $title = $this->getTitle(); - if ( - !$title->isUserJsConfigPage() - && !$title->isUserCssConfigPage() - ) { - return false; - } - if ( !$title->isSubpageOf( $user->getUserPage() ) ) { - // Don't execute another user's CSS or JS on preview (T85855) - return false; - } - $errors = $title->getUserPermissionsErrors( 'edit', $user ); if ( count( $errors ) !== 0 ) { return false; @@ -3570,29 +3558,10 @@ class OutputPage extends ContextSource { * @return string|WrappedStringList HTML */ protected function buildExemptModules() { - global $wgContLang; - $chunks = []; // Things that go after the ResourceLoaderDynamicStyles marker $append = []; - // Exempt 'user' styles module (may need 'excludepages' for live preview) - if ( $this->isUserCssPreview() ) { - $append[] = $this->makeResourceLoaderLink( - 'user.styles', - ResourceLoaderModule::TYPE_STYLES, - [ 'excludepage' => $this->getTitle()->getPrefixedDBkey() ] - ); - - // Load the previewed CSS. Janus it if needed. - // User-supplied CSS is assumed to in the wiki's content language. - $previewedCSS = $this->getRequest()->getText( 'wpTextbox1' ); - if ( $this->getLanguage()->getDir() !== $wgContLang->getDir() ) { - $previewedCSS = CSSJanus::transform( $previewedCSS, true, false ); - } - $append[] = Html::inlineStyle( $previewedCSS ); - } - // We want site, private and user styles to override dynamically added styles from // general modules, but we want dynamically added styles to override statically added // style modules. So the order has to be: