mirror of
https://gerrit.wikimedia.org/r/mediawiki/extensions/CategoryTree
synced 2024-11-27 09:43:06 +00:00
Re-apply: Convert to new hook system (Workshop)
This converts the CategtoryTree extension to the new (MW1.35) hook system. The patch was written live during a hackathon workshop. A recording of the workshop is available at <https://www.youtube.com/watch?v=ZOj44Rbh0tM&t>. Re-applying after fixing: premature access to $wgRequest Restores change: Ie52c393af378a980a2dac4ae7076fd6c016a8e0e Reverts revert: Ieee300c7b35b7069bd7e781610c915f2ecae1bf1 NOTE: the "mode" parameter for category pages seems to be broken, as the mode is not proeprly propoagated to dynamic requests. This was already the case before this change, and this change does not try to fix that issue. I was tempted to just remove the feature entirely, but T137812 inidcates that it may be useful to some. I will comment there to see if this should be fiexed or removed. Bug: T282110 Bug: T271011 Change-Id: Ic3ee05e9dc382f4ada5cfeb9ff5d9a69249cc60d
This commit is contained in:
parent
31314b9332
commit
ece310d7be
|
@ -11,9 +11,6 @@
|
|||
"ConfigRegistry": {
|
||||
"categorytree": "GlobalVarConfig::newInstance"
|
||||
},
|
||||
"ExtensionFunctions": [
|
||||
"MediaWiki\\Extension\\CategoryTree\\Hooks::initialize"
|
||||
],
|
||||
"SpecialPages": {
|
||||
"CategoryTree": {
|
||||
"class": "MediaWiki\\Extension\\CategoryTree\\CategoryTreePage",
|
||||
|
@ -84,16 +81,23 @@
|
|||
"localBasePath": "modules",
|
||||
"remoteExtPath": "CategoryTree/modules"
|
||||
},
|
||||
"HookHandlers": {
|
||||
"default": {
|
||||
"class": "MediaWiki\\Extension\\CategoryTree\\Hooks",
|
||||
"services": [ "DBLoadBalancer", "MainConfig" ]
|
||||
}
|
||||
},
|
||||
"Hooks": {
|
||||
"ArticleFromTitle": "MediaWiki\\Extension\\CategoryTree\\Hooks::articleFromTitle",
|
||||
"SpecialTrackingCategories::preprocess": "MediaWiki\\Extension\\CategoryTree\\Hooks::onSpecialTrackingCategoriesPreprocess",
|
||||
"SpecialTrackingCategories::generateCatLink": "MediaWiki\\Extension\\CategoryTree\\Hooks::onSpecialTrackingCategoriesGenerateCatLink",
|
||||
"SkinBuildSidebar": "MediaWiki\\Extension\\CategoryTree\\Hooks::onSkinBuildSidebar",
|
||||
"ParserFirstCallInit": "MediaWiki\\Extension\\CategoryTree\\Hooks::setHooks",
|
||||
"OutputPageMakeCategoryLinks": "MediaWiki\\Extension\\CategoryTree\\Hooks::outputPageMakeCategoryLinks",
|
||||
"BeforePageDisplay": "MediaWiki\\Extension\\CategoryTree\\Hooks::addHeaders",
|
||||
"BeforePageDisplayMobile": "MediaWiki\\Extension\\CategoryTree\\Hooks::addHeaders",
|
||||
"OutputPageParserOutput": "MediaWiki\\Extension\\CategoryTree\\Hooks::parserOutput"
|
||||
"MediaWikiServices": "default",
|
||||
"ArticleFromTitle": "default",
|
||||
"SpecialTrackingCategories::preprocess": "default",
|
||||
"SpecialTrackingCategories::generateCatLink": "default",
|
||||
"SkinBuildSidebar": "default",
|
||||
"ParserFirstCallInit": "default",
|
||||
"OutputPageMakeCategoryLinks": "default",
|
||||
"BeforePageDisplay": "default",
|
||||
"OutputPageParserOutput": "default",
|
||||
"BeforePageDisplayMobile": "MediaWiki\\Extension\\CategoryTree\\Hooks::addHeaders"
|
||||
},
|
||||
"config": {
|
||||
"CategoryTreeMaxChildren": {
|
||||
|
|
|
@ -40,7 +40,14 @@ class CategoryTreeCategoryViewer extends CategoryViewer {
|
|||
CategoryTree::setHeaders( $this->getOutput() );
|
||||
}
|
||||
|
||||
$this->categorytree = new CategoryTree( $this->getConfig()->get( 'CategoryTreeCategoryPageOptions' ) );
|
||||
$options = $this->getConfig()->get( 'CategoryTreeCategoryPageOptions' );
|
||||
|
||||
$mode = $this->getRequest()->getVal( 'mode' );
|
||||
if ( $mode !== null ) {
|
||||
$options['mode'] = CategoryTree::decodeMode( $mode );
|
||||
}
|
||||
|
||||
$this->categorytree = new CategoryTree( $options );
|
||||
}
|
||||
|
||||
return $this->categorytree;
|
||||
|
|
|
@ -26,7 +26,19 @@ namespace MediaWiki\Extension\CategoryTree;
|
|||
|
||||
use Article;
|
||||
use Category;
|
||||
use Config;
|
||||
use Html;
|
||||
use IContextSource;
|
||||
use MediaWiki\Hook\BeforePageDisplayHook;
|
||||
use MediaWiki\Hook\MediaWikiServicesHook;
|
||||
use MediaWiki\Hook\OutputPageMakeCategoryLinksHook;
|
||||
use MediaWiki\Hook\OutputPageParserOutputHook;
|
||||
use MediaWiki\Hook\ParserFirstCallInitHook;
|
||||
use MediaWiki\Hook\SkinBuildSidebarHook;
|
||||
use MediaWiki\Hook\SpecialTrackingCategories__generateCatLinkHook;
|
||||
use MediaWiki\Hook\SpecialTrackingCategories__preprocessHook;
|
||||
use MediaWiki\MediaWikiServices;
|
||||
use MediaWiki\Page\Hook\ArticleFromTitleHook;
|
||||
use OutputPage;
|
||||
use Parser;
|
||||
use ParserOutput;
|
||||
|
@ -35,15 +47,45 @@ use Sanitizer;
|
|||
use Skin;
|
||||
use SpecialPage;
|
||||
use Title;
|
||||
use Wikimedia\Rdbms\ILoadBalancer;
|
||||
|
||||
/**
|
||||
* Hooks for the CategoryTree extension, an AJAX based gadget
|
||||
* to display the category structure of a wiki
|
||||
*
|
||||
* @phpcs:disable MediaWiki.NamingConventions.LowerCamelFunctionsName.FunctionName
|
||||
*/
|
||||
class Hooks {
|
||||
class Hooks implements
|
||||
ArticleFromTitleHook,
|
||||
SpecialTrackingCategories__preprocessHook,
|
||||
SpecialTrackingCategories__generateCatLinkHook,
|
||||
BeforePageDisplayHook,
|
||||
OutputPageParserOutputHook,
|
||||
MediaWikiServicesHook,
|
||||
SkinBuildSidebarHook,
|
||||
ParserFirstCallInitHook,
|
||||
OutputPageMakeCategoryLinksHook
|
||||
{
|
||||
|
||||
private const EXTENSION_DATA_FLAG = 'CategoryTree';
|
||||
|
||||
/** @var ILoadBalancer */
|
||||
private $loadBalancer;
|
||||
|
||||
/**
|
||||
* @var Config
|
||||
*/
|
||||
private $config;
|
||||
|
||||
/**
|
||||
* @param ILoadBalancer $loadBalancer
|
||||
* @param Config $config
|
||||
*/
|
||||
public function __construct( ILoadBalancer $loadBalancer, Config $config ) {
|
||||
$this->loadBalancer = $loadBalancer;
|
||||
$this->config = $config;
|
||||
}
|
||||
|
||||
/**
|
||||
* @internal For use by CategoryTreeCategoryViewer and CategoryTreePage only!
|
||||
* @return bool
|
||||
|
@ -56,44 +98,35 @@ class Hooks {
|
|||
/**
|
||||
* Adjusts config once MediaWiki is fully initialised
|
||||
* TODO: Don't do this, lazy initialize the config
|
||||
* @param MediaWikiServices $services
|
||||
*/
|
||||
public static function initialize() {
|
||||
global $wgRequest;
|
||||
public function onMediaWikiServices( $services ) {
|
||||
global $wgCategoryTreeDefaultOptions, $wgCategoryTreeDefaultMode;
|
||||
global $wgCategoryTreeCategoryPageOptions, $wgCategoryTreeCategoryPageMode;
|
||||
global $wgCategoryTreeOmitNamespace;
|
||||
|
||||
if ( !isset( $wgCategoryTreeDefaultOptions['mode'] )
|
||||
|| $wgCategoryTreeDefaultOptions['mode'] === null
|
||||
) {
|
||||
if ( !isset( $wgCategoryTreeDefaultOptions['mode'] ) ) {
|
||||
$wgCategoryTreeDefaultOptions['mode'] = $wgCategoryTreeDefaultMode;
|
||||
}
|
||||
|
||||
if ( !isset( $wgCategoryTreeDefaultOptions['hideprefix'] )
|
||||
|| $wgCategoryTreeDefaultOptions['hideprefix'] === null
|
||||
) {
|
||||
if ( !isset( $wgCategoryTreeDefaultOptions['hideprefix'] ) ) {
|
||||
$wgCategoryTreeDefaultOptions['hideprefix'] = $wgCategoryTreeOmitNamespace;
|
||||
}
|
||||
|
||||
if ( !isset( $wgCategoryTreeCategoryPageOptions['mode'] )
|
||||
|| $wgCategoryTreeCategoryPageOptions['mode'] === null
|
||||
) {
|
||||
$mode = $wgRequest->getVal( 'mode' );
|
||||
$wgCategoryTreeCategoryPageOptions['mode'] = ( $mode )
|
||||
? CategoryTree::decodeMode( $mode ) : $wgCategoryTreeCategoryPageMode;
|
||||
if ( !isset( $wgCategoryTreeCategoryPageOptions['mode'] ) ) {
|
||||
$wgCategoryTreeCategoryPageOptions['mode'] = $wgCategoryTreeCategoryPageMode;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Parser $parser
|
||||
*/
|
||||
public static function setHooks( Parser $parser ) {
|
||||
global $wgCategoryTreeAllowTag;
|
||||
if ( !$wgCategoryTreeAllowTag ) {
|
||||
public function onParserFirstCallInit( $parser ) {
|
||||
if ( !$this->config->get( 'CategoryTreeAllowTag' ) ) {
|
||||
return;
|
||||
}
|
||||
$parser->setHook( 'categorytree', [ self::class, 'parserHook' ] );
|
||||
$parser->setFunctionHook( 'categorytree', [ self::class, 'parserFunction' ] );
|
||||
$parser->setHook( 'categorytree', [ $this, 'parserHook' ] );
|
||||
$parser->setFunctionHook( 'categorytree', [ $this, 'parserFunction' ] );
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -103,7 +136,7 @@ class Hooks {
|
|||
* @param string ...$params
|
||||
* @return array|string
|
||||
*/
|
||||
public static function parserFunction( Parser $parser, ...$params ) {
|
||||
public function parserFunction( Parser $parser, ...$params ) {
|
||||
// first user-supplied parameter must be category name
|
||||
if ( !$params ) {
|
||||
// no category specified, return nothing
|
||||
|
@ -131,7 +164,7 @@ class Hooks {
|
|||
$cat . Html::closeElement( 'categorytree' );
|
||||
} else {
|
||||
// now handle just like a <categorytree> tag
|
||||
$html = self::parserHook( $cat, $argv, $parser );
|
||||
$html = $this->parserHook( $cat, $argv, $parser );
|
||||
return [ $html, 'noparse' => true, 'isHTML' => true ];
|
||||
}
|
||||
}
|
||||
|
@ -142,7 +175,7 @@ class Hooks {
|
|||
* @param Skin $skin
|
||||
* @param array &$sidebar
|
||||
*/
|
||||
public static function onSkinBuildSidebar( Skin $skin, array &$sidebar ) {
|
||||
public function onSkinBuildSidebar( $skin, &$sidebar ) {
|
||||
global $wgCategoryTreeSidebarRoot, $wgCategoryTreeSidebarOptions;
|
||||
|
||||
if ( !$wgCategoryTreeSidebarRoot ) {
|
||||
|
@ -166,7 +199,7 @@ class Hooks {
|
|||
* @param bool $allowMissing
|
||||
* @return bool|string
|
||||
*/
|
||||
public static function parserHook(
|
||||
public function parserHook(
|
||||
$cat,
|
||||
array $argv,
|
||||
Parser $parser = null,
|
||||
|
@ -203,7 +236,7 @@ class Hooks {
|
|||
* @param OutputPage $outputPage
|
||||
* @param ParserOutput $parserOutput
|
||||
*/
|
||||
public static function parserOutput( OutputPage $outputPage, ParserOutput $parserOutput ) {
|
||||
public function onOutputPageParserOutput( $outputPage, $parserOutput ) : void {
|
||||
if ( self::shouldForceHeaders() ) {
|
||||
// Skip, we've already set the headers unconditionally
|
||||
return;
|
||||
|
@ -213,6 +246,17 @@ class Hooks {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* This hook is called prior to outputting a page.
|
||||
*
|
||||
* @param OutputPage $out
|
||||
* @param Skin $skin
|
||||
* @return void This hook must not abort, it must return no value
|
||||
*/
|
||||
public function onBeforePageDisplay( $out, $skin ) : void {
|
||||
self::addHeaders( $out );
|
||||
}
|
||||
|
||||
/**
|
||||
* BeforePageDisplay and BeforePageDisplayMobile hooks.
|
||||
* These hooks are used when $wgCategoryTreeForceHeaders is set.
|
||||
|
@ -231,8 +275,10 @@ class Hooks {
|
|||
*
|
||||
* @param Title $title
|
||||
* @param Article|null &$article Article (object) that will be returned
|
||||
* @param IContextSource $context
|
||||
* @return bool|void True or no return value to continue or false to abort
|
||||
*/
|
||||
public static function articleFromTitle( Title $title, Article &$article = null ) {
|
||||
public function onArticleFromTitle( $title, &$article, $context ) {
|
||||
if ( $title->getNamespace() == NS_CATEGORY ) {
|
||||
$article = new CategoryTreeCategoryPage( $title );
|
||||
}
|
||||
|
@ -245,11 +291,7 @@ class Hooks {
|
|||
* @param array &$links
|
||||
* @return bool
|
||||
*/
|
||||
public static function outputPageMakeCategoryLinks(
|
||||
OutputPage $out,
|
||||
array $categories,
|
||||
array &$links
|
||||
) {
|
||||
public function onOutputPageMakeCategoryLinks( $out, $categories, &$links ) {
|
||||
global $wgCategoryTreePageCategoryOptions, $wgCategoryTreeHijackPageCategories;
|
||||
|
||||
if ( !$wgCategoryTreeHijackPageCategories ) {
|
||||
|
@ -258,7 +300,7 @@ class Hooks {
|
|||
}
|
||||
|
||||
foreach ( $categories as $category => $type ) {
|
||||
$links[$type][] = self::parserHook( $category, $wgCategoryTreePageCategoryOptions, null, null, true );
|
||||
$links[$type][] = $this->parserHook( $category, $wgCategoryTreePageCategoryOptions, null, null, true );
|
||||
}
|
||||
CategoryTree::setHeaders( $out );
|
||||
|
||||
|
@ -289,8 +331,9 @@ class Hooks {
|
|||
* @param array $trackingCategories [ 'msg' => Title, 'cats' => Title[] ]
|
||||
* @phan-param array<string,array{msg:Title,cats:Title[]}> $trackingCategories
|
||||
*/
|
||||
public static function onSpecialTrackingCategoriesPreprocess(
|
||||
SpecialPage $specialPage, array $trackingCategories
|
||||
public function onSpecialTrackingCategories__preprocess(
|
||||
$specialPage,
|
||||
$trackingCategories
|
||||
) {
|
||||
$categoryDbKeys = [];
|
||||
foreach ( $trackingCategories as $catMsg => $data ) {
|
||||
|
@ -300,7 +343,7 @@ class Hooks {
|
|||
}
|
||||
$categories = [];
|
||||
if ( $categoryDbKeys ) {
|
||||
$dbr = wfGetDB( DB_REPLICA );
|
||||
$dbr = $this->loadBalancer->getConnectionRef( DB_REPLICA );
|
||||
$res = $dbr->select(
|
||||
'category',
|
||||
[ 'cat_id', 'cat_title', 'cat_pages', 'cat_subcats', 'cat_files' ],
|
||||
|
@ -321,16 +364,16 @@ class Hooks {
|
|||
* @param Title $catTitle Title object of the linked category
|
||||
* @param string &$html Result html
|
||||
*/
|
||||
public static function onSpecialTrackingCategoriesGenerateCatLink(
|
||||
SpecialPage $specialPage, Title $catTitle, &$html
|
||||
public function onSpecialTrackingCategories__generateCatLink( $specialPage,
|
||||
$catTitle, &$html
|
||||
) {
|
||||
if ( !isset( $specialPage->categoryTreeCategories ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
$cat = null;
|
||||
if ( isset( $specialPage->categoryTreeCategories[$catTitle->getDbKey()] ) ) {
|
||||
$cat = $specialPage->categoryTreeCategories[$catTitle->getDbKey()];
|
||||
if ( isset( $specialPage->categoryTreeCategories[$catTitle->getDBkey()] ) ) {
|
||||
$cat = $specialPage->categoryTreeCategories[$catTitle->getDBkey()];
|
||||
}
|
||||
|
||||
$html .= CategoryTree::createCountString( $specialPage->getContext(), $cat, 0 );
|
||||
|
|
Loading…
Reference in a new issue