Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
0.00% covered (danger)
0.00%
0 / 121
0.00% covered (danger)
0.00%
0 / 8
CRAP
0.00% covered (danger)
0.00%
0 / 1
ThreadPermalinkView
0.00% covered (danger)
0.00%
0 / 121
0.00% covered (danger)
0.00%
0 / 8
1056
0.00% covered (danger)
0.00%
0 / 1
 customizeNavigation
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 customizeThreadNavigation
0.00% covered (danger)
0.00%
0 / 29
0.00% covered (danger)
0.00%
0 / 1
72
 getCustomTabs
0.00% covered (danger)
0.00%
0 / 27
0.00% covered (danger)
0.00%
0 / 1
30
 noSuchRevision
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 showMissingThreadPage
0.00% covered (danger)
0.00%
0 / 2
0.00% covered (danger)
0.00%
0 / 1
2
 getSubtitle
0.00% covered (danger)
0.00%
0 / 17
0.00% covered (danger)
0.00%
0 / 1
20
 __construct
0.00% covered (danger)
0.00%
0 / 6
0.00% covered (danger)
0.00%
0 / 1
6
 show
0.00% covered (danger)
0.00%
0 / 38
0.00% covered (danger)
0.00%
0 / 1
110
1<?php
2
3use MediaWiki\MediaWikiServices;
4use MediaWiki\SpecialPage\SpecialPage;
5use MediaWiki\Title\Title;
6
7class ThreadPermalinkView extends LqtView {
8    /** @var Thread */
9    protected $thread;
10
11    public function customizeNavigation( $skin, &$links ) {
12        self::customizeThreadNavigation( $skin, $links, $this );
13    }
14
15    /**
16     * @param Skin $skin
17     * @param array[] &$links
18     * @param ThreadPermalinkView|ThreadProtectionFormView $view
19     */
20    public static function customizeThreadNavigation( $skin, &$links, $view ) {
21        $tempTitle = Title::makeTitle( NS_LQT_THREAD, 'A' );
22        $talkKey = $tempTitle->getNamespaceKey( '' ) . '_talk';
23
24        if ( !$view->thread ) {
25            unset( $links['views']['edit'] );
26            unset( $links['views']['history'] );
27
28            $links['actions'] = [];
29
30            unset( $links['namespaces'][$talkKey] );
31            return;
32        }
33
34        // Insert 'article' and 'discussion' namespace-tabs
35        $new_nstabs = self::getCustomTabs( $view );
36
37        $nstabs =& $links['namespaces'];
38
39        unset( $nstabs[$talkKey] );
40        $nstabs = $new_nstabs + $nstabs;
41
42        // Remove some views.
43        $views =& $links['views'];
44        unset( $views['viewsource'] );
45        unset( $views['edit'] );
46
47        $subpageTitle = $view->thread->title();
48        // Re-point move, delete and history actions
49        $actions =& $links['actions'];
50        if ( isset( $actions['move'] ) && $subpageTitle ) {
51            $subpage = $subpageTitle->getPrefixedText();
52            $actions['move']['href'] =
53                SpecialPage::getTitleFor( 'MoveThread', $subpage )->getLocalURL();
54        }
55
56        if ( isset( $actions['delete'] ) && $subpageTitle ) {
57            $actions['delete']['href'] =
58                $subpageTitle->getLocalURL( 'action=delete' );
59        }
60
61        if ( isset( $views['history'] ) ) {
62            $views['history']['href'] =
63                self::permalinkUrl( $view->thread, 'thread_history' );
64            if ( $view->methodApplies( 'thread_history' ) ) {
65                $views['history']['class'] = 'selected';
66            }
67        }
68    }
69
70    /**
71     * Pre-generates the tabs to be included, for customizeNavigation to insert in the appropriate
72     * place
73     *
74     * @param ThreadPermalinkView|ThreadProtectionFormView $view
75     * @return array[]
76     */
77    private static function getCustomTabs( $view ) {
78        $tabs = [];
79
80        $articleTitle = $view->thread->getTitle()->getSubjectPage();
81        $talkTitle = $view->thread->getTitle()->getTalkPage();
82
83        $articleClasses = [];
84        if ( !$articleTitle->exists() ) {
85            $articleClasses[] = 'new';
86        }
87        if ( $articleTitle->equals( $view->thread->getTitle() ) ) {
88            $articleClasses[] = 'selected';
89        }
90
91        $talkClasses = [];
92        if ( !$talkTitle->exists() ) {
93            $talkClasses[] = 'new';
94        }
95
96        if ( wfMessage( $articleTitle->getNamespaceKey() )->exists() ) {
97            $articleNamespaceText = wfMessage( $articleTitle->getNamespaceKey() )->text();
98        } else {
99            $articleNamespaceText = $articleTitle->getNsText();
100        }
101
102        $tabs['article'] =
103            [
104                'text' => $articleNamespaceText,
105                'href' => $articleTitle->getLocalURL(),
106                'class' => implode( ' ', $articleClasses ),
107            ];
108
109        $tabs['lqt_talk'] =
110            [
111                // talkpage certainly exists since this thread is from it.
112                'text' => wfMessage( 'talk' )->text(),
113                'href' => $talkTitle->getLocalURL(),
114                'class' => implode( ' ', $talkClasses ),
115            ];
116
117        return $tabs;
118    }
119
120    public function noSuchRevision() {
121        $this->output->addWikiMsg( 'lqt_nosuchrevision' );
122    }
123
124    public function showMissingThreadPage() {
125        $this->output->setPageTitleMsg( wfMessage( 'lqt_nosuchthread_title' ) );
126        $this->output->addWikiMsg( 'lqt_nosuchthread' );
127    }
128
129    /** @return string|null HTML or null */
130    public function getSubtitle() {
131        $linkRenderer = MediaWikiServices::getInstance()->getLinkRenderer();
132        $fragment = '#' . $this->anchorName( $this->thread );
133
134        $talkpage = $this->thread->getTitle();
135        if ( !$talkpage ) {
136            return null;
137        }
138        $talkpage->setFragment( $fragment );
139        $talkpage_link = $linkRenderer->makeLink( $talkpage );
140        $topmostTitle = $this->thread->topmostThread()->title();
141        if ( $this->thread->hasSuperthread() && $topmostTitle ) {
142            $topmostTitle->setFragment( $fragment );
143
144            $linkText = new HtmlArmor( wfMessage( 'lqt_discussion_link' )->parse() );
145            $permalink = $linkRenderer->makeLink( $topmostTitle, $linkText );
146            $message = wfMessage( 'lqt_fragment' )
147                ->rawParams( $permalink, $talkpage_link )
148                ->parse();
149        } else {
150            $message = wfMessage( 'lqt_from_talk' )->rawParams( $talkpage_link )->parse();
151        }
152        return $message;
153    }
154
155    public function __construct( &$output, &$article, &$title, &$user, &$request ) {
156        parent::__construct( $output, $article, $title, $user, $request );
157
158        $t = Threads::withRoot( $this->article->getPage() );
159
160        $this->thread = $t;
161        if ( !$t ) {
162            return;
163        }
164
165        // $this->article gets saved to thread_article, so we want it to point to the
166        // subject page associated with the talkpage, always, not the permalink url.
167        $this->article = $t->article(); # for creating reply threads.
168    }
169
170    public function show() {
171        if ( !$this->thread ) {
172            $this->showMissingThreadPage();
173            return false;
174        }
175
176        if ( $this->request->getBool( 'lqt_inline' ) ) {
177            $this->doInlineEditForm();
178            return false;
179        }
180
181        // Handle action=edit stuff
182        if ( $this->request->getVal( 'action' ) == 'edit' &&
183                !$this->request->getVal( 'lqt_method', null ) ) {
184            // Rewrite to lqt_method = edit
185            $this->request->setVal( 'lqt_method', 'edit' );
186            $this->request->setVal( 'lqt_operand', $this->thread->id() );
187        }
188
189        $topmostThreadTitle = $this->thread->topmostThread()->title();
190        if ( $topmostThreadTitle ) {
191            // Expose feed links.
192            global $wgFeedClasses;
193            $thread = $topmostThreadTitle->getPrefixedText();
194            $apiParams = [
195                'action' => 'feedthreads',
196                'type' => 'replies|newthreads',
197                'thread' => $thread
198            ];
199            $urlPrefix = wfScript( 'api' ) . '?';
200            foreach ( $wgFeedClasses as $format => $class ) {
201                $theseParams = $apiParams + [ 'feedformat' => $format ];
202                $url = $urlPrefix . wfArrayToCgi( $theseParams );
203                $this->output->addFeedLink( $format, $url );
204            }
205        }
206
207        $subtitle = $this->getSubtitle();
208        if ( $subtitle !== null ) {
209            $this->output->setSubtitle( $subtitle );
210        }
211
212        if ( $this->methodApplies( 'summarize' ) ) {
213            $this->showSummarizeForm( $this->thread );
214        } elseif ( $this->methodApplies( 'split' ) ) {
215            // @FIXME Method does not exists
216            // @phan-suppress-next-line PhanUndeclaredMethod
217            $this->showSplitForm( $this->thread );
218        }
219
220        $this->showThread( $this->thread, 1, 1, [ 'maxDepth' => -1, 'maxCount' => -1 ] );
221
222        $services = MediaWikiServices::getInstance();
223        $langConv = $services
224                ->getLanguageConverterFactory()
225                ->getLanguageConverter( $services->getContentLanguage() );
226        $this->output->setPageTitle( $langConv->convert( $this->thread->subject() ) );
227        return false;
228    }
229}