configFactory = $configFactory; $this->subscriptionStore = $subscriptionStore; $this->userNameUtils = $userNameUtils; $this->userOptionsLookup = $userOptionsLookup; } /** * Adds DiscussionTools JS to the output. * * This is attached to the MediaWiki 'BeforePageDisplay' hook. * * @param OutputPage $output * @param Skin $skin * @return void This hook must not abort, it must return no value */ public function onBeforePageDisplay( $output, $skin ): void { $user = $output->getUser(); $req = $output->getRequest(); foreach ( HookUtils::FEATURES as $feature ) { // Add a CSS class for each enabled feature if ( HookUtils::isFeatureEnabledForOutput( $output, $feature ) ) { $output->addBodyClasses( "ext-discussiontools-$feature-enabled" ); } } // Load style modules if the tools can be available for the title // to selectively hide DT features, depending on the body classes added above. if ( HookUtils::isAvailableForTitle( $output->getTitle() ) ) { $output->addModuleStyles( [ 'ext.discussionTools.init.styles', ] ); } // Load modules if any DT feature is enabled for this user if ( HookUtils::isFeatureEnabledForOutput( $output ) ) { $output->addModules( [ 'ext.discussionTools.init' ] ); $enabledVars = []; foreach ( HookUtils::FEATURES as $feature ) { $enabledVars[$feature] = HookUtils::isFeatureEnabledForOutput( $output, $feature ); } $output->addJsConfigVars( 'wgDiscussionToolsFeaturesEnabled', $enabledVars ); $editor = $this->userOptionsLookup->getOption( $user, 'discussiontools-editmode' ); // User has no preferred editor yet // If the user has a preferred editor, this will be evaluated in the client if ( !$editor ) { // Check which editor we would use for articles // VE pref is 'visualeditor'/'wikitext'. Here we describe the mode, // not the editor, so 'visual'/'source' $editor = VisualEditorHooks::getPreferredEditor( $user, $req ) === 'visualeditor' ? 'visual' : 'source'; $output->addJsConfigVars( 'wgDiscussionToolsFallbackEditMode', $editor ); } $dtConfig = $this->configFactory->makeConfig( 'discussiontools' ); $abstate = $dtConfig->get( 'DiscussionToolsABTest' ) ? $this->userOptionsLookup->getOption( $user, 'discussiontools-abtest2' ) : false; if ( $abstate ) { $output->addJsConfigVars( 'wgDiscussionToolsABTestBucket', $abstate ); } } // Replace the action=edit§ion=new form with the new topic tool. if ( HookUtils::shouldOpenNewTopicTool( $output->getContext() ) ) { $output->addJsConfigVars( 'wgDiscussionToolsStartNewTopicTool', true ); // For no-JS compatibility, redirect to the old new section editor if JS is unavailable. // This isn't great, because the user has to load the page twice. But making a page that is // both a view mode and an edit mode seems difficult, so I'm cutting some corners here. // (Code below adapted from VisualEditor.) $params = $output->getRequest()->getValues(); $params['dtenable'] = '0'; $url = wfScript() . '?' . wfArrayToCgi( $params ); $escapedUrl = htmlspecialchars( $url ); // Redirect if the user has no JS (