4
* Setup and Hooks for the CategoryTree extension, an AJAX based gadget
5
* to display the category structure of a wiki
7
* @addtogroup Extensions
8
* @author Daniel Kinzler, brightbyte.de
9
* @copyright © 2006-2008 Daniel Kinzler and others
10
* @license GNU General Public Licence 2.0 or later
13
if( !defined( 'MEDIAWIKI' ) ) {
14
echo( "This file is an extension to the MediaWiki software and cannot be used standalone.\n" );
19
* Constants for use with the mode,
20
* defining what should be shown in the tree
22
define('CT_MODE_CATEGORIES', 0);
23
define('CT_MODE_PAGES', 10);
24
define('CT_MODE_ALL', 20);
25
define('CT_MODE_PARENTS', 100);
28
* Constants for use with the hideprefix option,
29
* defining when the namespace prefix should be hidden
31
define('CT_HIDEPREFIX_NEVER', 0);
32
define('CT_HIDEPREFIX_ALWAYS', 10);
33
define('CT_HIDEPREFIX_CATEGORIES', 20);
34
define('CT_HIDEPREFIX_AUTO', 30);
39
* $wgCategoryTreeMaxChildren - maximum number of children shown in a tree node. Default is 200
40
* $wgCategoryTreeAllowTag - enable <categorytree> tag. Default is true.
41
* $wgCategoryTreeDynamicTag - loads the first level of the tree in a <categorytag> dynamically.
42
* This way, the cache does not need to be disabled. Default is false.
43
* $wgCategoryTreeDisableCache - disabled the parser cache for pages with a <categorytree> tag. Default is true.
44
* $wgCategoryTreeUseCache - enable HTTP cache for anon users. Default is false.
45
* $wgCategoryTreeMaxDepth - maximum value for depth argument; An array that maps mode values to
46
* the maximum depth acceptable for the depth option.
47
* Per default, the "categories" mode has a max depth of 2,
48
* all other modes have a max depth of 1.
49
* $wgCategoryTreeDefaultOptions - default options for the <categorytree> tag.
50
* $wgCategoryTreeCategoryPageOptions - options to apply on category pages.
51
* $wgCategoryTreeSpecialPageOptions - options to apply on Special:CategoryTree.
54
$wgCategoryTreeMaxChildren = 200;
55
$wgCategoryTreeAllowTag = true;
56
$wgCategoryTreeDisableCache = true;
57
$wgCategoryTreeDynamicTag = false;
58
$wgCategoryTreeHTTPCache = false;
59
#$wgCategoryTreeUnifiedView = true;
60
$wgCategoryTreeMaxDepth = array(CT_MODE_PAGES => 1, CT_MODE_ALL => 1, CT_MODE_CATEGORIES => 2);
62
# Set $wgCategoryTreeForceHeaders to true to force the JS and CSS headers for CategoryTree to be included on every page.
63
# May be usefull for using CategoryTree from within system messages, in the sidebar, or a custom skin.
64
$wgCategoryTreeForceHeaders = false;
65
$wgCategoryTreeSidebarRoot = NULL;
66
$wgCategoryTreeHijackPageCategories = false; # EXPERIMENTAL! NOT YET FOR PRODUCTION USE! Main problem is general HTML/CSS layout cruftiness.
68
$wgCategoryTreeExtPath = '/extensions/CategoryTree';
69
$wgCategoryTreeVersion = '5'; #NOTE: bump this when you change the CSS or JS files!
70
$wgCategoryTreeUseCategoryTable = version_compare( $wgVersion, "1.13", '>=' );
72
$wgCategoryTreeOmitNamespace = CT_HIDEPREFIX_CATEGORIES;
73
$wgCategoryTreeDefaultMode = CT_MODE_CATEGORIES;
74
$wgCategoryTreeDefaultOptions = array(); #Default values for most options. ADD NEW OPTIONS HERE!
75
$wgCategoryTreeDefaultOptions['mode'] = NULL; # will be set to $wgCategoryTreeDefaultMode in efCategoryTree(); compatibility quirk
76
$wgCategoryTreeDefaultOptions['hideprefix'] = NULL; # will be set to $wgCategoryTreeDefaultMode in efCategoryTree(); compatibility quirk
77
$wgCategoryTreeDefaultOptions['showcount'] = false;
78
$wgCategoryTreeDefaultOptions['namespaces'] = false; # false means "no filter"
80
$wgCategoryTreeCategoryPageMode = CT_MODE_CATEGORIES;
81
$wgCategoryTreeCategoryPageOptions = array(); #Options to be used for category pages
82
$wgCategoryTreeCategoryPageOptions['mode'] = NULL; # will be set to $wgCategoryTreeDefaultMode in efCategoryTree(); compatibility quirk
83
$wgCategoryTreeCategoryPageOptions['showcount'] = true;
85
$wgCategoryTreeSpecialPageOptions = array(); #Options to be used for Special:CategoryTree
86
$wgCategoryTreeSpecialPageOptions['showcount'] = true;
88
$wgCategoryTreeSidebarOptions = array(); #Options to be used in the sidebar (for use with $wgCategoryTreeSidebarRoot)
89
$wgCategoryTreeSidebarOptions['mode'] = CT_MODE_CATEGORIES;
90
$wgCategoryTreeSidebarOptions['hideprefix'] = CT_HIDEPREFIX_CATEGORIES;
91
$wgCategoryTreeSidebarOptions['showcount'] = false;
92
$wgCategoryTreeSidebarOptions['hideroot'] = true;
93
$wgCategoryTreeSidebarOptions['namespaces'] = false;
94
$wgCategoryTreeSidebarOptions['depth'] = 1;
96
$wgCategoryTreePageCategoryOptions = array(); #Options to be used in the sidebar (for use with $wgCategoryTreePageCategories)
97
$wgCategoryTreePageCategoryOptions['mode'] = CT_MODE_PARENTS;
98
$wgCategoryTreePageCategoryOptions['hideprefix'] = CT_HIDEPREFIX_CATEGORIES;
99
$wgCategoryTreePageCategoryOptions['showcount'] = false;
100
$wgCategoryTreePageCategoryOptions['hideroot'] = false;
101
$wgCategoryTreePageCategoryOptions['namespaces'] = false;
102
$wgCategoryTreePageCategoryOptions['depth'] = 0;
103
#$wgCategoryTreePageCategoryOptions['class'] = 'CategoryTreeInlineNode';
105
$wgExtensionAliasesFiles['CategoryTree'] = dirname(__FILE__) . '/CategoryTreePage.i18n.alias.php';
108
* Register extension setup hook and credits
110
$wgExtensionFunctions[] = 'efCategoryTree';
111
$wgExtensionCredits['specialpage'][] = array(
112
'name' => 'CategoryTree',
113
'svn-date' => '$LastChangedDate: 2009-03-09 12:54:39 +0100 (lun 09 mar 2009) $',
114
'svn-revision' => '$LastChangedRevision: 48218 $',
115
'author' => 'Daniel Kinzler',
116
'url' => 'http://www.mediawiki.org/wiki/Extension:CategoryTree',
117
'description' => 'Dynamically navigate the category structure',
118
'descriptionmsg' => 'categorytree-desc',
120
$wgExtensionCredits['parserhook'][] = array(
121
'name' => 'CategoryTree',
122
'svn-date' => '$LastChangedDate: 2009-03-09 12:54:39 +0100 (lun 09 mar 2009) $',
123
'svn-revision' => '$LastChangedRevision: 48218 $',
124
'author' => 'Daniel Kinzler',
125
'url' => 'http://www.mediawiki.org/wiki/Extension:CategoryTree',
126
'description' => 'Dynamically navigate the category structure',
127
'descriptionmsg' => 'categorytree-desc',
131
* Register the special page
133
$dir = dirname(__FILE__) . '/';
134
$wgExtensionMessagesFiles['CategoryTree'] = $dir . 'CategoryTree.i18n.php';
135
$wgAutoloadClasses['CategoryTreePage'] = $dir . 'CategoryTreePage.php';
136
$wgAutoloadClasses['CategoryTree'] = $dir . 'CategoryTreeFunctions.php';
137
$wgAutoloadClasses['CategoryTreeCategoryPage'] = $dir . 'CategoryPageSubclass.php';
138
$wgSpecialPages['CategoryTree'] = 'CategoryTreePage';
139
$wgSpecialPageGroups['CategoryTree'] = 'pages';
140
#$wgHooks['SkinTemplateTabs'][] = 'efCategoryTreeInstallTabs';
141
$wgHooks['ArticleFromTitle'][] = 'efCategoryTreeArticleFromTitle';
142
$wgHooks['LanguageGetMagic'][] = 'efCategoryTreeGetMagic';
145
* register Ajax function
147
$wgAjaxExportList[] = 'efCategoryTreeAjaxWrapper';
152
function efCategoryTree() {
153
global $wgUseAjax, $wgHooks, $wgOut;
154
global $wgCategoryTreeDefaultOptions, $wgCategoryTreeDefaultMode, $wgCategoryTreeOmitNamespace;
155
global $wgCategoryTreeCategoryPageOptions, $wgCategoryTreeCategoryPageMode;
156
global $wgCategoryTreeSidebarRoot, $wgCategoryTreeForceHeaders, $wgCategoryTreeHijackPageCategories;
158
# Abort if AJAX is not enabled
160
wfDebug( 'efCategoryTree: $wgUseAjax is not enabled, aborting extension setup.' );
164
if ( $wgCategoryTreeSidebarRoot ) {
165
$wgCategoryTreeForceHeaders = true; # needed on every page anyway
166
$wgHooks['SkinTemplateOutputPageBeforeExec'][] = 'efCategoryTreeSkinTemplateOutputPageBeforeExec';
169
if ( $wgCategoryTreeHijackPageCategories ) {
170
$wgCategoryTreeForceHeaders = true; # needed on almost every page anyway
171
$wgHooks['OutputPageMakeCategoryLinks'][] = 'efCategoryTreeOutputPageMakeCategoryLinks';
172
$wgHooks['SkinJoinCategoryLinks'][] = 'efCategoryTreeSkinJoinCategoryLinks';
175
if ( defined( 'MW_SUPPORTS_PARSERFIRSTCALLINIT' ) ) {
176
$wgHooks['ParserFirstCallInit'][] = 'efCategoryTreeSetHooks';
178
efCategoryTreeSetHooks();
181
if ( !isset( $wgCategoryTreeDefaultOptions['mode'] ) || is_null( $wgCategoryTreeDefaultOptions['mode'] ) ) {
182
$wgCategoryTreeDefaultOptions['mode'] = $wgCategoryTreeDefaultMode;
185
if ( !isset( $wgCategoryTreeDefaultOptions['hideprefix'] ) || is_null( $wgCategoryTreeDefaultOptions['hideprefix'] ) ) {
186
$wgCategoryTreeDefaultOptions['hideprefix'] = $wgCategoryTreeOmitNamespace;
189
if ( !isset( $wgCategoryTreeCategoryPageOptions['mode'] ) || is_null( $wgCategoryTreeCategoryPageOptions['mode'] ) ) {
190
$wgCategoryTreeCategoryPageOptions['mode'] = $wgCategoryTreeCategoryPageMode;
193
if ( $wgCategoryTreeForceHeaders ) {
194
CategoryTree::setHeaders( $wgOut );
197
$wgHooks['OutputPageParserOutput'][] = 'efCategoryTreeParserOutput';
201
function efCategoryTreeSetHooks() {
202
global $wgParser, $wgCategoryTreeAllowTag;
203
if ( $wgCategoryTreeAllowTag ) {
204
$wgParser->setHook( 'categorytree' , 'efCategoryTreeParserHook' );
205
$wgParser->setFunctionHook( 'categorytree' , 'efCategoryTreeParserFunction' );
213
function efCategoryTreeGetMagic( &$magicWords, $langCode ) {
214
global $wgUseAjax, $wgCategoryTreeAllowTag;
216
if ( $wgUseAjax && $wgCategoryTreeAllowTag ) {
217
//XXX: should we allow a local alias?
218
$magicWords['categorytree'] = array( 0, 'categorytree' );
225
* Entry point for Ajax, registered in $wgAjaxExportList.
226
* The $enc parameter determins how the $options is decoded into a PHP array.
227
* If $enc is not given, '' is asumed, which simulates the old call interface,
228
* namely, only providing the mode name or number.
229
* This loads CategoryTreeFunctions.php and calls CategoryTree::ajax()
231
function efCategoryTreeAjaxWrapper( $category, $options, $enc = '' ) {
232
global $wgCategoryTreeHTTPCache, $wgSquidMaxage, $wgUseSquid;
234
if ( is_string( $options ) ) {
235
$options = CategoryTree::decodeOptions( $options, $enc );
238
$depth = isset( $options['depth'] ) ? (int)$options['depth'] : 1;
240
$ct = new CategoryTree( $options, true );
241
$depth = efCategoryTreeCapDepth( $ct->getOption('mode'), $depth );
242
$response = $ct->ajax( $category, $depth );
244
if ( $wgCategoryTreeHTTPCache && $wgSquidMaxage && $wgUseSquid ) {
245
$response->setCacheDuration( $wgSquidMaxage );
246
$response->setVary( 'Accept-Encoding, Cookie' ); #cache for anons only
247
#TODO: purge the squid cache when a category page is invalidated
254
* Internal function to cap depth
257
function efCategoryTreeCapDepth( $mode, $depth ) {
258
global $wgCategoryTreeMaxDepth;
260
if (is_numeric($depth))
261
$depth = intval($depth);
264
if (is_array($wgCategoryTreeMaxDepth)) {
265
$max = isset($wgCategoryTreeMaxDepth[$mode]) ? $wgCategoryTreeMaxDepth[$mode] : 1;
266
} elseif (is_numeric($wgCategoryTreeMaxDepth)) {
267
$max = $wgCategoryTreeMaxDepth;
269
wfDebug( 'efCategoryTreeCapDepth: $wgCategoryTreeMaxDepth is invalid.' );
273
return min($depth, $max);
277
* Entry point for the {{#categorytree}} tag parser function.
278
* This is a wrapper around efCategoryTreeParserHook
280
function efCategoryTreeParserFunction( &$parser ) {
281
$params = func_get_args();
282
array_shift( $params ); //first is &$parser, strip it
284
//first user-supplied parameter must be category name
285
if ( !$params ) return ''; //no category specified, return nothing
286
$cat = array_shift( $params );
288
//build associative arguments from flat parameter list
290
foreach ( $params as $p ) {
291
if ( preg_match('/^\s*(\S.*?)\s*=\s*(.*?)\s*$/', $p, $m) ) {
293
$v = preg_replace('/^"\s*(.*?)\s*"$/', '$1', $m[2]); //strip any quotes enclusing the value
303
//now handle just like a <categorytree> tag
304
$html = efCategoryTreeParserHook( $cat, $argv, $parser );
305
return array( $html, 'noparse' => true, 'isHTML' => true );
309
* Hook implementation for injecting a category tree into the sidebar.
310
* Registered automatically if $wgCategoryTreeSidebarRoot is set to a category name.
312
function efCategoryTreeSkinTemplateOutputPageBeforeExec( &$skin, &$tpl ) {
313
global $wgCategoryTreeSidebarRoot, $wgCategoryTreeSidebarOptions;
315
$html = efCategoryTreeParserHook( $wgCategoryTreeSidebarRoot, $wgCategoryTreeSidebarOptions );
316
if ( $html ) $tpl->data['sidebar']['categorytree-portlet'] = $html; //requires MW 1.13, r36917
323
* Entry point for the <categorytree> tag parser hook.
324
* This loads CategoryTreeFunctions.php and calls CategoryTree::getTag()
326
function efCategoryTreeParserHook( $cat, $argv, $parser = NULL, $allowMissing = false ) {
330
$parser->mOutput->mCategoryTreeTag = true; # flag for use by efCategoryTreeParserOutput
333
CategoryTree::setHeaders( $wgOut );
336
$ct = new CategoryTree( $argv );
338
$attr = Sanitizer::validateTagAttributes( $argv, 'div' );
340
$hideroot = isset( $argv[ 'hideroot' ] ) ? CategoryTree::decodeBoolean( $argv[ 'hideroot' ] ) : null;
341
$onlyroot = isset( $argv[ 'onlyroot' ] ) ? CategoryTree::decodeBoolean( $argv[ 'onlyroot' ] ) : null;
342
$depthArg = isset( $argv[ 'depth' ] ) ? (int)$argv[ 'depth' ] : null;
344
$depth = efCategoryTreeCapDepth( $ct->getOption( 'mode' ), $depthArg );
345
if ( $onlyroot ) $depth = 0;
347
return $ct->getTag( $parser, $cat, $hideroot, $attr, $depth, $allowMissing );
351
* Hook callback that injects messages and things into the <head> tag
352
* Does nothing if $parserOutput->mCategoryTreeTag is not set
354
function efCategoryTreeParserOutput( &$outputPage, $parserOutput ) {
355
if ( !empty( $parserOutput->mCategoryTreeTag ) ) {
356
CategoryTree::setHeaders( $outputPage );
362
* ArticleFromTitle hook, override category page handling
364
function efCategoryTreeArticleFromTitle( &$title, &$article ) {
365
if ( $title->getNamespace() == NS_CATEGORY ) {
366
$article = new CategoryTreeCategoryPage( $title );
372
* OutputPageMakeCategoryLinks hook, override category links
374
function efCategoryTreeOutputPageMakeCategoryLinks( &$out, &$categories, &$links ) {
375
global $wgContLang, $wgCategoryTreePageCategoryOptions;
377
$ct = new CategoryTree( $wgCategoryTreePageCategoryOptions );
379
foreach ( $categories as $category => $type ) {
380
$links[$type][] = efCategoryTreeParserHook( $category, $wgCategoryTreePageCategoryOptions, NULL, true );
387
function efCategoryTreeSkinJoinCategoryLinks( &$skin, &$links, &$result ) {
388
$embed = '<div class="CategoryTreePretendInlineMSIE CategoryTreeCategoryBarItem">';
392
# $result = '<div class="CategoryTreeCatBarWrapper" style="border:1px solid blue">' . $embed . implode ( "{$pop} {$sep} {$embed}" , $links ) . $pop . '</div>';
393
$result = $embed . implode ( "{$pop} {$sep} {$embed}" , $links ) . $pop;
b'\\ No newline at end of file'