Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
0.00% covered (danger)
0.00%
0 / 115
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 / 114
0.00% covered (danger)
0.00%
0 / 4
702
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 / 22
0.00% covered (danger)
0.00%
0 / 1
42
 outputPageList
0.00% covered (danger)
0.00%
0 / 81
0.00% covered (danger)
0.00%
0 / 1
306
1<?php
2/**
3 * Implements Special:Specialpages
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License along
16 * with this program; if not, write to the Free Software Foundation, Inc.,
17 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
18 * http://www.gnu.org/copyleft/gpl.html
19 *
20 * @file
21 * @ingroup SpecialPage
22 */
23
24namespace MediaWiki\Specials;
25
26use MediaWiki\Html\Html;
27use MediaWiki\Language\RawMessage;
28use MediaWiki\Parser\Parser;
29use MediaWiki\Parser\ParserOutput;
30use MediaWiki\Parser\ParserOutputFlags;
31use MediaWiki\SpecialPage\UnlistedSpecialPage;
32use Wikimedia\Parsoid\Core\SectionMetadata;
33use Wikimedia\Parsoid\Core\TOCData;
34
35/**
36 * A special page that lists special pages
37 *
38 * @ingroup SpecialPage
39 */
40class SpecialSpecialPages extends UnlistedSpecialPage {
41
42    public function __construct() {
43        parent::__construct( 'Specialpages' );
44    }
45
46    public function execute( $par ) {
47        $out = $this->getOutput();
48        $this->setHeaders();
49        $this->outputHeader();
50        $out->setPreventClickjacking( false );
51        $out->addModuleStyles( 'mediawiki.special' );
52
53        $groups = $this->getPageGroups();
54
55        if ( $groups === false ) {
56            return;
57        }
58
59        $this->addHelpLink( 'Help:Special pages' );
60        $this->outputPageList( $groups );
61    }
62
63    private function getPageGroups() {
64        $pages = $this->getSpecialPageFactory()->getUsablePages( $this->getUser() );
65
66        if ( $pages === [] ) {
67            // Yeah, that was pointless. Thanks for coming.
68            return false;
69        }
70
71        // Put them into a sortable array
72        $groups = [];
73        foreach ( $pages as $page ) {
74            $group = $page->getFinalGroupName();
75            $desc = $page->getDescription();
76            // T343849
77            if ( is_string( $desc ) ) {
78                wfDeprecated( "string return from {$page->getName()}::getDescription()", '1.41' );
79                $desc = ( new RawMessage( '$1' ) )->rawParams( $desc );
80            }
81            $groups[$group][$desc->text()] = [
82                $page->getPageTitle(),
83                $page->isRestricted(),
84                $page->isCached()
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' );