94 'mediawiki.action.view.categoryPage.styles'
102 unset( $this->query[
'title'] );
111 $this->showGallery = $this->
getConfig()->get(
'CategoryMagicGallery' )
137 $r = $this->
msg(
'category-empty' )->parseAsBlock();
142 'class' =>
'mw-category-generated',
143 'lang' =>
$lang->getHtmlCode(),
144 'dir' =>
$lang->getDir()
146 # put a div around the headings which are in the user language
147 $r = Html::openElement(
'div', $attribs ) . $r .
'</div>';
153 $this->articles = [];
154 $this->articles_start_char = [];
155 $this->children = [];
156 $this->children_start_char = [];
157 if ( $this->showGallery ) {
159 $mode = $this->
getRequest()->getVal(
'gallerymode',
null );
162 }
catch ( Exception $e ) {
167 $this->gallery->setHideBadImages();
169 $this->imgsNoGallery = [];
170 $this->imgsNoGallery_start_char = [];
191 $this->children_start_char[] =
198 if ( $link ===
null ) {
199 $linkRenderer = MediaWikiServices::getInstance()->getLinkRenderer();
200 if ( $html !==
null ) {
203 $link = $linkRenderer->makeLink(
$title, $html );
206 $link =
'<span class="redirect-in-category">' . $link .
'</span>';
230 $firstChar = $this->collation->getFirstLetter( $word );
232 return MediaWikiServices::getInstance()->getContentLanguage()->convert( $firstChar );
243 if ( $this->showGallery ) {
244 $flip = $this->flip[
'file'];
246 $this->gallery->insert(
$title );
248 $this->gallery->add(
$title );
251 $this->imgsNoGallery[] = $this->
generateLink(
'image', $title, $isRedirect );
253 $this->imgsNoGallery_start_char[] = MediaWikiServices::getInstance()->
254 getContentLanguage()->convert( $this->collation->getFirstLetter( $sortkey ) );
268 $this->articles_start_char[] = MediaWikiServices::getInstance()->
269 getContentLanguage()->convert( $this->collation->getFirstLetter( $sortkey ) );
273 if ( $this->flip[
'subcat'] ) {
274 $this->children = array_reverse( $this->children );
275 $this->children_start_char = array_reverse( $this->children_start_char );
277 if ( $this->flip[
'page'] ) {
278 $this->articles = array_reverse( $this->articles );
279 $this->articles_start_char = array_reverse( $this->articles_start_char );
281 if ( !$this->showGallery && $this->flip[
'file'] ) {
282 $this->imgsNoGallery = array_reverse( $this->imgsNoGallery );
283 $this->imgsNoGallery_start_char = array_reverse( $this->imgsNoGallery_start_char );
301 $this->flip = [
'page' =>
false,
'subcat' =>
false,
'file' => false ];
303 foreach ( [
'page',
'subcat',
'file' ] as
$type ) {
304 # Get the sortkeys for start/end, if applicable. Note that if
305 # the collation in the database differs from the one
306 # set in $wgCategoryCollation, pagination might go totally haywire.
307 $extraConds = [
'cl_type' =>
$type ];
308 if ( isset( $this->from[
$type] ) && $this->from[
$type] !==
null ) {
309 $extraConds[] =
'cl_sortkey >= '
310 .
$dbr->addQuotes( $this->collation->getSortKey( $this->from[
$type] ) );
311 } elseif ( isset( $this->until[
$type] ) && $this->until[
$type] !==
null ) {
312 $extraConds[] =
'cl_sortkey < '
313 .
$dbr->addQuotes( $this->collation->getSortKey( $this->until[
$type] ) );
314 $this->flip[
$type] =
true;
318 [
'page',
'categorylinks',
'category' ],
334 array_merge( [
'cl_to' => $this->title->getDBkey() ], $extraConds ),
337 'USE INDEX' => [
'categorylinks' =>
'cl_sortkey' ],
338 'LIMIT' => $this->limit + 1,
339 'ORDER BY' => $this->flip[
$type] ?
'cl_sortkey DESC' :
'cl_sortkey',
342 'categorylinks' => [
'JOIN',
'cl_from = page_id' ],
343 'category' => [
'LEFT JOIN', [
344 'cat_title = page_title',
351 $linkCache = MediaWikiServices::getInstance()->getLinkCache();
354 foreach (
$res as $row ) {
356 $linkCache->addGoodLinkObjFromRow(
$title, $row );
358 if ( $row->cl_collation ===
'' ) {
362 $humanSortkey = $row->cl_sortkey;
367 if ( ++$count > $this->limit ) {
368 # We've reached the one extra which shows that there
369 # are additional pages to be had. Stop here...
370 $this->nextPage[
$type] = $humanSortkey;
373 if ( $count == $this->limit ) {
374 $this->prevPage[
$type] = $humanSortkey;
381 $this->
addImage(
$title, $humanSortkey, $row->page_len, $row->page_is_redirect );
383 $this->
addPage(
$title, $humanSortkey, $row->page_len, $row->page_is_redirect );
396 :
"<br style=\"clear:both;\"/>\n" . $r;
403 # Don't show subcategories section if there are none.
405 $rescnt = count( $this->children );
406 $dbcnt = $this->cat->getSubcatCount();
411 # Showing subcategories
412 $r .=
"<div id=\"mw-subcategories\">\n";
413 $r .=
'<h2>' . $this->
msg(
'subcategories' )->parse() .
"</h2>\n";
416 $r .= $this->
formatList( $this->children, $this->children_start_char );
427 $name = $this->
getOutput()->getUnprefixedDisplayTitle();
428 # Don't show articles section if there are none.
431 # @todo FIXME: Here and in the other two sections: we don't need to bother
432 # with this rigmarole if the entire category contents fit on one page
433 # and have already been retrieved. We can just use $rescnt in that
434 # case and save a query and some logic.
435 $dbcnt = $this->cat->getPageCount() - $this->cat->getSubcatCount()
436 - $this->cat->getFileCount();
437 $rescnt = count( $this->articles );
442 $r =
"<div id=\"mw-pages\">\n";
443 $r .=
'<h2>' . $this->
msg(
'category_header' )->rawParams( $name )->parse() .
"</h2>\n";
446 $r .= $this->
formatList( $this->articles, $this->articles_start_char );
457 $name = $this->
getOutput()->getUnprefixedDisplayTitle();
459 $rescnt = $this->showGallery ? $this->gallery->count() : count( $this->imgsNoGallery );
460 $dbcnt = $this->cat->getFileCount();
465 $r .=
"<div id=\"mw-category-media\">\n";
467 $this->
msg(
'category-media-header' )->rawParams( $name )->parse() .
471 if ( $this->showGallery ) {
472 $r .= $this->gallery->toHTML();
474 $r .= $this->
formatList( $this->imgsNoGallery, $this->imgsNoGallery_start_char );
490 if ( isset( $this->until[
$type] ) && $this->until[
$type] !==
null ) {
495 if ( $this->nextPage[
$type] !==
null ) {
502 } elseif ( $this->nextPage[
$type] !==
null
503 || ( isset( $this->from[
$type] ) && $this->from[
$type] !==
null )
537 $pageLang = $this->title->getPageLanguage();
538 $attribs = [
'lang' => $pageLang->getHtmlCode(),
'dir' => $pageLang->getDir(),
539 'class' =>
'mw-content-' . $pageLang->getDir() ];
540 $list = Html::rawElement(
'div', $attribs, $list );
562 $ret = Html::openElement(
'div', [
'class' =>
'mw-category' ] );
566 # Kind of like array_flip() here, but we keep duplicates in an
567 # array instead of dropping them.
568 foreach ( $columns as $article => $char ) {
569 if ( !isset( $colContents[$char] ) ) {
570 $colContents[$char] = [];
572 $colContents[$char][] = $article;
575 foreach ( $colContents as $char =>
$articles ) {
576 # Change space to non-breaking space to keep headers aligned
577 $h3char = $char ===
' ' ?
"\u{00A0}" : htmlspecialchars( $char );
579 $ret .=
'<div class="mw-category-group"><h3>' . $h3char;
583 $ret .= implode(
"</li>\n<li>",
$articles );
584 $ret .=
'</li></ul></div>';
588 $ret .= Html::closeElement(
'div' );
602 $r .=
'<ul><li>' .
$articles[0] .
'</li>';
604 for ( $index = 1; $index < $articleCount; $index++ ) {
609 $r .=
"<li>{$articles[$index]}</li>";
625 $prevLink = $this->
msg(
'prev-page' )->escaped();
627 $linkRenderer = MediaWikiServices::getInstance()->getLinkRenderer();
628 if ( $first !=
'' ) {
630 $prevQuery[
"{$type}until"] = $first;
631 unset( $prevQuery[
"{$type}from"] );
632 $prevLink = $linkRenderer->makeKnownLink(
640 $nextLink = $this->
msg(
'next-page' )->escaped();
644 $lastQuery[
"{$type}from"] =
$last;
645 unset( $lastQuery[
"{$type}until"] );
646 $nextLink = $linkRenderer->makeKnownLink(
654 return $this->
msg(
'categoryviewer-pagedlinks' )->rawParams( $prevLink, $nextLink )->escaped();
667 switch ( $section ) {
669 $fragment =
'mw-pages';
672 $fragment =
'mw-subcategories';
675 $fragment =
'mw-category-media';
679 " Invalid section $section." );
711 if (
$type ===
'article' ) {
712 $pagingType =
'page';
717 $fromOrUntil =
false;
718 if ( ( isset( $this->from[$pagingType] ) && $this->from[$pagingType] !==
null ) ||
719 ( isset( $this->until[$pagingType] ) && $this->until[$pagingType] !==
null )
724 if ( $dbcnt == $rescnt ||
725 ( ( $rescnt == $this->limit || $fromOrUntil ) && $dbcnt > $rescnt )
729 } elseif ( $rescnt < $this->limit && !$fromOrUntil ) {
736 return $this->
msg(
"category-$type-count-limited" )->numParams( $rescnt )->parseAsBlock();
739 return $this->
msg(
"category-$type-count" )->numParams( $rescnt, $totalcnt )->parseAsBlock();