Code Coverage |
||||||||||
Classes and Traits |
Functions and Methods |
Lines |
||||||||
Total | |
0.00% |
0 / 1 |
|
70.00% |
7 / 10 |
CRAP | |
97.06% |
99 / 102 |
AboutTopicRenderer | |
0.00% |
0 / 1 |
|
70.00% |
7 / 10 |
25 | |
97.06% |
99 / 102 |
__construct | |
100.00% |
1 / 1 |
1 | |
100.00% |
9 / 9 |
|||
showPlaceholder | |
100.00% |
1 / 1 |
4 | |
100.00% |
17 / 17 |
|||
showTopMessage | |
100.00% |
1 / 1 |
4 | |
100.00% |
22 / 22 |
|||
showCreateArticle | |
0.00% |
0 / 1 |
3.00 | |
92.31% |
12 / 13 |
|||
getLabel | |
0.00% |
0 / 1 |
2.03 | |
80.00% |
4 / 5 |
|||
getDescription | |
0.00% |
0 / 1 |
2.03 | |
80.00% |
4 / 5 |
|||
showTitle | |
100.00% |
1 / 1 |
1 | |
100.00% |
2 / 2 |
|||
showLanguageLinks | |
100.00% |
1 / 1 |
5 | |
100.00% |
20 / 20 |
|||
setOtherProjectsLinks | |
100.00% |
1 / 1 |
1 | |
100.00% |
5 / 5 |
|||
addMetaTags | |
100.00% |
1 / 1 |
2 | |
100.00% |
4 / 4 |
<?php | |
namespace ArticlePlaceholder; | |
use ExtensionRegistry; | |
use Html; | |
use Language; | |
use MalformedTitleException; | |
use MediaWiki\Permissions\PermissionManager; | |
use OOUI; | |
use OutputPage; | |
use SiteLookup; | |
use SpecialPage; | |
use TitleFactory; | |
use User; | |
use Wikibase\Client\Hooks\OtherProjectsSidebarGeneratorFactory; | |
use Wikibase\Client\RepoLinker; | |
use Wikibase\Client\Usage\HashUsageAccumulator; | |
use Wikibase\Client\WikibaseClient; | |
use Wikibase\DataModel\Entity\ItemId; | |
use Wikibase\Lib\Store\LanguageFallbackLabelDescriptionLookupFactory; | |
use Wikibase\Lib\Store\SiteLinkLookup; | |
/** | |
* The AboutTopic SpecialPage for the ArticlePlaceholder extension | |
* The AboutTopicRenderer assumes the 'wikibase_item' OutputPage property | |
* is set in SpecialAboutTopic | |
* | |
* @ingroup Extensions | |
* @author Lucie-Aimée Kaffee | |
* @license GPL-2.0-or-later | |
*/ | |
class AboutTopicRenderer { | |
/** | |
* @var LanguageFallbackLabelDescriptionLookupFactory | |
*/ | |
private $termLookupFactory; | |
/** | |
* @var SiteLinkLookup | |
*/ | |
private $siteLinkLookup; | |
/** | |
* @var SiteLookup | |
*/ | |
private $siteLookup; | |
/** | |
* @var string | |
*/ | |
private $langLinkSiteGroup; | |
/** | |
* @var TitleFactory | |
*/ | |
private $titleFactory; | |
/** | |
* @var OtherProjectsSidebarGeneratorFactory | |
*/ | |
private $otherProjectsSidebarGeneratorFactory; | |
/** | |
* @var PermissionManager | |
*/ | |
private $permissionManager; | |
/** @var RepoLinker */ | |
private $repoLinker; | |
/** | |
* @param LanguageFallbackLabelDescriptionLookupFactory $termLookupFactory | |
* @param SiteLinkLookup $siteLinkLookup | |
* @param SiteLookup $siteLookup | |
* @param string $langLinkSiteGroup | |
* @param TitleFactory $titleFactory | |
* @param OtherProjectsSidebarGeneratorFactory $otherProjectsSidebarGeneratorFactory | |
* @param PermissionManager $permissionManager | |
* @param RepoLinker $repoLinker | |
*/ | |
public function __construct( | |
LanguageFallbackLabelDescriptionLookupFactory $termLookupFactory, | |
SiteLinkLookup $siteLinkLookup, | |
SiteLookup $siteLookup, | |
string $langLinkSiteGroup, | |
TitleFactory $titleFactory, | |
OtherProjectsSidebarGeneratorFactory $otherProjectsSidebarGeneratorFactory, | |
PermissionManager $permissionManager, | |
RepoLinker $repoLinker | |
) { | |
$this->termLookupFactory = $termLookupFactory; | |
$this->siteLinkLookup = $siteLinkLookup; | |
$this->siteLookup = $siteLookup; | |
$this->langLinkSiteGroup = $langLinkSiteGroup; | |
$this->titleFactory = $titleFactory; | |
$this->otherProjectsSidebarGeneratorFactory = $otherProjectsSidebarGeneratorFactory; | |
$this->permissionManager = $permissionManager; | |
$this->repoLinker = $repoLinker; | |
} | |
/** | |
* Show content of the ArticlePlaceholder | |
* | |
* @param ItemId $entityId | |
* @param Language $language | |
* @param User $user | |
* @param OutputPage $output | |
*/ | |
public function showPlaceholder( | |
ItemId $entityId, | |
Language $language, | |
User $user, | |
OutputPage $output | |
) { | |
$label = $this->getLabel( $entityId, $language ); | |
$canEdit = false; | |
if ( $label !== null ) { | |
$this->showTitle( $label, $output ); | |
try { | |
$title = $this->titleFactory->newFromTextThrow( $label ); | |
if ( $this->permissionManager->quickUserCan( 'createpage', $user, $title ) ) { | |
$canEdit = true; | |
} | |
} catch ( MalformedTitleException $ex ) { | |
// When the entity's label contains characters not allowed in page titles | |
$label = ''; | |
$canEdit = true; | |
} | |
} | |
$this->showTopMessage( $entityId, $label, $output, $canEdit ); | |
$output->addModuleStyles( 'ext.articleplaceholder.defaultDisplay' ); | |
$output->addWikiTextAsInterface( '{{aboutTopic|' . $entityId->getSerialization() . '}}' ); | |
$this->showLanguageLinks( $entityId, $output ); | |
$this->setOtherProjectsLinks( $entityId, $output ); | |
$this->addMetaTags( $entityId, $output, $language ); | |
} | |
/** | |
* Adds the top message bar | |
* | |
* @param ItemId $entityId | |
* @param string|null $label | |
* @param OutputPage $output | |
* @param bool $canEdit | |
*/ | |
private function showTopMessage( ItemId $entityId, ?string $label, OutputPage $output, bool $canEdit ) { | |
$infoIcon = new OOUI\IconWidget( [ | |
'icon' => 'infoFilled', | |
'title' => $output->msg( 'articleplaceholder-abouttopic-icon-title' )->text() | |
] ); | |
$output->enableOOUI(); | |
$leftDIV = Html::rawElement( 'div', | |
[ 'class' => 'mw-articleplaceholder-topmessage-container-left' ], | |
$infoIcon | |
); | |
$buttonCode = ''; | |
if ( $label !== null && $canEdit ) { | |
$buttonCode = $this->showCreateArticle( $entityId, $label, $output ); | |
} | |
$this->repoLinker = WikibaseClient::getRepoLinker(); | |
$messageP = Html::rawElement( 'p', [], $output->msg( | |
'articleplaceholder-abouttopic-topmessage-text', | |
$this->repoLinker->getEntityUrl( $entityId ) | |
)->parse() | |
); | |
$centerDIV = Html::rawElement( 'div', | |
[ 'class' => [ 'plainlinks', 'mw-articleplaceholder-topmessage-container-center' ] ], | |
$messageP | |
); | |
$rightDIV = Html::rawElement( 'div', | |
[ 'class' => 'mw-articleplaceholder-topmessage-container-right' ], | |
$buttonCode | |
); | |
$output->addHTML( Html::rawElement( 'div', | |
[ 'class' => 'mw-articleplaceholder-topmessage-container' ], | |
$leftDIV . $rightDIV . $centerDIV ) | |
); | |
} | |
/** | |
* Adds a button to create an article | |
* | |
* @param ItemId $itemId | |
* @param string $label | |
* @param OutputPage $output | |
* | |
* @return string HTML | |
*/ | |
private function showCreateArticle( ItemId $itemId, $label, OutputPage $output ) { | |
$siteLinks = $this->siteLinkLookup->getSiteLinksForItem( $itemId ); | |
$output->enableOOUI(); | |
$output->addModules( 'ext.articleplaceholder.createArticle' ); | |
$output->addJsConfigVars( 'apLabel', $label ); | |
$contents = new OOUI\ButtonWidget( [ | |
'id' => 'new-article-button', | |
'flags' => [ 'primary', 'progressive' ], | |
'infusable' => true, | |
'label' => wfMessage( 'articleplaceholder-abouttopic-create-article-button' )->text(), | |
'href' => SpecialPage::getTitleFor( 'CreateTopicPage', $label ) | |
->getLocalURL( [ 'ref' => 'button' ] ), | |
'target' => 'blank' | |
] ); | |
// TODO: Button should be hidden if the only sitelink links to the current wiki. | |
// $wikibaseClient->getSettings()->getSetting( 'siteGlobalID' ) should be injected here! | |
if ( ExtensionRegistry::getInstance()->isLoaded( 'ContentTranslation' ) && $siteLinks ) { | |
$output->addJsConfigVars( 'apContentTranslation', true ); | |
} | |
return $contents; | |
} | |
/** | |
* @param ItemId $entityId | |
* @param Language $language | |
* | |
* @return string|null null if the item doesn't have a label | |
*/ | |
private function getLabel( ItemId $entityId, Language $language ) { | |
$label = $this->termLookupFactory->newLabelDescriptionLookup( $language ) | |
->getLabel( $entityId ); | |
if ( $label !== null ) { | |
return $label->getText(); | |
} | |
return null; | |
} | |
/** | |
* @param ItemId $entityId | |
* @param Language $language | |
* | |
* @return string|null null if the item doesn't have a description | |
*/ | |
private function getDescription( ItemId $entityId, Language $language ) { | |
$description = $this->termLookupFactory->newLabelDescriptionLookup( $language ) | |
->getDescription( $entityId ); | |
if ( $description !== null ) { | |
return $description->getText(); | |
} | |
return null; | |
} | |
/** | |
* Show label as page title | |
* | |
* @param string $label | |
* @param OutputPage $output | |
*/ | |
private function showTitle( $label, OutputPage $output ) { | |
$output->setPageTitle( htmlspecialchars( $label ) ); | |
} | |
/** | |
* Set language links | |
* | |
* @param ItemId $entityId | |
* @param OutputPage $output | |
*/ | |
private function showLanguageLinks( ItemId $entityId, OutputPage $output ) { | |
$siteLinks = $this->siteLinkLookup->getSiteLinksForItem( $entityId ); | |
$languageLinks = []; | |
$languageNames = []; | |
$pageNames = []; | |
foreach ( $siteLinks as $siteLink ) { | |
$site = $this->siteLookup->getSite( $siteLink->getSiteId() ); | |
if ( $site === null ) { | |
continue; | |
} | |
$languageCode = $site->getLanguageCode(); | |
$group = $site->getGroup(); | |
// TODO: This should not contain the current wiki. | |
// $wikibaseClient->getSettings()->getSetting( 'siteGlobalID' ) should be injected here! | |
if ( $languageCode !== null && $group === $this->langLinkSiteGroup ) { | |
$languageLinks[$languageCode] = $languageCode . ':' . $siteLink->getPageName(); | |
// TODO: We may want to filter with user languages | |
$languageNames[] = [ | |
'data' => $languageCode, | |
'label' => Language::fetchLanguageName( $languageCode ), | |
]; | |
$pageNames[ $languageCode ] = $siteLink->getPageName(); | |
} | |
} | |
$output->setLanguageLinks( $languageLinks ); | |
$output->addJsConfigVars( 'apLanguages', $languageNames ); | |
$output->addJsConfigVars( 'apPageNames', $pageNames ); | |
} | |
/** | |
* @param ItemId $itemId | |
* @param OutputPage $output | |
*/ | |
private function setOtherProjectsLinks( ItemId $itemId, OutputPage $output ) { | |
$otherProjectsSidebarGenerator = $this->otherProjectsSidebarGeneratorFactory | |
->getOtherProjectsSidebarGenerator( new HashUsageAccumulator() ); | |
$otherProjects = $otherProjectsSidebarGenerator->buildProjectLinkSidebarFromItemId( $itemId ); | |
$output->setProperty( 'wikibase-otherprojects-sidebar', $otherProjects ); | |
} | |
/** | |
* @param ItemId $itemId | |
* @param OutputPage $output | |
* @param Language $language | |
*/ | |
private function addMetaTags( ItemId $itemId, OutputPage $output, Language $language ) { | |
$description = $this->getDescription( $itemId, $language ); | |
if ( $description !== null ) { | |
$output->addMeta( 'description', trim( $description ) ); | |
} | |
} | |
} |