Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
0.00% covered (danger)
0.00%
0 / 116
0.00% covered (danger)
0.00%
0 / 4
CRAP
0.00% covered (danger)
0.00%
0 / 1
SpecialSpecialPages
0.00% covered (danger)
0.00%
0 / 115
0.00% covered (danger)
0.00%
0 / 4
756
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
 execute
0.00% covered (danger)
0.00%
0 / 10
0.00% covered (danger)
0.00%
0 / 1
6
 getPageGroups
0.00% covered (danger)
0.00%
0 / 23
0.00% covered (danger)
0.00%
0 / 1
56
 outputPageList
0.00% covered (danger)
0.00%
0 / 81
0.00% covered (danger)
0.00%
0 / 1
306
1<?php
2/**
3 * This program is free software; you can redistribute it and/or modify
4 * it under the terms of the GNU General Public License as published by
5 * the Free Software Foundation; either version 2 of the License, or
6 * (at your option) any later version.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
12 *
13 * You should have received a copy of the GNU General Public License along
14 * with this program; if not, write to the Free Software Foundation, Inc.,
15 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
16 * http://www.gnu.org/copyleft/gpl.html
17 *
18 * @file
19 */
20
21namespace MediaWiki\Specials;
22
23use MediaWiki\Html\Html;
24use MediaWiki\Language\RawMessage;
25use MediaWiki\Parser\Parser;
26use MediaWiki\Parser\ParserOutput;
27use MediaWiki\Parser\ParserOutputFlags;
28use MediaWiki\SpecialPage\UnlistedSpecialPage;
29use Wikimedia\Parsoid\Core\SectionMetadata;
30use Wikimedia\Parsoid\Core\TOCData;
31
32/**
33 * A special page that lists special pages
34 *
35 * @ingroup SpecialPage
36 */
37class SpecialSpecialPages extends UnlistedSpecialPage {
38
39    public function __construct() {
40        parent::__construct( 'Specialpages' );
41    }
42
43    public function execute( $par ) {
44        $out = $this->getOutput();
45        $this->setHeaders();
46        $this->outputHeader();
47        $out->getMetadata()->setPreventClickjacking( false );
48        $out->addModuleStyles( 'mediawiki.special' );
49
50        $groups = $this->getPageGroups();
51
52        if ( $groups === false ) {
53            return;
54        }
55
56        $this->addHelpLink( 'Help:Special pages' );
57        $this->outputPageList( $groups );
58    }
59
60    private function getPageGroups() {
61        $pages = $this->getSpecialPageFactory()->getUsablePages( $this->getUser() );
62
63        if ( $pages === [] ) {
64            // Yeah, that was pointless. Thanks for coming.
65            return false;
66        }
67
68        // Put them into a sortable array
69        $groups = [];
70        foreach ( $pages as $page ) {
71            $group = $page->getFinalGroupName();
72            $desc = $page->getDescription();
73            // T343849
74            if ( is_string( $desc ) ) {
75                wfDeprecated( "string return from {$page->getName()}::getDescription()", '1.41' );
76                $desc = ( new RawMessage( '$1' ) )->rawParams( $desc );
77            }
78            // (T360723) Only show an entry if the message isn't blanked, to allow on-wiki unlisting
79            if ( !$desc->isDisabled() ) {
80                $groups[$group][$desc->text()] = [
81                    $page->getPageTitle(),
82                    $page->isRestricted(),
83                    $page->isCached()
84                ];
85            }
86        }
87
88        // Sort
89        foreach ( $groups as $group => $sortedPages ) {
90            ksort( $groups[$group] );
91        }
92
93        // Always move "other" to end
94        if ( array_key_exists( 'other', $groups ) ) {
95            $other = $groups['other'];
96            unset( $groups['other'] );
97            $groups['other'] = $other;
98        }
99
100        return $groups;
101    }
102
103    private function outputPageList( $groups ) {
104        $out = $this->getOutput();
105
106        // Legend
107        $includesRestrictedPages = false;
108        $includesCachedPages = false;
109        foreach ( $groups as $group => $sortedPages ) {
110            foreach ( $sortedPages as $desc => [ $title, $restricted, $cached ] ) {
111                if ( $cached ) {
112                    $includesCachedPages = true;
113                }
114                if ( $restricted ) {
115                    $includesRestrictedPages = true;
116                }
117            }
118        }
119
120        $notes = [];
121        if ( $includesRestrictedPages ) {
122            $restricedMsg = $this->msg( 'specialpages-note-restricted' );
123            if ( !$restricedMsg->isDisabled() ) {
124                $notes[] = $restricedMsg->parse();
125            }
126        }
127        if ( $includesCachedPages ) {
128            $cachedMsg = $this->msg( 'specialpages-note-cached' );
129            if ( !$cachedMsg->isDisabled() ) {
130                $notes[] = $cachedMsg->parse();
131            }
132        }
133        if ( $notes !== [] ) {
134            $legendHeading = $this->msg( 'specialpages-note-top' )->parse();
135
136            $legend = Html::rawElement(
137                'div',
138                [ 'class' => 'mw-changeslist-legend mw-specialpages-notes' ],
139                $legendHeading . implode( "\n", $notes )
140            );
141
142            $out->addHTML( $legend );
143            $out->addModuleStyles( 'mediawiki.special.changeslist.legend' );
144        }
145
146        // Format table of contents
147        $tocData = new TOCData();
148        $tocLength = 0;
149        foreach ( $groups as $group => $sortedPages ) {
150            if ( !str_contains( $group, '/' ) ) {
151                ++$tocLength;
152                $tocData->addSection( new SectionMetadata(
153                    1,
154                    2,
155                    $this->msg( "specialpages-group-$group" )->escaped(),
156                    $this->getLanguage()->formatNum( $tocLength ),
157                    (string)$tocLength,
158                    null,
159                    null,
160                    "mw-specialpagesgroup-$group",
161                    "mw-specialpagesgroup-$group"
162                ) );
163            }
164        }
165
166        $pout = new ParserOutput;
167        $pout->setTOCData( $tocData );
168        $pout->setOutputFlag( ParserOutputFlags::SHOW_TOC );
169        $pout->setRawText( Parser::TOC_PLACEHOLDER );
170        $out->addParserOutput( $pout );
171
172        // Format contents
173        foreach ( $groups as $group => $sortedPages ) {
174            if ( str_contains( $group, '/' ) ) {
175                [ $group, $subGroup ] = explode( '/', $group, 2 );
176                $out->addHTML( Html::element(
177                    'h3',
178                    [ 'class' => "mw-specialpagessubgroup" ],
179                    $this->msg( "specialpages-group-$group-$subGroup" )->text()
180                ) . "\n" );
181            } else {
182                $out->addHTML( Html::element(
183                    'h2',
184                    [ 'class' => "mw-specialpagesgroup", 'id' => "mw-specialpagesgroup-$group" ],
185                    $this->msg( "specialpages-group-$group" )->text()
186                ) . "\n" );
187            }
188            $out->addHTML(
189                Html::openElement( 'div', [ 'class' => 'mw-specialpages-list' ] )
190                . '<ul>'
191            );
192            foreach ( $sortedPages as $desc => [ $title, $restricted, $cached ] ) {
193                $pageClasses = [];
194                if ( $cached ) {
195                    $pageClasses[] = 'mw-specialpagecached';
196                }
197                if ( $restricted ) {
198                    $pageClasses[] = 'mw-specialpagerestricted';
199                }
200
201                $link = $this->getLinkRenderer()->makeKnownLink( $title, $desc );
202                $out->addHTML( Html::rawElement(
203                        'li',
204                        [ 'class' => $pageClasses ],
205                        $link
206                    ) . "\n" );
207            }
208            $out->addHTML(
209                Html::closeElement( 'ul' ) .
210                Html::closeElement( 'div' )
211            );
212        }
213    }
214}
215
216/**
217 * Retain the old class name for backwards compatibility.
218 * @deprecated since 1.41
219 */
220class_alias( SpecialSpecialPages::class, 'SpecialSpecialpages' );