Index: trunk/extensions/CategoryTree/CategoryPageSubclass.php |
— | — | @@ -12,7 +12,7 @@ |
13 | 13 | } |
14 | 14 | |
15 | 15 | class CategoryTreeCategoryViewer extends CategoryViewer { |
16 | | - var $child_titles; |
| 16 | + var $child_cats; |
17 | 17 | |
18 | 18 | function getCategoryTree() { |
19 | 19 | global $wgOut, $wgCategoryTreeCategoryPageOptions; |
— | — | @@ -29,25 +29,29 @@ |
30 | 30 | /** |
31 | 31 | * Add a subcategory to the internal lists |
32 | 32 | */ |
33 | | - function addSubcategory( $title, $sortkey, $pageLength ) { |
| 33 | + function addSubcategoryObject( $cat, $sortkey, $pageLength ) { |
34 | 34 | global $wgContLang, $wgOut, $wgRequest; |
35 | 35 | |
| 36 | + $title = $cat->getTitle(); |
| 37 | + |
36 | 38 | if ( $wgRequest->getCheck( 'notree' ) ) { |
37 | | - return parent::addSubcategory( $title, $sortkey, $pageLength ); |
| 39 | + return parent::addSubcategoryObject( $cat, $sortkey, $pageLength ); |
38 | 40 | } |
39 | 41 | |
40 | | - if ( ! $GLOBALS['wgCategoryTreeUnifiedView'] ) { |
41 | | - $this->child_titles[] = $title; |
42 | | - return parent::addSubcategory( $title, $sortkey, $pageLength ); |
43 | | - } |
| 42 | + /*if ( ! $GLOBALS['wgCategoryTreeUnifiedView'] ) { |
| 43 | + $this->child_cats[] = $cat; |
| 44 | + return parent::addSubcategory( $cat, $sortkey, $pageLength ); |
| 45 | + }*/ |
44 | 46 | |
45 | 47 | $tree = $this->getCategoryTree(); |
46 | 48 | |
47 | | - $this->children[] = $tree->renderNode( $title ); |
| 49 | + $this->children[] = $tree->renderNodeInfo( $title, $cat ); |
48 | 50 | |
49 | 51 | $this->children_start_char[] = $this->getSubcategorySortChar( $title, $sortkey ); |
50 | 52 | } |
51 | 53 | |
| 54 | + /* |
| 55 | + # this is a pain to keep this consistent, and no one should be using wgCategoryTreeUnifiedView = false anyway. |
52 | 56 | function getSubcategorySection() { |
53 | 57 | global $wgOut, $wgRequest, $wgCookiePrefix; |
54 | 58 | |
— | — | @@ -107,14 +111,14 @@ |
108 | 112 | if ( $showAs == 'list' ) { |
109 | 113 | $r .= $this->formatList( $this->children, $this->children_start_char ); |
110 | 114 | } else { |
111 | | - $ct = getCategoryTree(); |
| 115 | + $ct = $this->getCategoryTree(); |
112 | 116 | |
113 | | - foreach ( $this->child_titles as $title ) { |
114 | | - $r .= $ct->renderNode( $title ); |
| 117 | + foreach ( $this->child_cats as $cat ) { |
| 118 | + $r .= $ct->renderNodeInfo( $cat->getTitle(), $cat ); |
115 | 119 | } |
116 | 120 | } |
117 | 121 | return $r; |
118 | | - } |
| 122 | + }*/ |
119 | 123 | |
120 | 124 | function makeShowAsLink( $targetValue, $currentValue ) { |
121 | 125 | $msg = htmlspecialchars( CategoryTree::msg( "show-$targetValue" ) ); |
— | — | @@ -127,13 +131,13 @@ |
128 | 132 | } |
129 | 133 | |
130 | 134 | function clearCategoryState() { |
131 | | - $this->child_titles = array(); |
| 135 | + $this->child_cats = array(); |
132 | 136 | parent::clearCategoryState(); |
133 | 137 | } |
134 | 138 | |
135 | 139 | function finaliseCategoryState() { |
136 | 140 | if( $this->flip ) { |
137 | | - $this->child_titles = array_reverse( $this->child_titles ); |
| 141 | + $this->child_cats = array_reverse( $this->child_cats ); |
138 | 142 | } |
139 | 143 | parent::finaliseCategoryState(); |
140 | 144 | } |
Index: trunk/extensions/CategoryTree/CategoryTreePage.php |
— | — | @@ -40,7 +40,7 @@ |
41 | 41 | * @param $par Parameters passed to the page |
42 | 42 | */ |
43 | 43 | function execute( $par ) { |
44 | | - global $wgRequest, $wgOut, $wgMakeBotPrivileged, $wgUser, $wgCategoryTreeDefaultOptions; |
| 44 | + global $wgRequest, $wgOut, $wgCategoryTreeDefaultOptions, $wgCategoryTreeSpecialPageOptions; |
45 | 45 | |
46 | 46 | $this->setHeaders(); |
47 | 47 | |
— | — | @@ -56,6 +56,9 @@ |
57 | 57 | |
58 | 58 | # grab all known options from the request. Normalization is done by the CategoryTree class |
59 | 59 | foreach ( $wgCategoryTreeDefaultOptions as $option => $default ) { |
| 60 | + if ( isset( $wgCategoryTreeSpecialPageOptions[$option] ) ) |
| 61 | + $default = $wgCategoryTreeSpecialPageOptions[$option]; |
| 62 | + |
60 | 63 | $options[$option] = $wgRequest->getVal( $option, $default ); |
61 | 64 | } |
62 | 65 | |
Index: trunk/extensions/CategoryTree/CategoryTree.i18n.php |
— | — | @@ -34,8 +34,11 @@ |
35 | 35 | 'categorytree-expand' => 'expand', |
36 | 36 | 'categorytree-collapse-bullet' => '[<b>−</b>]', # do not translate or duplicate this message to other languages |
37 | 37 | 'categorytree-expand-bullet' => '[<b>+</b>]', # do not translate or duplicate this message to other languages |
| 38 | + 'categorytree-empty-bullet' => '[<b>×</b>]', # do not translate or duplicate this message to other languages |
38 | 39 | 'categorytree-page-bullet' => ' ', # do not translate or duplicate this message to other languages |
39 | 40 | |
| 41 | + 'categorytree-member-counts' => 'contains $1 subcategories, $2 pages, and $3 files', |
| 42 | + |
40 | 43 | 'categorytree-load' => 'load', |
41 | 44 | 'categorytree-loading' => 'loading…', |
42 | 45 | 'categorytree-nothing-found' => 'nothing found', |
— | — | @@ -596,6 +599,7 @@ |
597 | 600 | 'categorytree-category' => 'Kategorie:', |
598 | 601 | 'categorytree-go' => 'Laden', |
599 | 602 | 'categorytree-parents' => 'Oberkategorien', |
| 603 | + 'categorytree-member-counts' => 'enthält $1 Unterkategorien, $2 Seiten und $3 Dateien', |
600 | 604 | 'categorytree-mode-categories' => 'nur Kategorien', |
601 | 605 | 'categorytree-mode-pages' => 'Seiten außer Bilder', |
602 | 606 | 'categorytree-mode-all' => 'alle Seiten', |
Index: trunk/extensions/CategoryTree/CategoryTree.php |
— | — | @@ -32,12 +32,13 @@ |
33 | 33 | * This way, the cache does not need to be disabled. Default is false. |
34 | 34 | * $wgCategoryTreeDisableCache - disabled the parser cache for pages with a <categorytree> tag. Default is true. |
35 | 35 | * $wgCategoryTreeUseCache - enable HTTP cache for anon users. Default is false. |
36 | | - * $wgCategoryTreeUnifiedView - use unified view on category pages, instead of "tree" or "traditional list". Default is true. |
37 | | - * $wgCategoryTreeOmitNamespace - never show namespace prefix. Default is false |
38 | 36 | * $wgCategoryTreeMaxDepth - maximum value for depth argument; An array that maps mode values to |
39 | 37 | * the maximum depth acceptable for the depth option. |
40 | 38 | * Per default, the "categories" mode has a max depth of 2, |
41 | 39 | * all other modes have a max depth of 1. |
| 40 | + * $wgCategoryTreeDefaultOptions - default options for the <categorytree> tag. |
| 41 | + * $wgCategoryTreeCategoryPageOptions - options to apply on category pages. |
| 42 | + * $wgCategoryTreeSpecialPageOptions - options to apply on Special:CategoryTree. |
42 | 43 | */ |
43 | 44 | |
44 | 45 | $wgCategoryTreeMaxChildren = 200; |
— | — | @@ -45,7 +46,7 @@ |
46 | 47 | $wgCategoryTreeDisableCache = true; |
47 | 48 | $wgCategoryTreeDynamicTag = false; |
48 | 49 | $wgCategoryTreeHTTPCache = false; |
49 | | -$wgCategoryTreeUnifiedView = true; |
| 50 | +#$wgCategoryTreeUnifiedView = true; |
50 | 51 | $wgCategoryTreeMaxDepth = array(CT_MODE_PAGES => 1, CT_MODE_ALL => 1, CT_MODE_CATEGORIES => 2); |
51 | 52 | |
52 | 53 | $wgCategoryTreeExtPath = '/extensions/CategoryTree'; |
— | — | @@ -56,12 +57,17 @@ |
57 | 58 | $wgCategoryTreeDefaultOptions = array(); #Default values for most options. ADD NEW OPTIONS HERE! |
58 | 59 | $wgCategoryTreeDefaultOptions['mode'] = NULL; # will be set to $wgCategoryTreeDefaultMode in efCategoryTree(); compatibility quirk |
59 | 60 | $wgCategoryTreeDefaultOptions['hideprefix'] = NULL; # will be set to $wgCategoryTreeDefaultMode in efCategoryTree(); compatibility quirk |
| 61 | +$wgCategoryTreeDefaultOptions['showcount'] = false; |
60 | 62 | #TODO: hideprefix: always, never, catonly, catonly_if_onlycat |
61 | 63 | |
62 | 64 | $wgCategoryTreeCategoryPageMode = CT_MODE_CATEGORIES; |
63 | 65 | $wgCategoryTreeCategoryPageOptions = array(); #Options to be used for category pages |
64 | 66 | $wgCategoryTreeCategoryPageOptions['mode'] = NULL; # will be set to $wgCategoryTreeDefaultMode in efCategoryTree(); compatibility quirk |
| 67 | +$wgCategoryTreeCategoryPageOptions['showcount'] = true; |
65 | 68 | |
| 69 | +$wgCategoryTreeSpecialPageOptions = array(); #Options to be used for Special:CategoryTree |
| 70 | +$wgCategoryTreeSpecialPageOptions['showcount'] = true; |
| 71 | + |
66 | 72 | /** |
67 | 73 | * Register extension setup hook and credits |
68 | 74 | */ |
Index: trunk/extensions/CategoryTree/CategoryTreeFunctions.php |
— | — | @@ -32,6 +32,7 @@ |
33 | 33 | |
34 | 34 | $this->mOptions['mode'] = self::decodeMode( $this->mOptions['mode'] ); |
35 | 35 | $this->mOptions['hideprefix'] = self::decodeBoolean( $this->mOptions['hideprefix'] ); |
| 36 | + $this->mOptions['showcount'] = self::decodeBoolean( $this->mOptions['showcount'] ); |
36 | 37 | } |
37 | 38 | |
38 | 39 | function getOption( $name ) { |
— | — | @@ -66,7 +67,7 @@ |
67 | 68 | if ( is_int( $value ) ) return ( $value > 0 ); |
68 | 69 | |
69 | 70 | $value = trim( strtolower( $value ) ); |
70 | | - if ( is_numeric( $value ) ) return ( (int)$mode > 0 ); |
| 71 | + if ( is_numeric( $value ) ) return ( (int)$value > 0 ); |
71 | 72 | |
72 | 73 | if ( $value == 'yes' || $value == 'y' || $value == 'true' || $value == 't' || $value == 'on' ) return true; |
73 | 74 | else if ( $value == 'no' || $value == 'n' || $value == 'false' || $value == 'f' || $value == 'off' ) return false; |
— | — | @@ -306,7 +307,7 @@ |
307 | 308 | * $title must be a Title object |
308 | 309 | */ |
309 | 310 | function renderChildren( &$title, $depth=1 ) { |
310 | | - global $wgCategoryTreeMaxChildren; |
| 311 | + global $wgCategoryTreeMaxChildren, $wgVersion; |
311 | 312 | |
312 | 313 | if( $title->getNamespace() != NS_CATEGORY ) { |
313 | 314 | // Non-categories can't have children. :) |
— | — | @@ -315,10 +316,6 @@ |
316 | 317 | |
317 | 318 | $dbr =& wfGetDB( DB_SLAVE ); |
318 | 319 | |
319 | | - #additional stuff to be used if "transaltion" by interwiki-links is desired |
320 | | - $transFields = ''; |
321 | | - $transJoin = ''; |
322 | | - $transWhere = ''; |
323 | 320 | |
324 | 321 | $mode = $this->getOption('mode'); |
325 | 322 | |
— | — | @@ -327,14 +324,33 @@ |
328 | 325 | else if ( $mode == CT_MODE_PAGES ) $nsmatch = ' AND cat.page_namespace != ' . NS_IMAGE; |
329 | 326 | else $nsmatch = ' AND cat.page_namespace = ' . NS_CATEGORY; |
330 | 327 | |
| 328 | + #additional stuff to be used if "transaltion" by interwiki-links is desired |
| 329 | + $transFields = ''; |
| 330 | + $transJoin = ''; |
| 331 | + $transWhere = ''; |
| 332 | + |
| 333 | + # fetch member count if possible |
| 334 | + $doCount = version_compare( $wgVersion, "1.12", '>' ); |
| 335 | + |
| 336 | + $countFields = ''; |
| 337 | + $countJoin = ''; |
| 338 | + |
| 339 | + if ( $doCount ) { |
| 340 | + $cat = $dbr->tableName( 'category' ); |
| 341 | + $countJoin = " LEFT JOIN $cat ON cat_title = page_title AND page_namespace = " . NS_CATEGORY; |
| 342 | + $countFields = ', cat_id, cat_title, cat_subcats, cat_pages, cat_files'; |
| 343 | + } |
| 344 | + |
331 | 345 | $page = $dbr->tableName( 'page' ); |
332 | 346 | $categorylinks = $dbr->tableName( 'categorylinks' ); |
333 | 347 | |
334 | 348 | $sql = "SELECT cat.page_namespace, cat.page_title |
335 | 349 | $transFields |
| 350 | + $countFields |
336 | 351 | FROM $page as cat |
337 | 352 | JOIN $categorylinks ON cl_from = cat.page_id |
338 | 353 | $transJoin |
| 354 | + $countJoin |
339 | 355 | WHERE cl_to = " . $dbr->addQuotes( $title->getDBkey() ) . " |
340 | 356 | $nsmatch |
341 | 357 | "./*AND cat.page_is_redirect = 0*/" |
— | — | @@ -348,14 +364,20 @@ |
349 | 365 | $categories= ''; |
350 | 366 | $other= ''; |
351 | 367 | |
352 | | - while ( $row = $dbr->fetchRow( $res ) ) { |
| 368 | + while ( $row = $dbr->fetchObject( $res ) ) { |
353 | 369 | #TODO: translation support; ideally added to Title object |
354 | | - $t = Title::makeTitle( $row['page_namespace'], $row['page_title'] ); |
| 370 | + $t = Title::newFromRow( $row ); |
355 | 371 | |
356 | | - $s = $this->renderNode( $t, $depth-1, false ); |
| 372 | + $cat = NULL; |
| 373 | + |
| 374 | + if ( $doCount && $row->page_namespace == NS_CATEGORY ) { |
| 375 | + $cat = Category::newFromRow( $row, $t ); |
| 376 | + } |
| 377 | + |
| 378 | + $s = $this->renderNodeInfo( $t, $cat, $depth-1, false ); |
357 | 379 | $s .= "\n\t\t"; |
358 | 380 | |
359 | | - if ($row['page_namespace'] == NS_CATEGORY) $categories .= $s; |
| 381 | + if ($row->page_namespace == NS_CATEGORY) $categories .= $s; |
360 | 382 | else $other .= $s; |
361 | 383 | } |
362 | 384 | |
— | — | @@ -394,9 +416,9 @@ |
395 | 417 | |
396 | 418 | $s= ''; |
397 | 419 | |
398 | | - while ( $row = $dbr->fetchRow( $res ) ) { |
| 420 | + while ( $row = $dbr->fetchObject( $res ) ) { |
399 | 421 | #TODO: translation support; ideally added to Title object |
400 | | - $t = Title::makeTitle( $row['page_namespace'], $row['page_title'] ); |
| 422 | + $t = Title::newFromRow( $row ); |
401 | 423 | |
402 | 424 | #$trans = $title->getLocalizedText(); |
403 | 425 | $trans = ''; #place holder for when translated titles are available |
— | — | @@ -424,8 +446,18 @@ |
425 | 447 | * Returns a string with a HTML represenation of the given page. |
426 | 448 | * $title must be a Title object |
427 | 449 | */ |
428 | | - function renderNode( &$title, $children = 0, $loadchildren = false ) { |
429 | | - global $wgCategoryTreeDefaultMode; |
| 450 | + function renderNode( $title, $children = 0, $loadchildren = false ) { |
| 451 | + if ( $title->getNamespace() == NS_CATEGORY ) $cat = Category::newFromTitle( $title ); |
| 452 | + else $cat = NULL; |
| 453 | + |
| 454 | + return $this->renderNodeInfo( $title, $cat, $children, $loadchildren ); |
| 455 | + } |
| 456 | + |
| 457 | + /** |
| 458 | + * Returns a string with a HTML represenation of the given page. |
| 459 | + * $info must be an associative array, containing at least a Title object under the 'title' key. |
| 460 | + */ |
| 461 | + function renderNodeInfo( $title, $cat, $children = 0, $loadchildren = false ) { |
430 | 462 | static $uniq = 0; |
431 | 463 | |
432 | 464 | $mode = $this->getOption('mode'); |
— | — | @@ -462,6 +494,7 @@ |
463 | 495 | |
464 | 496 | if ( ( $ns % 2 ) > 0 ) $labelClass .= ' CategoryTreeLabelTalk'; |
465 | 497 | |
| 498 | + $count = false; |
466 | 499 | $s = ''; |
467 | 500 | |
468 | 501 | #NOTE: things in CategoryTree.js rely on the exact order of tags! |
— | — | @@ -475,25 +508,37 @@ |
476 | 509 | $s .= Xml::openElement( 'span', $attr ); |
477 | 510 | |
478 | 511 | if ( $ns == NS_CATEGORY ) { |
| 512 | + if ( $cat ) { |
| 513 | + if ( $mode == CT_MODE_CATEGORIES ) $count = $cat->getSubcatCount(); |
| 514 | + else if ( $mode == CT_MODE_PAGES ) $count = $cat->getPageCount() - $cat->getFileCount(); |
| 515 | + else $count = $cat->getPageCount(); |
| 516 | + } |
| 517 | + |
479 | 518 | $linkattr= array( 'href' => $wikiLink ); |
480 | 519 | if ( $load ) $linkattr[ 'id' ] = $load; |
481 | 520 | |
482 | 521 | $linkattr[ 'class' ] = "CategoryTreeToggle"; |
483 | 522 | |
484 | | - if ( $children == 0 || $loadchildren ) { |
| 523 | + if ( $count === 0 ) { |
| 524 | + $tag = 'span'; |
| 525 | + $txt = $this->msg('empty-bullet'); |
| 526 | + } |
| 527 | + else if ( $children == 0 || $loadchildren ) { |
| 528 | + $tag = 'a'; |
485 | 529 | $txt = $this->msg('expand-bullet'); |
486 | 530 | $linkattr[ 'onclick' ] = "this.href='javascript:void(0)'; categoryTreeExpandNode('".Xml::escapeJsString($key)."',".$this->getOptionsAsJsStructure().",this);"; |
487 | 531 | # Don't load this message for ajax requests, so that we don't have to initialise $wgLang |
488 | 532 | $linkattr[ 'title' ] = $this->mIsAjaxRequest ? '##LOAD##' : self::msg('expand'); |
489 | 533 | } |
490 | 534 | else { |
| 535 | + $tag = 'a'; |
491 | 536 | $txt = $this->msg('collapse-bullet'); |
492 | 537 | $linkattr[ 'onclick' ] = "this.href='javascript:void(0)'; categoryTreeCollapseNode('".Xml::escapeJsString($key)."',".$this->getOptionsAsJsStructure().",this);"; |
493 | 538 | $linkattr[ 'title' ] = self::msg('collapse'); |
494 | 539 | $linkattr[ 'class' ] .= ' CategoryTreeLoaded'; |
495 | 540 | } |
496 | 541 | |
497 | | - $s .= Xml::openElement( 'a', $linkattr ) . $txt . Xml::closeElement( 'a' ) . ' '; |
| 542 | + $s .= Xml::openElement( $tag, $linkattr ) . $txt . Xml::closeElement( $tag ) . ' '; |
498 | 543 | } else { |
499 | 544 | $s .= $this->msg('page-bullet'); |
500 | 545 | } |
— | — | @@ -501,6 +546,17 @@ |
502 | 547 | $s .= Xml::closeElement( 'span' ); |
503 | 548 | |
504 | 549 | $s .= Xml::openElement( 'a', array( 'class' => $labelClass, 'href' => $wikiLink ) ) . $label . Xml::closeElement( 'a' ); |
| 550 | + |
| 551 | + if ( $count !== false && $this->getOption( 'showcount' ) ) { |
| 552 | + $pages = $cat->getPageCount() - $cat->getSubcatCount() - $cat->getFileCount(); |
| 553 | + |
| 554 | + $attr = array( |
| 555 | + 'title' => $this->msg( 'member-counts', $cat->getSubcatCount(), $pages , $cat->getFileCount() ) |
| 556 | + ); |
| 557 | + |
| 558 | + $s .= Xml::element( 'span', $attr, ' (' . $count . ')' ); |
| 559 | + } |
| 560 | + |
505 | 561 | $s .= Xml::closeElement( 'div' ); |
506 | 562 | $s .= "\n\t\t"; |
507 | 563 | $s .= Xml::openElement( 'div', array( 'class' => 'CategoryTreeChildren', 'style' => $children > 0 ? "display:block" : "display:none" ) ); |