mirror of
https://gerrit.wikimedia.org/r/mediawiki/skins/Vector.git
synced 2024-09-25 11:17:35 +00:00
Merge "Components: Model table of contents in title bar."
This commit is contained in:
commit
cff2a4961a
|
@ -1,15 +1,39 @@
|
||||||
<?php
|
<?php
|
||||||
namespace MediaWiki\Skins\Vector\Components;
|
namespace MediaWiki\Skins\Vector\Components;
|
||||||
|
|
||||||
|
use MessageLocalizer;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* VectorComponentStickyHeader component
|
* VectorComponentStickyHeader component
|
||||||
*/
|
*/
|
||||||
class VectorComponentStickyHeader implements VectorComponent {
|
class VectorComponentStickyHeader implements VectorComponent {
|
||||||
|
/** @var MessageLocalizer */
|
||||||
|
private $localizer;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param MessageLocalizer $localizer
|
||||||
|
*/
|
||||||
|
public function __construct( MessageLocalizer $localizer ) {
|
||||||
|
$this->localizer = $localizer;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @inheritDoc
|
* @inheritDoc
|
||||||
*/
|
*/
|
||||||
public function getTemplateData(): array {
|
public function getTemplateData(): array {
|
||||||
return [];
|
$pinnableContainer = new VectorComponentTableOfContentsContainer(
|
||||||
|
$this->localizer,
|
||||||
|
'vector-sticky-header-toc'
|
||||||
|
);
|
||||||
|
$tocDropdown = new VectorComponentDropdown(
|
||||||
|
'vector-toc',
|
||||||
|
'',
|
||||||
|
'mw-portlet mw-portlet-sticky-header-toc vector-sticky-header-toc',
|
||||||
|
'listBullet'
|
||||||
|
);
|
||||||
|
return [
|
||||||
|
'data-sticky-header-toc-pinnable-container' => $pinnableContainer->getTemplateData(),
|
||||||
|
'data-sticky-header-toc-dropdown' => $tocDropdown->getTemplateData(),
|
||||||
|
];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -24,7 +24,7 @@ class VectorComponentTableOfContents implements VectorComponent {
|
||||||
/** @var VectorComponentPinnableHeader */
|
/** @var VectorComponentPinnableHeader */
|
||||||
private $pinnableHeader;
|
private $pinnableHeader;
|
||||||
|
|
||||||
/** @var string */
|
/** @var string */
|
||||||
public const ID = 'vector-toc';
|
public const ID = 'vector-toc';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -42,14 +42,6 @@ class VectorComponentTableOfContents implements VectorComponent {
|
||||||
// ToC is pinned by default, hardcoded for now
|
// ToC is pinned by default, hardcoded for now
|
||||||
$this->isPinned = true;
|
$this->isPinned = true;
|
||||||
$this->config = $config;
|
$this->config = $config;
|
||||||
$this->pinnableHeader = new VectorComponentPinnableHeader(
|
|
||||||
$this->localizer,
|
|
||||||
$this->isPinned,
|
|
||||||
'vector-toc',
|
|
||||||
null,
|
|
||||||
false,
|
|
||||||
'h2'
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -72,11 +64,9 @@ class VectorComponentTableOfContents implements VectorComponent {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
$pinnableContainer = new VectorComponentPinnableContainer( self::ID );
|
|
||||||
$pinnableElement = new VectorComponentPinnableElement( self::ID );
|
$pinnableElement = new VectorComponentPinnableElement( self::ID );
|
||||||
|
|
||||||
return $pinnableElement->getTemplateData() +
|
return $pinnableElement->getTemplateData() +
|
||||||
$pinnableContainer->getTemplateData() +
|
|
||||||
array_merge( $this->tocData, [
|
array_merge( $this->tocData, [
|
||||||
'is-vector-toc-beginning-enabled' => $this->config->get(
|
'is-vector-toc-beginning-enabled' => $this->config->get(
|
||||||
'VectorTableOfContentsBeginning'
|
'VectorTableOfContentsBeginning'
|
||||||
|
@ -85,7 +75,6 @@ class VectorComponentTableOfContents implements VectorComponent {
|
||||||
$this->tocData[ 'number-section-count'] >= $this->config->get(
|
$this->tocData[ 'number-section-count'] >= $this->config->get(
|
||||||
'VectorTableOfContentsCollapseAtCount'
|
'VectorTableOfContentsCollapseAtCount'
|
||||||
),
|
),
|
||||||
'data-pinnable-header' => $this->pinnableHeader->getTemplateData(),
|
|
||||||
] );
|
] );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,44 @@
|
||||||
|
<?php
|
||||||
|
namespace MediaWiki\Skins\Vector\Components;
|
||||||
|
|
||||||
|
use MessageLocalizer;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* VectorComponentTableOfContentsContainer component
|
||||||
|
*/
|
||||||
|
class VectorComponentTableOfContentsContainer implements VectorComponent {
|
||||||
|
/** @var string */
|
||||||
|
private $id;
|
||||||
|
/** @var MessageLocalizer */
|
||||||
|
private $localizer;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param MessageLocalizer $localizer
|
||||||
|
* @param string $id (optional) of the pinnable element associated
|
||||||
|
* with the pinnable header and container.
|
||||||
|
*/
|
||||||
|
public function __construct( MessageLocalizer $localizer, $id = 'vector-toc' ) {
|
||||||
|
$this->localizer = $localizer;
|
||||||
|
$this->id = $id;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* In tableOfContents.js we have tableOfContents::getTableOfContentsSectionsData(),
|
||||||
|
* that yields the same result as this function, please make sure to keep them in sync.
|
||||||
|
* @inheritDoc
|
||||||
|
*/
|
||||||
|
public function getTemplateData(): array {
|
||||||
|
$pinnableHeader = new VectorComponentPinnableHeader(
|
||||||
|
$this->localizer,
|
||||||
|
true,
|
||||||
|
$this->id,
|
||||||
|
null,
|
||||||
|
false,
|
||||||
|
'h2'
|
||||||
|
);
|
||||||
|
$pinnableContainer = new VectorComponentPinnableContainer( $this->id );
|
||||||
|
return $pinnableContainer->getTemplateData() + [
|
||||||
|
'data-pinnable-header' => $pinnableHeader->getTemplateData(),
|
||||||
|
];
|
||||||
|
}
|
||||||
|
}
|
|
@ -226,24 +226,11 @@ abstract class SkinVector extends SkinMustache {
|
||||||
}
|
}
|
||||||
$btns[] = $this->getAddSectionButtonData();
|
$btns[] = $this->getAddSectionButtonData();
|
||||||
|
|
||||||
// FIXME: Sync with VectorComponentTableOfContents:getTemplateData
|
|
||||||
$tocPortletData = Hooks::updateDropdownMenuData( [
|
|
||||||
'id' => 'vector-sticky-header-toc',
|
|
||||||
'class' => 'mw-portlet mw-portlet-sticky-header-toc vector-sticky-header-toc',
|
|
||||||
'html-vector-menu-checkbox-attributes' => 'tabindex="-1"',
|
|
||||||
'html-vector-menu-heading-attributes' => 'tabindex="-1"',
|
|
||||||
'is-pinned' => true,
|
|
||||||
'button' => true,
|
|
||||||
'text-hidden' => true,
|
|
||||||
'icon' => 'listBullet'
|
|
||||||
] );
|
|
||||||
|
|
||||||
// Show sticky ULS if the ULS extension is enabled and the ULS in header is not hidden
|
// Show sticky ULS if the ULS extension is enabled and the ULS in header is not hidden
|
||||||
$showStickyULS = $this->isULSExtensionEnabled() && !$this->shouldHideLanguages();
|
$showStickyULS = $this->isULSExtensionEnabled() && !$this->shouldHideLanguages();
|
||||||
$langButton = new VectorComponentLanguageButton( $this->getULSLabels()[ 'label' ] );
|
$langButton = new VectorComponentLanguageButton( $this->getULSLabels()[ 'label' ] );
|
||||||
|
|
||||||
return [
|
return [
|
||||||
'data-sticky-header-toc' => $tocPortletData,
|
|
||||||
'data-primary-action' => $showStickyULS ?
|
'data-primary-action' => $showStickyULS ?
|
||||||
$langButton->getTemplateData() : null,
|
$langButton->getTemplateData() : null,
|
||||||
'data-button-start' => [
|
'data-button-start' => [
|
||||||
|
|
|
@ -11,9 +11,11 @@ use MediaWiki\Skins\Vector\Components\VectorComponentMenu;
|
||||||
use MediaWiki\Skins\Vector\Components\VectorComponentMenuListItem;
|
use MediaWiki\Skins\Vector\Components\VectorComponentMenuListItem;
|
||||||
use MediaWiki\Skins\Vector\Components\VectorComponentMenuVariants;
|
use MediaWiki\Skins\Vector\Components\VectorComponentMenuVariants;
|
||||||
use MediaWiki\Skins\Vector\Components\VectorComponentPageTools;
|
use MediaWiki\Skins\Vector\Components\VectorComponentPageTools;
|
||||||
|
use MediaWiki\Skins\Vector\Components\VectorComponentPinnableContainer;
|
||||||
use MediaWiki\Skins\Vector\Components\VectorComponentSearchBox;
|
use MediaWiki\Skins\Vector\Components\VectorComponentSearchBox;
|
||||||
use MediaWiki\Skins\Vector\Components\VectorComponentStickyHeader;
|
use MediaWiki\Skins\Vector\Components\VectorComponentStickyHeader;
|
||||||
use MediaWiki\Skins\Vector\Components\VectorComponentTableOfContents;
|
use MediaWiki\Skins\Vector\Components\VectorComponentTableOfContents;
|
||||||
|
use MediaWiki\Skins\Vector\Components\VectorComponentTableOfContentsContainer;
|
||||||
use MediaWiki\Skins\Vector\Components\VectorComponentUserLinks;
|
use MediaWiki\Skins\Vector\Components\VectorComponentUserLinks;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -50,20 +52,6 @@ class SkinVector22 extends SkinVector {
|
||||||
$shouldShowOnMainPage;
|
$shouldShowOnMainPage;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* @return array
|
|
||||||
*/
|
|
||||||
private function getTocPageTitleData(): array {
|
|
||||||
return Hooks::updateDropdownMenuData( [
|
|
||||||
'id' => 'vector-page-titlebar-toc',
|
|
||||||
'class' => 'vector-page-titlebar-toc mw-ui-icon-flush-left',
|
|
||||||
'is-pinned' => true,
|
|
||||||
'button' => true,
|
|
||||||
'text-hidden' => true,
|
|
||||||
'icon' => 'listBullet'
|
|
||||||
] );
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Merges the `view-overflow` menu into the `action` menu.
|
* Merges the `view-overflow` menu into the `action` menu.
|
||||||
* This ensures that the previous state of the menu e.g. emptyPortlet class
|
* This ensures that the previous state of the menu e.g. emptyPortlet class
|
||||||
|
@ -167,7 +155,8 @@ class SkinVector22 extends SkinVector {
|
||||||
public function getTemplateData(): array {
|
public function getTemplateData(): array {
|
||||||
$featureManager = VectorServices::getFeatureManager();
|
$featureManager = VectorServices::getFeatureManager();
|
||||||
$parentData = parent::getTemplateData();
|
$parentData = parent::getTemplateData();
|
||||||
$stickyHeader = new VectorComponentStickyHeader();
|
$localizer = $this->getContext();
|
||||||
|
$stickyHeader = new VectorComponentStickyHeader( $localizer );
|
||||||
$parentData = $this->mergeViewOverflowIntoActions( $parentData );
|
$parentData = $this->mergeViewOverflowIntoActions( $parentData );
|
||||||
$portlets = $parentData['data-portlets'];
|
$portlets = $parentData['data-portlets'];
|
||||||
|
|
||||||
|
@ -253,9 +242,12 @@ class SkinVector22 extends SkinVector {
|
||||||
$langData['html-after-portal'] ?? '',
|
$langData['html-after-portal'] ?? '',
|
||||||
$this->getTitle()
|
$this->getTitle()
|
||||||
) : null,
|
) : null,
|
||||||
|
'data-toc-container' => new VectorComponentTableOfContentsContainer(
|
||||||
|
$localizer,
|
||||||
|
),
|
||||||
'data-toc' => new VectorComponentTableOfContents(
|
'data-toc' => new VectorComponentTableOfContents(
|
||||||
$parentData['data-toc'],
|
$parentData['data-toc'],
|
||||||
$this->getContext(),
|
$localizer,
|
||||||
$this->getConfig()
|
$this->getConfig()
|
||||||
),
|
),
|
||||||
'data-search-box' => new VectorComponentSearchBox(
|
'data-search-box' => new VectorComponentSearchBox(
|
||||||
|
@ -295,6 +287,19 @@ class SkinVector22 extends SkinVector {
|
||||||
$this->msg( 'toolbox' )->text(),
|
$this->msg( 'toolbox' )->text(),
|
||||||
VectorComponentPageTools::ID . '-dropdown',
|
VectorComponentPageTools::ID . '-dropdown',
|
||||||
) : null,
|
) : null,
|
||||||
|
'data-page-titlebar-toc-dropdown' => new VectorComponentDropdown(
|
||||||
|
'vector-page-titlebar-toc',
|
||||||
|
// no label,
|
||||||
|
'',
|
||||||
|
// class
|
||||||
|
'vector-page-titlebar-toc mw-ui-icon-flush-left',
|
||||||
|
// icon
|
||||||
|
'listBullet',
|
||||||
|
),
|
||||||
|
'data-page-titlebar-pinnable-container' => new VectorComponentPinnableContainer(
|
||||||
|
'vector-page-titlebar-toc',
|
||||||
|
true
|
||||||
|
),
|
||||||
];
|
];
|
||||||
foreach ( $components as $key => $component ) {
|
foreach ( $components as $key => $component ) {
|
||||||
// Array of components or null values.
|
// Array of components or null values.
|
||||||
|
@ -322,7 +327,6 @@ class SkinVector22 extends SkinVector {
|
||||||
'is-main-menu-visible' => $this->isMainMenuVisible(),
|
'is-main-menu-visible' => $this->isMainMenuVisible(),
|
||||||
// Cast empty string to null
|
// Cast empty string to null
|
||||||
'html-subtitle' => $parentData['html-subtitle'] === '' ? null : $parentData['html-subtitle'],
|
'html-subtitle' => $parentData['html-subtitle'] === '' ? null : $parentData['html-subtitle'],
|
||||||
'data-page-titlebar-toc' => $this->getTocPageTitleData(),
|
|
||||||
'data-vector-sticky-header' => $featureManager->isFeatureEnabled(
|
'data-vector-sticky-header' => $featureManager->isFeatureEnabled(
|
||||||
Constants::FEATURE_STICKY_HEADER
|
Constants::FEATURE_STICKY_HEADER
|
||||||
) ? $stickyHeader->getTemplateData() + $this->getStickyHeaderData(
|
) ? $stickyHeader->getTemplateData() + $this->getStickyHeaderData(
|
||||||
|
|
|
@ -3,7 +3,6 @@
|
||||||
When language button is visible, indicators are placed in the BeforeContent.mustache template instead.
|
When language button is visible, indicators are placed in the BeforeContent.mustache template instead.
|
||||||
}}
|
}}
|
||||||
<header class="mw-body-header vector-page-titlebar{{#is-title-blank}} vector-page-titlebar-blank{{/is-title-blank}}">
|
<header class="mw-body-header vector-page-titlebar{{#is-title-blank}} vector-page-titlebar-blank{{/is-title-blank}}">
|
||||||
{{#data-toc}}
|
|
||||||
{{! Checkbox hack used by collapsed TOC on narrow viewports for no JS users }}
|
{{! Checkbox hack used by collapsed TOC on narrow viewports for no JS users }}
|
||||||
<label
|
<label
|
||||||
id="vector-toc-collapsed-button"
|
id="vector-toc-collapsed-button"
|
||||||
|
@ -18,13 +17,14 @@
|
||||||
</label>
|
</label>
|
||||||
|
|
||||||
{{! TOC is moved into this dropdown from the sidebar in stickyHeader.js. }}
|
{{! TOC is moved into this dropdown from the sidebar in stickyHeader.js. }}
|
||||||
{{#data-page-titlebar-toc}}
|
{{#data-page-titlebar-toc-dropdown}}
|
||||||
{{>Dropdown/Open}}
|
{{>Dropdown/Open}}
|
||||||
|
{{#data-page-titlebar-pinnable-container}}
|
||||||
{{>PinnableContainer/Unpinned/Open}}
|
{{>PinnableContainer/Unpinned/Open}}
|
||||||
{{>PinnableContainer/Close}}
|
{{>PinnableContainer/Close}}
|
||||||
|
{{/data-page-titlebar-pinnable-container}}
|
||||||
{{>Dropdown/Close}}
|
{{>Dropdown/Close}}
|
||||||
{{/data-page-titlebar-toc}}
|
{{/data-page-titlebar-toc-dropdown}}
|
||||||
{{/data-toc}}
|
|
||||||
|
|
||||||
{{{html-title-heading}}}
|
{{{html-title-heading}}}
|
||||||
|
|
||||||
|
|
|
@ -21,12 +21,14 @@
|
||||||
<div class="vector-sticky-header-context-bar">
|
<div class="vector-sticky-header-context-bar">
|
||||||
<div class="vector-sticky-header-toc-container mw-ui-icon-flush-left">
|
<div class="vector-sticky-header-toc-container mw-ui-icon-flush-left">
|
||||||
{{! TOC is moved into this dropdown from the sidebar in stickyHeader.js. }}
|
{{! TOC is moved into this dropdown from the sidebar in stickyHeader.js. }}
|
||||||
{{#data-sticky-header-toc}}
|
{{#data-sticky-header-toc-dropdown}}
|
||||||
{{>Dropdown/Open}}
|
{{>Dropdown/Open}}
|
||||||
|
{{#data-sticky-header-toc-pinnable-container}}
|
||||||
{{>PinnableContainer/Unpinned/Open}}
|
{{>PinnableContainer/Unpinned/Open}}
|
||||||
{{>PinnableContainer/Close}}
|
{{>PinnableContainer/Close}}
|
||||||
|
{{/data-sticky-header-toc-pinnable-container}}
|
||||||
{{>Dropdown/Close}}
|
{{>Dropdown/Close}}
|
||||||
{{/data-sticky-header-toc}}
|
{{/data-sticky-header-toc-dropdown}}
|
||||||
</div>
|
</div>
|
||||||
<div class="vector-sticky-header-context-bar-primary" {{{html-user-language-attributes}}}>{{{html-title}}}</div>
|
<div class="vector-sticky-header-context-bar-primary" {{{html-user-language-attributes}}}>{{{html-title}}}</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -1,8 +1,10 @@
|
||||||
{{#data-toc}}
|
{{#data-toc-container}}
|
||||||
<nav id="mw-panel-toc" role="navigation" aria-label="{{ msg-vector-toc-label }}" data-event-name="ui.sidebar-toc" class="mw-table-of-contents-container">
|
<nav id="mw-panel-toc" role="navigation" aria-label="{{ msg-vector-toc-label }}" data-event-name="ui.sidebar-toc" class="mw-table-of-contents-container">
|
||||||
{{! T313060 Additional container div needed to prevent the sticky element from being siblings with the footer }}
|
{{! T313060 Additional container div needed to prevent the sticky element from being siblings with the footer }}
|
||||||
{{>PinnableContainer/Pinned/Open}}
|
{{>PinnableContainer/Pinned/Open}}
|
||||||
{{#is-pinned}}{{>TableOfContents}}{{/is-pinned}}
|
{{#is-pinned}}
|
||||||
|
{{#data-toc}}{{>TableOfContents}}{{/data-toc}}
|
||||||
|
{{/is-pinned}}
|
||||||
{{>PinnableContainer/Close}}
|
{{>PinnableContainer/Close}}
|
||||||
</nav>
|
</nav>
|
||||||
{{/data-toc}}
|
{{/data-toc-container}}
|
||||||
|
|
|
@ -19,8 +19,6 @@ exports[`Sticky header renders 1`] = `
|
||||||
</label>
|
</label>
|
||||||
<div class=\\"vector-menu-content\\">
|
<div class=\\"vector-menu-content\\">
|
||||||
|
|
||||||
<div id=\\"vector-sticky-header-toc-unpinned-container\\" class=\\"vector-unpinned-container\\">
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
</div> </div>
|
</div> </div>
|
||||||
<div class=\\"vector-sticky-header-context-bar-primary\\"></div>
|
<div class=\\"vector-sticky-header-context-bar-primary\\"></div>
|
||||||
|
|
|
@ -58,7 +58,7 @@ const editButtonsTemplateData = [ {
|
||||||
} ];
|
} ];
|
||||||
|
|
||||||
const templateData = {
|
const templateData = {
|
||||||
'data-sticky-header-toc': {
|
'data-sticky-header-toc-dropdown': {
|
||||||
id: 'vector-sticky-header-toc',
|
id: 'vector-sticky-header-toc',
|
||||||
class: 'mw-portlet mw-portlet-sticky-header-toc vector-sticky-header-toc',
|
class: 'mw-portlet mw-portlet-sticky-header-toc vector-sticky-header-toc',
|
||||||
'html-items': '',
|
'html-items': '',
|
||||||
|
|
|
@ -109,16 +109,6 @@ class VectorComponentTableOfContentsTest extends \MediaWikiUnitTestCase {
|
||||||
'is-vector-toc-beginning-enabled' => $config[ 'VectorTableOfContentsBeginning' ],
|
'is-vector-toc-beginning-enabled' => $config[ 'VectorTableOfContentsBeginning' ],
|
||||||
'vector-is-collapse-sections-enabled' =>
|
'vector-is-collapse-sections-enabled' =>
|
||||||
$tocData[ 'number-section-count' ] >= $config[ 'VectorTableOfContentsCollapseAtCount' ],
|
$tocData[ 'number-section-count' ] >= $config[ 'VectorTableOfContentsCollapseAtCount' ],
|
||||||
'data-pinnable-header' => [
|
|
||||||
'is-pinned' => true,
|
|
||||||
'data-name' => 'vector-toc',
|
|
||||||
'data-feature-name' => null,
|
|
||||||
'label' => 'vector-toc-label',
|
|
||||||
'unpin-label' => 'vector-unpin-element-label',
|
|
||||||
'pin-label' => 'vector-pin-element-label',
|
|
||||||
'label-tag-name' => 'h2'
|
|
||||||
],
|
|
||||||
'is-pinned' => true,
|
|
||||||
'id' => 'vector-toc'
|
'id' => 'vector-toc'
|
||||||
];
|
];
|
||||||
$expectedNestedTocData = array_merge( $nestedTocData, $expectedConfigData );
|
$expectedNestedTocData = array_merge( $nestedTocData, $expectedConfigData );
|
||||||
|
|
Loading…
Reference in a new issue