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