Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
0.00% covered (danger)
0.00%
0 / 24
0.00% covered (danger)
0.00%
0 / 5
CRAP
0.00% covered (danger)
0.00%
0 / 1
ParserHooks
0.00% covered (danger)
0.00%
0 / 24
0.00% covered (danger)
0.00%
0 / 5
156
0.00% covered (danger)
0.00%
0 / 1
 __construct
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 transformHtml
0.00% covered (danger)
0.00%
0 / 10
0.00% covered (danger)
0.00%
0 / 1
42
 onParserOutputPostCacheTransform
0.00% covered (danger)
0.00%
0 / 5
0.00% covered (danger)
0.00%
0 / 1
6
 onParserAfterTidy
0.00% covered (danger)
0.00%
0 / 6
0.00% covered (danger)
0.00%
0 / 1
6
 onGetDoubleUnderscoreIDs
0.00% covered (danger)
0.00%
0 / 2
0.00% covered (danger)
0.00%
0 / 1
2
1<?php
2/**
3 * DiscussionTools parser hooks
4 *
5 * @file
6 * @ingroup Extensions
7 * @license MIT
8 */
9
10namespace MediaWiki\Extension\DiscussionTools\Hooks;
11
12use MediaWiki\Config\Config;
13use MediaWiki\Config\ConfigFactory;
14use MediaWiki\Extension\DiscussionTools\CommentFormatter;
15use MediaWiki\Hook\GetDoubleUnderscoreIDsHook;
16use MediaWiki\Hook\ParserAfterTidyHook;
17use MediaWiki\Hook\ParserOutputPostCacheTransformHook;
18use MediaWiki\Parser\ParserOutputFlags;
19use MediaWiki\Parser\Parsoid\PageBundleParserOutputConverter;
20use MediaWiki\Parser\Parsoid\ParsoidParser;
21use MediaWiki\Title\Title;
22use Parser;
23use ParserOutput;
24
25class ParserHooks implements
26    ParserOutputPostCacheTransformHook,
27    GetDoubleUnderscoreIDsHook,
28    ParserAfterTidyHook
29{
30
31    private Config $config;
32
33    public function __construct(
34        ConfigFactory $configFactory
35    ) {
36        $this->config = $configFactory->makeConfig( 'discussiontools' );
37    }
38
39    private function transformHtml(
40        ParserOutput $pout, string &$html, Title $title, bool $isPreview
41    ): void {
42        // This condition must be unreliant on current enablement config or user preference.
43        // In other words, include parser output of talk pages with DT disabled.
44        //
45        // This is similar to HookUtils::isAvailableForTitle, but instead of querying the
46        // database for the latest metadata of a page that exists, we check metadata of
47        // the given ParserOutput object only (this runs before the edit is saved).
48        if ( $title->isTalkPage() || $pout->getNewSection() ) {
49            $talkExpiry = $this->config->get( 'DiscussionToolsTalkPageParserCacheExpiry' );
50            // Override parser cache expiry of talk pages (T280605).
51            // Note, this can only shorten it. MediaWiki ignores values higher than the default.
52            // NOTE: this currently has no effect for Parsoid read
53            // views, since parsoid executes this method as a
54            // post-cache transform.  *However* future work may allow
55            // caching of intermediate results of the "post cache"
56            // transformation pipeline, in which case this code will
57            // again be effective. (More: T350626)
58            if ( $talkExpiry > 0 ) {
59                $pout->updateCacheExpiry( $talkExpiry );
60            }
61        }
62
63        // Always apply the DOM transform if DiscussionTools are available for this page,
64        // to allow linking to individual comments from Echo 'mention' and 'edit-user-talk'
65        // notifications (T253082, T281590), and to reduce parser cache fragmentation (T279864).
66        // The extra buttons are hidden in CSS (ext.discussionTools.init.styles module) when
67        // the user doesn't have DiscussionTools features enabled.
68        if ( HookUtils::isAvailableForTitle( $title ) ) {
69            // This modifies $html
70            CommentFormatter::addDiscussionTools( $html, $pout, $title );
71
72            if ( $isPreview ) {
73                $html = CommentFormatter::removeInteractiveTools( $html );
74                // Suppress the empty state
75                $pout->setExtensionData( 'DiscussionTools-isEmptyTalkPage', null );
76            }
77
78            $pout->addModuleStyles( [ 'ext.discussionTools.init.styles' ] );
79        }
80    }
81
82    /**
83     * For now, this hook only runs on Parsoid HTML. Eventually, this is likely
84     * to be run for legacy HTML but that requires ParserCache storage to be allocated
85     * for DiscussionTools HTML which will be purused separately.
86     *
87     * @inheritDoc
88     */
89    public function onParserOutputPostCacheTransform( $parserOutput, &$text, &$options ): void {
90        $isPreview = $parserOutput->getOutputFlag( ParserOutputFlags::IS_PREVIEW );
91
92        // We want to run this hook only on Parsoid HTML for now.
93        // (and leave the onParserAfterTidy handler for legacy HTML).
94        if ( PageBundleParserOutputConverter::hasPageBundle( $parserOutput ) ) {
95            $titleDbKey = $parserOutput->getExtensionData( ParsoidParser::PARSOID_TITLE_KEY );
96            $title = Title::newFromDBkey( $titleDbKey );
97            '@phan-var Title $title';
98            $this->transformHtml( $parserOutput, $text, $title, $isPreview );
99        }
100    }
101
102    /**
103     * @see https://www.mediawiki.org/wiki/Manual:Hooks/ParserAfterTidy
104     *
105     * @param Parser $parser
106     * @param string &$text
107     */
108    public function onParserAfterTidy( $parser, &$text ) {
109        $pOpts = $parser->getOptions();
110        if ( $pOpts->getInterfaceMessage() ) {
111            return;
112        }
113
114        $this->transformHtml(
115            $parser->getOutput(), $text, $parser->getTitle(), $pOpts->getIsPreview()
116        );
117    }
118
119    /**
120     * @see https://www.mediawiki.org/wiki/Manual:Hooks/GetDoubleUnderscoreIDs
121     *
122     * @param string[] &$doubleUnderscoreIDs
123     * @return bool|void
124     */
125    public function onGetDoubleUnderscoreIDs( &$doubleUnderscoreIDs ) {
126        $doubleUnderscoreIDs[] = 'archivedtalk';
127        $doubleUnderscoreIDs[] = 'notalk';
128    }
129}