diff --git a/CategoryPageSubclass.php b/CategoryPageSubclass.php
index acc5c068..37228d6e 100644
--- a/CategoryPageSubclass.php
+++ b/CategoryPageSubclass.php
@@ -12,7 +12,7 @@ class CategoryTreeCategoryPage extends CategoryPage {
}
class CategoryTreeCategoryViewer extends CategoryViewer {
- var $child_titles;
+ var $child_cats;
function getCategoryTree() {
global $wgOut, $wgCategoryTreeCategoryPageOptions;
@@ -29,25 +29,29 @@ class CategoryTreeCategoryViewer extends CategoryViewer {
/**
* Add a subcategory to the internal lists
*/
- function addSubcategory( $title, $sortkey, $pageLength ) {
+ function addSubcategoryObject( $cat, $sortkey, $pageLength ) {
global $wgContLang, $wgOut, $wgRequest;
+ $title = $cat->getTitle();
+
if ( $wgRequest->getCheck( 'notree' ) ) {
- return parent::addSubcategory( $title, $sortkey, $pageLength );
+ return parent::addSubcategoryObject( $cat, $sortkey, $pageLength );
}
- if ( ! $GLOBALS['wgCategoryTreeUnifiedView'] ) {
- $this->child_titles[] = $title;
- return parent::addSubcategory( $title, $sortkey, $pageLength );
- }
+ /*if ( ! $GLOBALS['wgCategoryTreeUnifiedView'] ) {
+ $this->child_cats[] = $cat;
+ return parent::addSubcategory( $cat, $sortkey, $pageLength );
+ }*/
$tree = $this->getCategoryTree();
- $this->children[] = $tree->renderNode( $title );
+ $this->children[] = $tree->renderNodeInfo( $title, $cat );
$this->children_start_char[] = $this->getSubcategorySortChar( $title, $sortkey );
}
+ /*
+ # this is a pain to keep this consistent, and no one should be using wgCategoryTreeUnifiedView = false anyway.
function getSubcategorySection() {
global $wgOut, $wgRequest, $wgCookiePrefix;
@@ -107,14 +111,14 @@ class CategoryTreeCategoryViewer extends CategoryViewer {
if ( $showAs == 'list' ) {
$r .= $this->formatList( $this->children, $this->children_start_char );
} else {
- $ct = getCategoryTree();
+ $ct = $this->getCategoryTree();
- foreach ( $this->child_titles as $title ) {
- $r .= $ct->renderNode( $title );
+ foreach ( $this->child_cats as $cat ) {
+ $r .= $ct->renderNodeInfo( $cat->getTitle(), $cat );
}
}
return $r;
- }
+ }*/
function makeShowAsLink( $targetValue, $currentValue ) {
$msg = htmlspecialchars( CategoryTree::msg( "show-$targetValue" ) );
@@ -127,13 +131,13 @@ class CategoryTreeCategoryViewer extends CategoryViewer {
}
function clearCategoryState() {
- $this->child_titles = array();
+ $this->child_cats = array();
parent::clearCategoryState();
}
function finaliseCategoryState() {
if( $this->flip ) {
- $this->child_titles = array_reverse( $this->child_titles );
+ $this->child_cats = array_reverse( $this->child_cats );
}
parent::finaliseCategoryState();
}
diff --git a/CategoryTree.i18n.php b/CategoryTree.i18n.php
index 46db931c..bcdd019f 100644
--- a/CategoryTree.i18n.php
+++ b/CategoryTree.i18n.php
@@ -34,8 +34,11 @@ If you have a very old browser, or have JavaScript disabled, it will not work.',
'categorytree-expand' => 'expand',
'categorytree-collapse-bullet' => '[−]', # do not translate or duplicate this message to other languages
'categorytree-expand-bullet' => '[+]', # do not translate or duplicate this message to other languages
+ 'categorytree-empty-bullet' => '[×]', # do not translate or duplicate this message to other languages
'categorytree-page-bullet' => ' ', # do not translate or duplicate this message to other languages
+ 'categorytree-member-counts' => 'contains $1 subcategories, $2 pages, and $3 files',
+
'categorytree-load' => 'load',
'categorytree-loading' => 'loading…',
'categorytree-nothing-found' => 'nothing found',
@@ -596,6 +599,7 @@ Diese Seite benötigt bestimmte JavaScript-Funktionen (Ajax) und funktioniert m
'categorytree-category' => 'Kategorie:',
'categorytree-go' => 'Laden',
'categorytree-parents' => 'Oberkategorien',
+ 'categorytree-member-counts' => 'enthält $1 Unterkategorien, $2 Seiten und $3 Dateien',
'categorytree-mode-categories' => 'nur Kategorien',
'categorytree-mode-pages' => 'Seiten außer Bilder',
'categorytree-mode-all' => 'alle Seiten',
diff --git a/CategoryTree.php b/CategoryTree.php
index ea9c4e39..3edcd390 100644
--- a/CategoryTree.php
+++ b/CategoryTree.php
@@ -32,12 +32,13 @@ define('CT_MODE_ALL', 20);
* This way, the cache does not need to be disabled. Default is false.
* $wgCategoryTreeDisableCache - disabled the parser cache for pages with a tag. Default is true.
* $wgCategoryTreeUseCache - enable HTTP cache for anon users. Default is false.
- * $wgCategoryTreeUnifiedView - use unified view on category pages, instead of "tree" or "traditional list". Default is true.
- * $wgCategoryTreeOmitNamespace - never show namespace prefix. Default is false
* $wgCategoryTreeMaxDepth - maximum value for depth argument; An array that maps mode values to
* the maximum depth acceptable for the depth option.
* Per default, the "categories" mode has a max depth of 2,
* all other modes have a max depth of 1.
+ * $wgCategoryTreeDefaultOptions - default options for the tag.
+ * $wgCategoryTreeCategoryPageOptions - options to apply on category pages.
+ * $wgCategoryTreeSpecialPageOptions - options to apply on Special:CategoryTree.
*/
$wgCategoryTreeMaxChildren = 200;
@@ -45,7 +46,7 @@ $wgCategoryTreeAllowTag = true;
$wgCategoryTreeDisableCache = true;
$wgCategoryTreeDynamicTag = false;
$wgCategoryTreeHTTPCache = false;
-$wgCategoryTreeUnifiedView = true;
+#$wgCategoryTreeUnifiedView = true;
$wgCategoryTreeMaxDepth = array(CT_MODE_PAGES => 1, CT_MODE_ALL => 1, CT_MODE_CATEGORIES => 2);
$wgCategoryTreeExtPath = '/extensions/CategoryTree';
@@ -56,11 +57,16 @@ $wgCategoryTreeDefaultMode = CT_MODE_CATEGORIES;
$wgCategoryTreeDefaultOptions = array(); #Default values for most options. ADD NEW OPTIONS HERE!
$wgCategoryTreeDefaultOptions['mode'] = NULL; # will be set to $wgCategoryTreeDefaultMode in efCategoryTree(); compatibility quirk
$wgCategoryTreeDefaultOptions['hideprefix'] = NULL; # will be set to $wgCategoryTreeDefaultMode in efCategoryTree(); compatibility quirk
+$wgCategoryTreeDefaultOptions['showcount'] = false;
#TODO: hideprefix: always, never, catonly, catonly_if_onlycat
$wgCategoryTreeCategoryPageMode = CT_MODE_CATEGORIES;
$wgCategoryTreeCategoryPageOptions = array(); #Options to be used for category pages
$wgCategoryTreeCategoryPageOptions['mode'] = NULL; # will be set to $wgCategoryTreeDefaultMode in efCategoryTree(); compatibility quirk
+$wgCategoryTreeCategoryPageOptions['showcount'] = true;
+
+$wgCategoryTreeSpecialPageOptions = array(); #Options to be used for Special:CategoryTree
+$wgCategoryTreeSpecialPageOptions['showcount'] = true;
/**
* Register extension setup hook and credits
diff --git a/CategoryTreeFunctions.php b/CategoryTreeFunctions.php
index 7b26e9a2..a69ff1cc 100644
--- a/CategoryTreeFunctions.php
+++ b/CategoryTreeFunctions.php
@@ -32,6 +32,7 @@ class CategoryTree {
$this->mOptions['mode'] = self::decodeMode( $this->mOptions['mode'] );
$this->mOptions['hideprefix'] = self::decodeBoolean( $this->mOptions['hideprefix'] );
+ $this->mOptions['showcount'] = self::decodeBoolean( $this->mOptions['showcount'] );
}
function getOption( $name ) {
@@ -66,7 +67,7 @@ class CategoryTree {
if ( is_int( $value ) ) return ( $value > 0 );
$value = trim( strtolower( $value ) );
- if ( is_numeric( $value ) ) return ( (int)$mode > 0 );
+ if ( is_numeric( $value ) ) return ( (int)$value > 0 );
if ( $value == 'yes' || $value == 'y' || $value == 'true' || $value == 't' || $value == 'on' ) return true;
else if ( $value == 'no' || $value == 'n' || $value == 'false' || $value == 'f' || $value == 'off' ) return false;
@@ -306,7 +307,7 @@ class CategoryTree {
* $title must be a Title object
*/
function renderChildren( &$title, $depth=1 ) {
- global $wgCategoryTreeMaxChildren;
+ global $wgCategoryTreeMaxChildren, $wgVersion;
if( $title->getNamespace() != NS_CATEGORY ) {
// Non-categories can't have children. :)
@@ -315,10 +316,6 @@ class CategoryTree {
$dbr =& wfGetDB( DB_SLAVE );
- #additional stuff to be used if "transaltion" by interwiki-links is desired
- $transFields = '';
- $transJoin = '';
- $transWhere = '';
$mode = $this->getOption('mode');
@@ -327,14 +324,33 @@ class CategoryTree {
else if ( $mode == CT_MODE_PAGES ) $nsmatch = ' AND cat.page_namespace != ' . NS_IMAGE;
else $nsmatch = ' AND cat.page_namespace = ' . NS_CATEGORY;
+ #additional stuff to be used if "transaltion" by interwiki-links is desired
+ $transFields = '';
+ $transJoin = '';
+ $transWhere = '';
+
+ # fetch member count if possible
+ $doCount = version_compare( $wgVersion, "1.12", '>' );
+
+ $countFields = '';
+ $countJoin = '';
+
+ if ( $doCount ) {
+ $cat = $dbr->tableName( 'category' );
+ $countJoin = " LEFT JOIN $cat ON cat_title = page_title AND page_namespace = " . NS_CATEGORY;
+ $countFields = ', cat_id, cat_title, cat_subcats, cat_pages, cat_files';
+ }
+
$page = $dbr->tableName( 'page' );
$categorylinks = $dbr->tableName( 'categorylinks' );
$sql = "SELECT cat.page_namespace, cat.page_title
$transFields
+ $countFields
FROM $page as cat
JOIN $categorylinks ON cl_from = cat.page_id
$transJoin
+ $countJoin
WHERE cl_to = " . $dbr->addQuotes( $title->getDBkey() ) . "
$nsmatch
"./*AND cat.page_is_redirect = 0*/"
@@ -348,14 +364,20 @@ class CategoryTree {
$categories= '';
$other= '';
- while ( $row = $dbr->fetchRow( $res ) ) {
+ while ( $row = $dbr->fetchObject( $res ) ) {
#TODO: translation support; ideally added to Title object
- $t = Title::makeTitle( $row['page_namespace'], $row['page_title'] );
+ $t = Title::newFromRow( $row );
- $s = $this->renderNode( $t, $depth-1, false );
+ $cat = NULL;
+
+ if ( $doCount && $row->page_namespace == NS_CATEGORY ) {
+ $cat = Category::newFromRow( $row, $t );
+ }
+
+ $s = $this->renderNodeInfo( $t, $cat, $depth-1, false );
$s .= "\n\t\t";
- if ($row['page_namespace'] == NS_CATEGORY) $categories .= $s;
+ if ($row->page_namespace == NS_CATEGORY) $categories .= $s;
else $other .= $s;
}
@@ -394,9 +416,9 @@ class CategoryTree {
$s= '';
- while ( $row = $dbr->fetchRow( $res ) ) {
+ while ( $row = $dbr->fetchObject( $res ) ) {
#TODO: translation support; ideally added to Title object
- $t = Title::makeTitle( $row['page_namespace'], $row['page_title'] );
+ $t = Title::newFromRow( $row );
#$trans = $title->getLocalizedText();
$trans = ''; #place holder for when translated titles are available
@@ -424,8 +446,18 @@ class CategoryTree {
* Returns a string with a HTML represenation of the given page.
* $title must be a Title object
*/
- function renderNode( &$title, $children = 0, $loadchildren = false ) {
- global $wgCategoryTreeDefaultMode;
+ function renderNode( $title, $children = 0, $loadchildren = false ) {
+ if ( $title->getNamespace() == NS_CATEGORY ) $cat = Category::newFromTitle( $title );
+ else $cat = NULL;
+
+ return $this->renderNodeInfo( $title, $cat, $children, $loadchildren );
+ }
+
+ /**
+ * Returns a string with a HTML represenation of the given page.
+ * $info must be an associative array, containing at least a Title object under the 'title' key.
+ */
+ function renderNodeInfo( $title, $cat, $children = 0, $loadchildren = false ) {
static $uniq = 0;
$mode = $this->getOption('mode');
@@ -462,6 +494,7 @@ class CategoryTree {
if ( ( $ns % 2 ) > 0 ) $labelClass .= ' CategoryTreeLabelTalk';
+ $count = false;
$s = '';
#NOTE: things in CategoryTree.js rely on the exact order of tags!
@@ -475,25 +508,37 @@ class CategoryTree {
$s .= Xml::openElement( 'span', $attr );
if ( $ns == NS_CATEGORY ) {
+ if ( $cat ) {
+ if ( $mode == CT_MODE_CATEGORIES ) $count = $cat->getSubcatCount();
+ else if ( $mode == CT_MODE_PAGES ) $count = $cat->getPageCount() - $cat->getFileCount();
+ else $count = $cat->getPageCount();
+ }
+
$linkattr= array( 'href' => $wikiLink );
if ( $load ) $linkattr[ 'id' ] = $load;
$linkattr[ 'class' ] = "CategoryTreeToggle";
- if ( $children == 0 || $loadchildren ) {
+ if ( $count === 0 ) {
+ $tag = 'span';
+ $txt = $this->msg('empty-bullet');
+ }
+ else if ( $children == 0 || $loadchildren ) {
+ $tag = 'a';
$txt = $this->msg('expand-bullet');
$linkattr[ 'onclick' ] = "this.href='javascript:void(0)'; categoryTreeExpandNode('".Xml::escapeJsString($key)."',".$this->getOptionsAsJsStructure().",this);";
# Don't load this message for ajax requests, so that we don't have to initialise $wgLang
$linkattr[ 'title' ] = $this->mIsAjaxRequest ? '##LOAD##' : self::msg('expand');
}
else {
+ $tag = 'a';
$txt = $this->msg('collapse-bullet');
$linkattr[ 'onclick' ] = "this.href='javascript:void(0)'; categoryTreeCollapseNode('".Xml::escapeJsString($key)."',".$this->getOptionsAsJsStructure().",this);";
$linkattr[ 'title' ] = self::msg('collapse');
$linkattr[ 'class' ] .= ' CategoryTreeLoaded';
}
- $s .= Xml::openElement( 'a', $linkattr ) . $txt . Xml::closeElement( 'a' ) . ' ';
+ $s .= Xml::openElement( $tag, $linkattr ) . $txt . Xml::closeElement( $tag ) . ' ';
} else {
$s .= $this->msg('page-bullet');
}
@@ -501,6 +546,17 @@ class CategoryTree {
$s .= Xml::closeElement( 'span' );
$s .= Xml::openElement( 'a', array( 'class' => $labelClass, 'href' => $wikiLink ) ) . $label . Xml::closeElement( 'a' );
+
+ if ( $count !== false && $this->getOption( 'showcount' ) ) {
+ $pages = $cat->getPageCount() - $cat->getSubcatCount() - $cat->getFileCount();
+
+ $attr = array(
+ 'title' => $this->msg( 'member-counts', $cat->getSubcatCount(), $pages , $cat->getFileCount() )
+ );
+
+ $s .= Xml::element( 'span', $attr, ' (' . $count . ')' );
+ }
+
$s .= Xml::closeElement( 'div' );
$s .= "\n\t\t";
$s .= Xml::openElement( 'div', array( 'class' => 'CategoryTreeChildren', 'style' => $children > 0 ? "display:block" : "display:none" ) );
diff --git a/CategoryTreePage.php b/CategoryTreePage.php
index a44544f1..30a61e1e 100644
--- a/CategoryTreePage.php
+++ b/CategoryTreePage.php
@@ -40,7 +40,7 @@ class CategoryTreePage extends SpecialPage {
* @param $par Parameters passed to the page
*/
function execute( $par ) {
- global $wgRequest, $wgOut, $wgMakeBotPrivileged, $wgUser, $wgCategoryTreeDefaultOptions;
+ global $wgRequest, $wgOut, $wgCategoryTreeDefaultOptions, $wgCategoryTreeSpecialPageOptions;
$this->setHeaders();
@@ -56,6 +56,9 @@ class CategoryTreePage extends SpecialPage {
# grab all known options from the request. Normalization is done by the CategoryTree class
foreach ( $wgCategoryTreeDefaultOptions as $option => $default ) {
+ if ( isset( $wgCategoryTreeSpecialPageOptions[$option] ) )
+ $default = $wgCategoryTreeSpecialPageOptions[$option];
+
$options[$option] = $wgRequest->getVal( $option, $default );
}