2021-09-09 22:13:48 +00:00
|
|
|
<?php
|
2022-02-19 00:53:42 +00:00
|
|
|
|
2022-02-06 22:43:56 +00:00
|
|
|
namespace Vector;
|
2022-02-19 00:53:42 +00:00
|
|
|
|
2022-03-17 23:02:39 +00:00
|
|
|
use MediaWiki\MediaWikiServices;
|
|
|
|
|
2021-09-09 22:13:48 +00:00
|
|
|
/**
|
|
|
|
* @ingroup Skins
|
|
|
|
* @package Vector
|
|
|
|
* @internal
|
|
|
|
*/
|
|
|
|
class SkinVector22 extends SkinVector {
|
2022-03-17 23:02:39 +00:00
|
|
|
private const TOC_AB_TEST_NAME = 'skin-vector-toc-experiment';
|
|
|
|
|
2021-09-09 22:13:48 +00:00
|
|
|
/**
|
2022-01-20 22:14:19 +00:00
|
|
|
* Updates the constructor to conditionally disable table of contents in article
|
|
|
|
* body. Note, the constructor can only check feature flags that do not vary on
|
|
|
|
* whether the user is logged in e.g. features with the 'default' key set.
|
2021-09-09 22:13:48 +00:00
|
|
|
* @inheritDoc
|
|
|
|
*/
|
2022-01-20 22:14:19 +00:00
|
|
|
public function __construct( array $options ) {
|
2022-03-17 23:02:39 +00:00
|
|
|
if ( !$this->isTOCABTestEnabled() ) {
|
|
|
|
$options['toc'] = !$this->isTableOfContentsVisibleInSidebar();
|
|
|
|
}
|
|
|
|
|
2021-09-09 22:13:48 +00:00
|
|
|
parent::__construct( $options );
|
|
|
|
}
|
|
|
|
|
2022-03-17 23:02:39 +00:00
|
|
|
/**
|
|
|
|
* @internal
|
|
|
|
* @return bool
|
|
|
|
*/
|
|
|
|
public function isTOCABTestEnabled(): bool {
|
|
|
|
$experimentConfig = $this->getConfig()->get( Constants::CONFIG_WEB_AB_TEST_ENROLLMENT );
|
|
|
|
|
|
|
|
return $experimentConfig['name'] === self::TOC_AB_TEST_NAME &&
|
|
|
|
$experimentConfig['enabled'] &&
|
|
|
|
MediaWikiServices::getInstance()->hasService( Constants::WEB_AB_TEST_ARTICLE_ID_FACTORY_SERVICE );
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Returns whether or not the table of contents is enabled through
|
|
|
|
* FeatureManager.
|
|
|
|
*
|
|
|
|
* @internal
|
|
|
|
* @return bool
|
|
|
|
*/
|
|
|
|
public function isTOCEnabled() {
|
|
|
|
$featureManager = VectorServices::getFeatureManager();
|
|
|
|
|
|
|
|
return $featureManager->isFeatureEnabled( Constants::FEATURE_TABLE_OF_CONTENTS );
|
|
|
|
}
|
|
|
|
|
2022-02-19 00:53:42 +00:00
|
|
|
/**
|
|
|
|
* Determines if the Table of Contents should be visible.
|
|
|
|
* TOC is visible on main namespaces except for the Main Page
|
|
|
|
* when the feature flag is on.
|
|
|
|
*
|
2022-03-17 23:02:39 +00:00
|
|
|
* @internal
|
2022-02-19 00:53:42 +00:00
|
|
|
* @return bool
|
|
|
|
*/
|
2022-03-17 23:02:39 +00:00
|
|
|
public function isTableOfContentsVisibleInSidebar(): bool {
|
2022-02-19 00:53:42 +00:00
|
|
|
$title = $this->getTitle();
|
2022-03-17 23:02:39 +00:00
|
|
|
|
|
|
|
if (
|
|
|
|
!$title ||
|
|
|
|
$title->isMainPage()
|
|
|
|
) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
if ( $this->isTOCABTestEnabled() ) {
|
2022-04-08 16:36:35 +00:00
|
|
|
return $title->getArticleID() !== 0;
|
2022-03-17 23:02:39 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return $this->isTOCEnabled();
|
2022-02-19 00:53:42 +00:00
|
|
|
}
|
|
|
|
|
2022-03-29 20:51:45 +00:00
|
|
|
/**
|
|
|
|
* Annotates table of contents data with Vector-specific information.
|
|
|
|
*
|
|
|
|
* @param array $tocData
|
|
|
|
* @return array
|
|
|
|
*/
|
|
|
|
private function getTocData( array $tocData ): array {
|
|
|
|
// If the table of contents has no items, we won't output it.
|
|
|
|
// empty array is interpreted by Mustache as falsey.
|
|
|
|
if ( empty( $tocData ) || empty( $tocData[ 'array-sections' ] ) ) {
|
|
|
|
return [];
|
|
|
|
}
|
|
|
|
|
|
|
|
// Populate button labels for collapsible TOC sections
|
|
|
|
foreach ( $tocData[ 'array-sections' ] as &$section ) {
|
|
|
|
if ( $section['is-top-level-section'] && $section['is-parent-section'] ) {
|
|
|
|
$section['vector-button-label'] =
|
|
|
|
$this->msg( 'vector-toc-toggle-button-label', $section['line'] )->text();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return array_merge( $tocData, [
|
|
|
|
'is-vector-toc-beginning-enabled' => $this->getConfig()->get(
|
|
|
|
'VectorTableOfContentsBeginning'
|
|
|
|
),
|
|
|
|
'vector-is-collapse-sections-enabled' =>
|
|
|
|
$tocData[ 'number-section-count'] >= $this->getConfig()->get(
|
|
|
|
'VectorTableOfContentsCollapseAtCount'
|
|
|
|
)
|
|
|
|
] );
|
|
|
|
}
|
|
|
|
|
2021-09-09 22:13:48 +00:00
|
|
|
/**
|
2022-01-20 22:14:19 +00:00
|
|
|
* Temporary function while we deprecate SkinVector class.
|
2021-09-09 22:13:48 +00:00
|
|
|
*
|
2022-01-20 22:14:19 +00:00
|
|
|
* @return bool
|
2021-09-09 22:13:48 +00:00
|
|
|
*/
|
2022-01-20 22:14:19 +00:00
|
|
|
protected function isLegacy(): bool {
|
|
|
|
return false;
|
2021-09-09 22:13:48 +00:00
|
|
|
}
|
2022-02-19 00:53:42 +00:00
|
|
|
|
2022-04-27 19:32:19 +00:00
|
|
|
/**
|
|
|
|
* Merges the `view-overflow` menu into the `action` menu.
|
|
|
|
* This ensures that the previous state of the menu e.g. emptyPortlet class
|
|
|
|
* is preserved.
|
|
|
|
* @param array $data
|
|
|
|
* @return array
|
|
|
|
*/
|
|
|
|
private function mergeViewOverflowIntoActions( $data ) {
|
|
|
|
$portlets = $data['data-portlets'];
|
|
|
|
$actions = $portlets['data-actions'];
|
|
|
|
$overflow = $portlets['data-views-overflow'];
|
2022-04-29 18:16:08 +00:00
|
|
|
// if the views overflow menu is not empty, then signal that the more menu despite
|
|
|
|
// being initially empty now has collapsible items.
|
|
|
|
if ( !$overflow['is-empty'] ) {
|
|
|
|
$data['data-portlets']['data-actions']['class'] .= ' vector-has-collapsible-items';
|
|
|
|
}
|
2022-04-27 19:32:19 +00:00
|
|
|
$data['data-portlets']['data-actions']['html-items'] = $overflow['html-items'] . $actions['html-items'];
|
|
|
|
return $data;
|
|
|
|
}
|
|
|
|
|
2022-02-19 00:53:42 +00:00
|
|
|
/**
|
|
|
|
* @return array
|
|
|
|
*/
|
|
|
|
public function getTemplateData(): array {
|
2022-04-01 15:53:03 +00:00
|
|
|
$featureManager = VectorServices::getFeatureManager();
|
|
|
|
$parentData = parent::getTemplateData();
|
2022-03-29 20:51:45 +00:00
|
|
|
|
|
|
|
$parentData['data-toc'] = $this->getTocData( $parentData['data-toc'] ?? [] );
|
|
|
|
|
2022-02-19 00:53:42 +00:00
|
|
|
if ( !$this->isTableOfContentsVisibleInSidebar() ) {
|
2022-04-01 15:53:03 +00:00
|
|
|
unset( $parentData['data-toc'] );
|
2022-02-19 00:53:42 +00:00
|
|
|
}
|
2022-04-27 19:32:19 +00:00
|
|
|
$parentData = $this->mergeViewOverflowIntoActions( $parentData );
|
|
|
|
|
2022-04-01 15:53:03 +00:00
|
|
|
return $parentData + [
|
|
|
|
'data-vector-sticky-header' => $featureManager->isFeatureEnabled(
|
|
|
|
Constants::FEATURE_STICKY_HEADER
|
|
|
|
) ? $this->getStickyHeaderData(
|
|
|
|
$this->getSearchData(
|
|
|
|
$parentData['data-search-box'],
|
|
|
|
// Collapse inside search box is disabled.
|
|
|
|
false,
|
|
|
|
false,
|
|
|
|
'vector-sticky-search-form',
|
|
|
|
false
|
|
|
|
),
|
|
|
|
$featureManager->isFeatureEnabled(
|
|
|
|
Constants::FEATURE_STICKY_HEADER_EDIT
|
|
|
|
)
|
|
|
|
) : false,
|
2022-05-10 15:41:01 +00:00
|
|
|
'is-title-above-tabs' => $featureManager->isFeatureEnabled( Constants::FEATURE_TITLE_ABOVE_TABS )
|
2022-04-01 15:53:03 +00:00
|
|
|
];
|
2022-02-19 00:53:42 +00:00
|
|
|
}
|
2021-09-09 22:13:48 +00:00
|
|
|
}
|