wikimedia/mediawiki-extensions-Wikibase

View on GitHub
client/includes/Hooks/SidebarHookHandler.php

Summary

Maintainability
A
50 mins
Test Coverage
<?php

declare( strict_types = 1 );

namespace Wikibase\Client\Hooks;

use MediaWiki\Hook\SidebarBeforeOutputHook;
use MediaWiki\Hook\SkinTemplateGetLanguageLinkHook;
use MediaWiki\Output\Hook\OutputPageParserOutputHook;
use MediaWiki\Output\OutputPage;
use MediaWiki\Parser\ParserOutput;
use MediaWiki\Title\Title;
use Skin;
use Wikibase\Client\ClientHooks;
use Wikibase\Client\NamespaceChecker;
use Wikibase\Lib\SettingsArray;

/**
 * Handler for ParserOutput-related hooks.
 *
 * @license GPL-2.0-or-later
 */
class SidebarHookHandler implements
    OutputPageParserOutputHook,
    SkinTemplateGetLanguageLinkHook,
    SidebarBeforeOutputHook
{

    /**
     * @var NamespaceChecker
     */
    private $namespaceChecker;

    /**
     * @var LanguageLinkBadgeDisplay
     */
    private $badgeDisplay;

    /**
     * @var SettingsArray
     */
    private $clientSettings;

    public function __construct(
        LanguageLinkBadgeDisplay $badgeDisplay,
        NamespaceChecker $namespaceChecker,
        SettingsArray $clientSettings
    ) {
        $this->namespaceChecker = $namespaceChecker;
        $this->badgeDisplay = $badgeDisplay;
        $this->clientSettings = $clientSettings;
    }

    /**
     * Add output page property if repo links are suppressed, and property for item id
     *
     * @param OutputPage $outputPage
     * @param ParserOutput $parserOutput
     */
    public function onOutputPageParserOutput( $outputPage, $parserOutput ): void {
        $title = $outputPage->getTitle();
        if ( !$title || !$this->namespaceChecker->isWikibaseEnabled( $title->getNamespace() ) ) {
            // shorten out
            return;
        }

        $noExternalLangLinks = NoLangLinkHandler::getNoExternalLangLinks( $parserOutput );

        if ( $noExternalLangLinks ) {
            $outputPage->setProperty( 'noexternallanglinks', $noExternalLangLinks );
        }

        $itemId = $parserOutput->getPageProperty( 'wikibase_item' );

        if ( $itemId !== null ) {
            $outputPage->setProperty( 'wikibase_item', $itemId );
        }

        $otherProjects = $parserOutput->getExtensionData( 'wikibase-otherprojects-sidebar' );

        if ( $otherProjects !== null ) {
            $outputPage->setProperty( 'wikibase-otherprojects-sidebar', $otherProjects );
        }

        $badges = $parserOutput->getExtensionData( 'wikibase_badges' );

        if ( $badges !== null ) {
            $outputPage->setProperty( 'wikibase_badges', $badges );
        }
    }

    /**
     * Add badges to the language links.
     *
     * @param array &$languageLink
     * @param Title $languageLinkTitle
     * @param Title $title
     * @param OutputPage|null $output
     */
    public function onSkinTemplateGetLanguageLink(
        &$languageLink,
        $languageLinkTitle,
        $title,
        $output
    ): void {
        $this->badgeDisplay->applyBadges( $languageLink, $languageLinkTitle, $output );
    }

    /**
     * SidebarBeforeOutput hook handler
     *
     * This handler adds too items to the sidebar section.
     * First it adds the 'Wikidata items' to the 'toolbox' section of the sidebar.
     * Second it adds the 'In other projects' item which lives in its own section.
     *
     * The items generation logic are handled separately for each. This callback
     * is only concerned with adding them to the &$sidebar array (if they exist).
     *
     * If current page cannot have 'Wikidata item' link, this callback will receive
     * null value from ClientHooks::buildWikidataItemLink() method and so it will
     * skip attempting to add the link. Same thing repeats for the second case.
     *
     * @param Skin $skin
     * @param array &$sidebar
     */
    public function onSidebarBeforeOutput( $skin, &$sidebar ): void {
        // Add the 'In other projects' section
        $otherProjectsSidebar = $this->buildOtherProjectsSidebar( $skin );
        $sidebar['wikibase-otherprojects'] = $otherProjectsSidebar === null ? [] : $otherProjectsSidebar;

        // Add 'Wikidata item' to the toolbox
        $wikidataItemLink = ClientHooks::buildWikidataItemLink( $skin );

        if ( $wikidataItemLink !== null || $otherProjectsSidebar !== null ) {
            $outputPage = $skin->getContext()->getOutput();
            $outputPage->addModules( 'wikibase.sidebar.tracking' );
        }

        if ( $wikidataItemLink === null ) {
            return;
        }

        $wikidataInOtherProjects = $this->clientSettings->getSetting( 'moveConnectedItemLinkToOtherProjects' );

        if ( $wikidataInOtherProjects && $skin->getSkinName() !== 'minerva' ) {
            $wikidataItemLink['class'] = 'wb-otherproject-link wb-otherproject-wikibase-dataitem';
            // This automatically appends the wikidata item link to the end of the Other Projects
            $sidebar['wikibase-otherprojects'][] = $wikidataItemLink;
        } else {
            $sidebar['TOOLBOX']['wikibase'] = $wikidataItemLink;
        }
    }

    /**
     * Build 'In other projects' section of the sidebar, if enabled project wide or
     * the user has the beta featured enabled.
     *
     * @param Skin $skin
     *
     * @return null|array[] Array of 'In other projects' contents or null if there are none
     */
    public function buildOtherProjectsSidebar( Skin $skin ): ?array {
        $outputPage = $skin->getContext()->getOutput();

        $otherProjectsSidebar = $outputPage->getProperty( 'wikibase-otherprojects-sidebar' );

        if ( !$otherProjectsSidebar ) {
            return null;
        }

        return $otherProjectsSidebar;
    }

}