22 use TocGeneratorTrait;
25 parent::__construct(
'Specialpages' );
33 $out->getMetadata()->setPreventClickjacking(
false );
34 $out->addModuleStyles(
'mediawiki.special' );
36 $groups = $this->getPageGroups();
38 if ( $groups ===
false ) {
43 $this->outputPageList( $groups );
47 private function getPageGroups() {
50 if ( $pages === [] ) {
57 foreach ( $pages as $page ) {
58 $group = $page->getFinalGroupName();
59 $desc = $page->getDescription();
61 if ( !$desc->isDisabled() ) {
62 $groups[$group][$desc->text()] = [
63 $page->getPageTitle(),
64 $page->isRestricted(),
71 foreach ( $groups as $group => $sortedPages ) {
72 ksort( $groups[$group] );
76 if ( array_key_exists(
'other', $groups ) ) {
77 $other = $groups[
'other'];
78 unset( $groups[
'other'] );
79 $groups[
'other'] = $other;
85 private function outputPageList( array $groups ) {
88 $out->addModules(
'mediawiki.special.specialpages' );
92 $includesRestrictedPages =
false;
93 $includesCachedPages =
false;
94 foreach ( $groups as $group => $sortedPages ) {
95 foreach ( $sortedPages as $desc => [ $title, $restricted, $cached ] ) {
97 $includesCachedPages =
true;
100 $includesRestrictedPages =
true;
106 if ( $includesRestrictedPages ) {
107 $restricedMsg = $this->
msg(
'specialpages-note-restricted' );
108 if ( !$restricedMsg->isDisabled() ) {
109 $notes[] = $restricedMsg->parse();
112 if ( $includesCachedPages ) {
113 $cachedMsg = $this->
msg(
'specialpages-note-cached' );
114 if ( !$cachedMsg->isDisabled() ) {
115 $notes[] = $cachedMsg->parse();
118 if ( $notes !== [] ) {
119 $legendHeading = $this->
msg(
'specialpages-note-top' )->parse();
121 $legend = Html::rawElement(
123 [
'class' => [
'mw-changeslist-legend',
'mw-specialpages-notes' ] ],
124 $legendHeading . implode(
"\n", $notes )
127 $out->addHTML( $legend );
128 $out->addModuleStyles(
'mediawiki.special.changeslist.legend' );
131 $out->addHTML( (
new FieldLayout(
132 new SearchInputWidget( [
133 'placeholder' => $this->
msg(
'specialpages-header-search' )->text(),
136 'classes' => [
'mw-special-pages-search' ],
137 'label' => $this->
msg(
'specialpages-header-search' )->text(),
138 'invisibleLabel' =>
true,
144 foreach ( $groups as $group => $sortedPages ) {
145 if ( !str_contains( $group,
'/' ) ) {
147 id:
"mw-specialpagesgroup-$group",
148 msg:
"specialpages-group-$group"
152 $out->addTOCPlaceholder( $this->
getTocData() );
156 foreach ( $groups as $group => $sortedPages ) {
157 if ( str_contains( $group,
'/' ) ) {
158 [ $group, $subGroup ] = explode(
'/', $group, 2 );
161 [
'class' =>
"mw-specialpagessubgroup" ],
162 $this->
msg(
"specialpages-group-$group-$subGroup" )->text()
167 [
'class' =>
"mw-specialpagesgroup",
'id' =>
"mw-specialpagesgroup-$group" ],
168 $this->
msg(
"specialpages-group-$group" )->text()
172 Html::openElement(
'div', [
'class' =>
'mw-specialpages-list' ] )
175 foreach ( $sortedPages as $desc => [ $title, $restricted, $cached ] ) {
176 $indexAttr = [
'data-search-index-0' => $language->lc( $title->getText() ) ];
178 foreach ( $aliases as $alias => $target ) {
181 $target == $title->getText() &&
182 $language->lc( $alias ) !== $language->lc( $title->getText() )
184 $indexAttr[
'data-search-index-' . $c ] = $language->lc( $alias );
190 $pageClasses[] =
'mw-specialpagecached';
193 $pageClasses[] =
'mw-specialpagerestricted';
197 $out->addHTML( Html::rawElement(
199 $indexAttr + [
'class' => $pageClasses ],
204 Html::closeElement(
'ul' ) .
205 Html::closeElement(
'div' )