Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
0.00% covered (danger)
0.00%
0 / 77
0.00% covered (danger)
0.00%
0 / 8
CRAP
0.00% covered (danger)
0.00%
0 / 1
SpecialDiscussionToolsDebug
0.00% covered (danger)
0.00%
0 / 77
0.00% covered (danger)
0.00%
0 / 8
210
0.00% covered (danger)
0.00%
0 / 1
 __construct
0.00% covered (danger)
0.00%
0 / 4
0.00% covered (danger)
0.00%
0 / 1
2
 getDescription
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 getFormFields
0.00% covered (danger)
0.00%
0 / 9
0.00% covered (danger)
0.00%
0 / 1
2
 getSubpageField
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 getDisplayFormat
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 requiresPost
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 onSubmit
0.00% covered (danger)
0.00%
0 / 33
0.00% covered (danger)
0.00%
0 / 1
12
 formatComments
0.00% covered (danger)
0.00%
0 / 27
0.00% covered (danger)
0.00%
0 / 1
30
1<?php
2
3namespace MediaWiki\Extension\DiscussionTools;
4
5use MediaWiki\Extension\DiscussionTools\ThreadItem\ContentCommentItem;
6use MediaWiki\Extension\DiscussionTools\ThreadItem\ContentHeadingItem;
7use MediaWiki\Extension\DiscussionTools\ThreadItem\ContentThreadItem;
8use MediaWiki\Html\Html;
9use MediaWiki\Languages\LanguageFactory;
10use MediaWiki\Linker\Linker;
11use MediaWiki\Page\ParserOutputAccess;
12use MediaWiki\Parser\ParserOptions;
13use MediaWiki\SpecialPage\FormSpecialPage;
14use MediaWiki\SpecialPage\SpecialPage;
15use MediaWiki\Title\Title;
16use MediaWiki\Utils\MWTimestamp;
17use Wikimedia\Assert\Assert;
18use Wikimedia\Parsoid\Utils\DOMCompat;
19use Wikimedia\Parsoid\Utils\DOMUtils;
20
21class SpecialDiscussionToolsDebug extends FormSpecialPage {
22
23    private LanguageFactory $languageFactory;
24    private ParserOutputAccess $parserOutputAccess;
25    private CommentParser $commentParser;
26
27    public function __construct(
28        LanguageFactory $languageFactory,
29        ParserOutputAccess $parserOutputAccess,
30        CommentParser $commentParser
31    ) {
32        parent::__construct( 'DiscussionToolsDebug' );
33        $this->languageFactory = $languageFactory;
34        $this->parserOutputAccess = $parserOutputAccess;
35        $this->commentParser = $commentParser;
36    }
37
38    /**
39     * @inheritDoc
40     */
41    public function getDescription() {
42        return $this->msg( 'discussiontoolsdebug-title' );
43    }
44
45    /**
46     * @inheritDoc
47     */
48    protected function getFormFields() {
49        return [
50            'pagetitle' => [
51                'label-message' => 'discussiontoolsdebug-pagetitle',
52                'name' => 'pagetitle',
53                'type' => 'title',
54                'required' => true,
55                'exists' => true,
56            ],
57        ];
58    }
59
60    /**
61     * @inheritDoc
62     */
63    protected function getSubpageField() {
64        return 'pagetitle';
65    }
66
67    /**
68     * @inheritDoc
69     */
70    protected function getDisplayFormat() {
71        return 'ooui';
72    }
73
74    /**
75     * @inheritDoc
76     */
77    public function requiresPost() {
78        return false;
79    }
80
81    /**
82     * @inheritDoc
83     */
84    public function onSubmit( array $data ) {
85        $title = Title::newFromText( $data['pagetitle'] );
86
87        $status = $this->parserOutputAccess->getParserOutput(
88            $title->toPageRecord(),
89            ParserOptions::newFromAnon()
90        );
91        if ( !$status->isOK() ) {
92            return $status;
93        }
94
95        $parserOutput = $status->getValue();
96        $html = $parserOutput->getText();
97
98        $doc = DOMUtils::parseHTML( $html );
99        $container = DOMCompat::getBody( $doc );
100        $threadItemSet = $this->commentParser->parse( $container, $title->getTitleValue() );
101
102        $out = $this->getOutput();
103
104        $out->addHTML( $this->msg(
105            'discussiontoolsdebug-intro',
106            $title->getPrefixedText(),
107            SpecialPage::getTitleFor(
108                'ApiSandbox',
109                false,
110                'action=discussiontoolspageinfo&prop=threaditemshtml&excludesignatures=1&page='
111                    . urlencode( $title->getPrefixedText() )
112            )->getFullText()
113        )->parseAsBlock() );
114
115        $pageLang = $this->languageFactory->getLanguage( $parserOutput->getLanguage() );
116        $pageLangAttribs = [
117            'lang' => $pageLang->getHtmlCode(),
118            'dir' => $pageLang->getDir(),
119            'class' => 'mw-content-' . $pageLang->getDir(),
120        ];
121
122        foreach ( $threadItemSet->getThreadsStructured() as $thread ) {
123            $out->addHTML( $this->formatComments( $thread, $pageLangAttribs ) );
124        }
125
126        $out->addModuleStyles( 'ext.discussionTools.debug.styles' );
127
128        return true;
129    }
130
131    /**
132     * Format a thread item with replies.
133     *
134     * @param ContentThreadItem $comment
135     * @param array $pageLangAttribs
136     * @return string HTML
137     */
138    private function formatComments( ContentThreadItem $comment, array $pageLangAttribs ) {
139        if ( $comment instanceof ContentHeadingItem ) {
140            $contents = '<span class="mw-dt-heading">' . $comment->getHTML() . '</span>';
141        } else {
142            Assert::precondition( $comment instanceof ContentCommentItem, 'Must be ContentCommentItem' );
143            $contents =
144                '<span class="mw-dt-comment-signature">' .
145                    '<span class="mw-dt-comment-author">' .
146                        Linker::userLink( 0, $comment->getAuthor() ) .
147                    '</span>' . ' ' .
148                    '(' . Linker::userTalkLink( 0, $comment->getAuthor() ) . ') ' .
149                    '<span class="mw-dt-comment-timestamp">' .
150                        htmlspecialchars( $this->getLanguage()->getHumanTimestamp(
151                            new MWTimestamp( $comment->getTimestamp()->getTimestamp() )
152                        ) ) .
153                    '</span>' .
154                '</span>' .
155                Html::rawElement( 'div', $pageLangAttribs,
156                    '<div class="mw-dt-comment-body mw-parser-output">' . $comment->getBodyHTML( true ) . '</div>'
157                );
158        }
159        $level = $comment->getLevel();
160
161        $replies = '';
162        foreach ( $comment->getReplies() as $reply ) {
163            $replies .= $this->formatComments( $reply, $pageLangAttribs );
164        }
165
166        return Html::rawElement( $replies ? 'details' : 'div', [
167            'open' => (bool)$replies,
168            'class' => 'mw-dt-comment',
169            'data-level' => $level,
170        ], ( $replies ? Html::rawElement( 'summary', [], $contents ) : $contents ) . $replies );
171    }
172
173}