Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
0.00% covered (danger)
0.00%
0 / 104
0.00% covered (danger)
0.00%
0 / 9
CRAP
0.00% covered (danger)
0.00%
0 / 1
LqtParserFunctions
0.00% covered (danger)
0.00%
0 / 104
0.00% covered (danger)
0.00%
0 / 9
812
0.00% covered (danger)
0.00%
0 / 1
 useLiquidThreads
0.00% covered (danger)
0.00%
0 / 6
0.00% covered (danger)
0.00%
0 / 1
12
 lqtPageLimit
0.00% covered (danger)
0.00%
0 / 2
0.00% covered (danger)
0.00%
0 / 1
12
 addToExtensionData
0.00% covered (danger)
0.00%
0 / 3
0.00% covered (danger)
0.00%
0 / 1
2
 lqtTalkPage
0.00% covered (danger)
0.00%
0 / 19
0.00% covered (danger)
0.00%
0 / 1
12
 lqtThread
0.00% covered (danger)
0.00%
0 / 22
0.00% covered (danger)
0.00%
0 / 1
30
 runLqtTalkPage
0.00% covered (danger)
0.00%
0 / 18
0.00% covered (danger)
0.00%
0 / 1
6
 showLqtThread
0.00% covered (danger)
0.00%
0 / 12
0.00% covered (danger)
0.00%
0 / 1
2
 onAddParserOutput
0.00% covered (danger)
0.00%
0 / 16
0.00% covered (danger)
0.00%
0 / 1
56
 onAddHTML
0.00% covered (danger)
0.00%
0 / 6
0.00% covered (danger)
0.00%
0 / 1
12
1<?php
2
3use MediaWiki\MediaWikiServices;
4use MediaWiki\Output\OutputPage;
5use MediaWiki\Parser\Parser;
6use MediaWiki\Parser\ParserOutput;
7use MediaWiki\Title\Title;
8
9/* @phan-file-suppress PhanUndeclaredProperty */
10class LqtParserFunctions {
11
12    private const LQT_REPLACEMENTS_DATA_KEY = 'liquidthreads_replacements';
13
14    public static function useLiquidThreads( Parser $parser, $param = '1' ) {
15        $offParams = [ 'no', 'off', 'disable' ];
16        // Figure out if they want to turn it off or on.
17        $param = trim( strtolower( $param ) );
18
19        if ( in_array( $param, $offParams ) || !$param ) {
20            $param = '0';
21        } else {
22            $param = '1';
23        }
24
25        $parser->getOutput()->setUnsortedPageProperty( 'use-liquid-threads', $param );
26    }
27
28    public static function lqtPageLimit( Parser $parser, $param = null ) {
29        if ( $param && $param > 0 ) {
30            $parser->getOutput()->setUnsortedPageProperty( 'lqt-page-limit', $param );
31        }
32    }
33
34    /**
35     * Adds $data under $text key to ParserOutput $out extension data
36     * LQT_REPLACEMENTS_DATA_KEY property.
37     *
38     * @param ParserOutput $pout
39     * @param string $text
40     * @param array $data
41     */
42    private static function addToExtensionData( ParserOutput $pout, string $text, array $data ) {
43        $lqtReplacements = $pout->getExtensionData( self::LQT_REPLACEMENTS_DATA_KEY ) ?? [];
44        $lqtReplacements[$text] = $data;
45        $pout->setExtensionData( self::LQT_REPLACEMENTS_DATA_KEY, $lqtReplacements );
46    }
47
48    /** To bypass the parser cache just for the LiquidThreads part, we have a cute trick.
49     * We leave a placeholder comment in the HTML, which we expand out in a hook. This way,
50     * most of the page can be cached, but the LiquidThreads dynamism still works.
51     * Thanks to Tim for the idea.
52     * @param string $content
53     * @param array $args
54     * @param Parser $parser
55     * @param PPFrame $frame
56     * @return string
57     */
58    public static function lqtTalkPage( $content, $args, $parser, $frame ) {
59        $pout = $parser->getOutput();
60
61        // Prepare information.
62        $title = null;
63        if ( !empty( $args['talkpage'] ) ) {
64            $title = Title::newFromText( $args['talkpage'] );
65        }
66        if ( $title === null ) {
67            $title = $parser->getTitle();
68        }
69
70        $talkpage = new Article( $title, 0 );
71        $article = new Article( $parser->getTitle(), 0 );
72
73        $data = [
74            'type' => 'talkpage',
75            'args' => $args,
76            'article' => $article,
77            'title' => $article->getTitle(),
78            'talkpage' => $talkpage,
79        ];
80
81        // Generate a token
82        $tok = MWCryptRand::generateHex( 32 );
83        $text = '<!--LQT-PAGE-' . $tok . '-->';
84        self::addToExtensionData( $pout, $text, $data );
85        return $text;
86    }
87
88    public static function lqtThread( $content, $args, $parser, $frame ) {
89        $pout = $parser->getOutput();
90
91        // Prepare information.
92        $title = Title::newFromText( $args['thread'] );
93        $thread = null;
94        if ( $args['thread'] ) {
95            if ( is_numeric( $args['thread'] ) ) {
96                $thread = Threads::withId( $args['thread'] );
97            } elseif ( $title ) {
98                $thread = Threads::withRoot(
99                    MediaWikiServices::getInstance()->getWikiPageFactory()->newFromTitle( $title )
100                );
101            }
102        }
103
104        if ( $thread === null ) {
105            return '';
106        }
107
108        $data = [
109            'type' => 'thread',
110            'args' => $args,
111            'thread' => $thread->id(),
112            'title' => $thread->title(),
113        ];
114
115        // Generate a token
116        $tok = MWCryptRand::generateHex( 32 );
117        $text = '<!--LQT-THREAD-' . $tok . '-->';
118        self::addToExtensionData( $pout, $text, $data );
119        return $text;
120    }
121
122    private static function runLqtTalkPage( $details, OutputPage $out ) {
123        $title = $details["title"];
124        $article = $details["article"];
125        $talkpage = $details["talkpage"];
126        $args = $details["args"];
127
128        global $wgRequest;
129        $oldOut = $out->getHTML();
130        $out->clearHTML();
131
132        $user = $out->getUser();
133        $view = new TalkpageView( $out, $article, $title, $user, $wgRequest );
134        $view->setTalkPage( $talkpage );
135
136        // Handle show/hide preferences. Header gone by default.
137        $view->hideItems( 'header' );
138
139        if ( array_key_exists( 'show', $args ) ) {
140            $show = explode( ' ', $args['show'] );
141            $view->setShownItems( $show );
142        }
143
144        $view->show();
145
146        $html = $out->getHTML();
147        $out->clearHTML();
148
149        return $html;
150    }
151
152    private static function showLqtThread( $details, OutputPage $out ) {
153        $title = $details["title"];
154        $article = $details["article"];
155
156        global $wgRequest;
157        $oldOut = $out->getHTML();
158        $out->clearHTML();
159
160        $thread = Threads::withRoot( MediaWikiServices::getInstance()->getWikiPageFactory()->newFromTitle( $title ) );
161
162        $user = $out->getUser();
163        $view = new LqtView( $out, $article, $title, $user, $wgRequest );
164
165        $view->showThread( $thread );
166
167        $html = $out->getHTML();
168        $out->clearHTML();
169
170        return $html;
171    }
172
173    public static function onAddParserOutput( OutputPage $out, ParserOutput $pout ) {
174        if ( !$pout->getExtensionData( self::LQT_REPLACEMENTS_DATA_KEY ) ) {
175            return true;
176        }
177
178        if ( !isset( $out->mLqtReplacements ) ) {
179            $out->mLqtReplacements = [];
180        }
181
182        $lqtReplacements = $pout->getExtensionData( self::LQT_REPLACEMENTS_DATA_KEY );
183        foreach ( $lqtReplacements as $text => $details ) {
184            $result = '';
185
186            if ( !is_array( $details ) ) {
187                continue;
188            }
189
190            if ( $details['type'] == 'talkpage' ) {
191                $result = self::runLqtTalkPage( $details, $out );
192            } elseif ( $details['type'] == 'thread' ) {
193                $result = self::showLqtThread( $details, $out );
194            }
195
196            $out->mLqtReplacements[$text] = $result;
197            $out->addModules( 'ext.liquidThreads' );
198        }
199
200        return true;
201    }
202
203    public static function onAddHTML( OutputPage $out, &$text ) {
204        if ( !isset( $out->mLqtReplacements ) || !count( $out->mLqtReplacements ) ) {
205            return true;
206        }
207
208        $replacements = $out->mLqtReplacements;
209
210        $replacer = new ReplacementArray( $replacements );
211        $text = $replacer->replace( $text );
212
213        return true;
214    }
215}