[Template] Move search template code into component

Bug: T322089
Change-Id: I8ad3218e99c07ea913df51a2b2134721568cdbf9
This commit is contained in:
Jon Robson 2022-10-27 09:11:32 -07:00
parent 042fe91b68
commit 62aa69fa77
5 changed files with 196 additions and 100 deletions

View file

@ -0,0 +1,151 @@
<?php
namespace MediaWiki\Skins\Vector\Components;
use Config;
use Linker;
use MessageLocalizer;
use Title;
/**
* VectorSearchBox component
*/
class VectorComponentSearchBox implements VectorComponent {
/** @var MessageLocalizer */
private $localizer;
/** @var array */
private $searchBoxData;
/** @var bool */
private $isCollapsible;
/** @var bool */
private $isPrimary;
/** @var string */
private $formId;
/** @var bool */
private $autoExpandWidth;
/** @var string */
private $location;
/** @var Config */
private $config;
private const SEARCH_SHOW_THUMBNAIL_CLASS = 'vector-search-box-show-thumbnail';
private const SEARCH_AUTO_EXPAND_WIDTH_CLASS = 'vector-search-box-auto-expand-width';
/**
* @return Config
*/
private function getConfig(): Config {
return $this->config;
}
/**
* Returns `true` if Vue search is enabled to show thumbnails and `false` otherwise.
* Note this is only relevant for Vue search experience (not legacy search).
*
* @return bool
*/
private function doesSearchHaveThumbnails(): bool {
return $this->getConfig()->get( 'VectorWvuiSearchOptions' )['showThumbnail'];
}
/**
* Gets the value of the "input-location" parameter for the SearchBox Mustache template.
*
* @return string Either `Constants::SEARCH_BOX_INPUT_LOCATION_DEFAULT` or
* `Constants::SEARCH_BOX_INPUT_LOCATION_MOVED`
*/
private function getSearchBoxInputLocation(): string {
return $this->location;
}
/**
* Annotates search box with Vector-specific information
*
* @param array $searchBoxData
* @param bool $isCollapsible
* @param bool $isPrimary
* @param string $formId
* @param bool $autoExpandWidth
* @return array modified version of $searchBoxData
*/
private function getSearchData(
array $searchBoxData,
bool $isCollapsible,
bool $isPrimary,
string $formId,
bool $autoExpandWidth
) {
$searchClass = 'vector-search-box-vue ';
if ( $isCollapsible ) {
$searchClass .= ' vector-search-box-collapses ';
}
if ( $this->doesSearchHaveThumbnails() ) {
$searchClass .= ' ' . self::SEARCH_SHOW_THUMBNAIL_CLASS .
( $autoExpandWidth ? ' ' . self::SEARCH_AUTO_EXPAND_WIDTH_CLASS : '' );
}
// Annotate search box with a component class.
$searchBoxData['class'] = trim( $searchClass );
$searchBoxData['is-collapsible'] = $isCollapsible;
$searchBoxData['is-primary'] = $isPrimary;
$searchBoxData['form-id'] = $formId;
$searchBoxData['input-location'] = $this->getSearchBoxInputLocation();
// At lower resolutions the search input is hidden search and only the submit button is shown.
// It should behave like a form submit link (e.g. submit the form with no input value).
// We'll wire this up in a later task T284242.
$collapseIconAttrs = Linker::tooltipAndAccesskeyAttribs( 'search' );
$searchBoxData['data-collapse-icon'] = array_merge( [
'href' => Title::newFromText( $searchBoxData['page-title'] )->getLocalUrl(),
'label' => $this->localizer->msg( 'search' ),
'icon' => 'wikimedia-search',
'is-quiet' => true,
'class' => 'search-toggle',
], $collapseIconAttrs );
return $searchBoxData;
}
/**
* @param array $searchBoxData
* @param bool $isCollapsible
* @param bool $isPrimary
* @param string $formId
* @param bool $autoExpandWidth
* @param Config $config
* @param string $location
* @param MessageLocalizer $localizer
*/
public function __construct(
array $searchBoxData,
bool $isCollapsible,
bool $isPrimary,
string $formId,
bool $autoExpandWidth,
Config $config,
string $location,
MessageLocalizer $localizer
) {
$this->searchBoxData = $searchBoxData;
$this->isCollapsible = $isCollapsible;
$this->isPrimary = $isPrimary;
$this->formId = $formId;
$this->autoExpandWidth = $autoExpandWidth;
$this->location = $location;
$this->config = $config;
$this->localizer = $localizer;
}
/**
* @inheritDoc
*/
public function getTemplateData(): array {
return $this->getSearchData(
$this->searchBoxData,
$this->isCollapsible,
$this->isPrimary,
$this->formId,
$this->autoExpandWidth
);
}
}

View file

@ -115,8 +115,6 @@ abstract class SkinVector extends SkinMustache {
'tabindex' => '-1',
'class' => 'sticky-header-icon'
];
private const SEARCH_SHOW_THUMBNAIL_CLASS = 'vector-search-box-show-thumbnail';
private const SEARCH_AUTO_EXPAND_WIDTH_CLASS = 'vector-search-box-auto-expand-width';
private const CLASS_PROGRESSIVE = 'mw-ui-progressive';
/**
@ -396,63 +394,6 @@ abstract class SkinVector extends SkinMustache {
];
}
/**
* Annotates search box with Vector-specific information
*
* @param array $searchBoxData
* @param bool $isCollapsible
* @param bool $isPrimary
* @param string $formId
* @param bool $autoExpandWidth
* @param bool $hasLabel whether search should have a label
* @param string $location Either `Constants::SEARCH_BOX_INPUT_LOCATION_DEFAULT` or
* `Constants::SEARCH_BOX_INPUT_LOCATION_MOVED`
* @return array modified version of $searchBoxData
*/
final protected function getSearchData(
array $searchBoxData,
bool $isCollapsible,
bool $isPrimary,
string $formId,
bool $autoExpandWidth,
bool $hasLabel,
string $location
) {
$searchClass = 'vector-search-box-vue ';
if ( $isCollapsible ) {
$searchClass .= ' vector-search-box-collapses ';
}
if ( $this->doesSearchHaveThumbnails() ) {
$searchClass .= ' ' . self::SEARCH_SHOW_THUMBNAIL_CLASS .
( $autoExpandWidth ? ' ' . self::SEARCH_AUTO_EXPAND_WIDTH_CLASS : '' );
}
// Annotate search box with a component class.
$searchBoxData['class'] = trim( $searchClass );
$searchBoxData['is-collapsible'] = $isCollapsible;
$searchBoxData['is-primary'] = $isPrimary;
$searchBoxData['form-id'] = $formId;
// At lower resolutions the search input is hidden search and only the submit button is shown.
// It should behave like a form submit link (e.g. submit the form with no input value).
// We'll wire this up in a later task T284242.
$collapseIconAttrs = Linker::tooltipAndAccesskeyAttribs( 'search' );
$searchBoxData['data-collapse-icon'] = array_merge( [
'href' => Title::newFromText( $searchBoxData['page-title'] )->getLocalUrl(),
'label' => $this->msg( 'search' ),
'icon' => 'wikimedia-search',
'is-quiet' => true,
'class' => 'search-toggle',
], $collapseIconAttrs );
return $searchBoxData + [
'has-label' => $hasLabel,
'input-location' => $location,
];
}
/**
* @inheritDoc
*/
@ -471,16 +412,6 @@ abstract class SkinVector extends SkinMustache {
return $responsive;
}
/**
* Returns `true` if Vue search is enabled to show thumbnails and `false` otherwise.
* Note this is only relevant for Vue search experience (not legacy search).
*
* @return bool
*/
private function doesSearchHaveThumbnails(): bool {
return $this->getConfig()->get( 'VectorWvuiSearchOptions' )['showThumbnail'];
}
/**
* Get the ULS button label, accounting for the number of available
* languages.

View file

@ -4,6 +4,7 @@ namespace MediaWiki\Skins\Vector;
use MediaWiki\MediaWikiServices;
use MediaWiki\Skins\Vector\Components\VectorComponentMainMenu;
use MediaWiki\Skins\Vector\Components\VectorComponentSearchBox;
/**
* @ingroup Skins
@ -242,8 +243,19 @@ class SkinVector22 extends SkinVector {
);
}
$user = $this->getUser();
$config = $this->getConfig();
$components = [
'data-search-box' => new VectorComponentSearchBox(
$parentData['data-search-box'],
true,
// is primary mode of search
true,
'searchform',
true,
$config,
Constants::SEARCH_BOX_INPUT_LOCATION_MOVED,
$this->getContext()
),
'data-portlets-main-menu' => new VectorComponentMainMenu(
$parentData['data-portlets-sidebar'],
$this,
@ -257,17 +269,19 @@ class SkinVector22 extends SkinVector {
}
}
$searchStickyHeader = new VectorComponentSearchBox(
$parentData['data-search-box'],
// Collapse inside search box is disabled.
false,
false,
'vector-sticky-search-form',
false,
$config,
Constants::SEARCH_BOX_INPUT_LOCATION_MOVED,
$this->getContext()
);
return array_merge( $parentData, [
'data-search-box' => $this->getSearchData(
$parentData['data-search-box'],
true,
// is primary mode of search
true,
'searchform',
true,
false,
Constants::SEARCH_BOX_INPUT_LOCATION_MOVED
),
'is-language-in-content' => $this->isLanguagesInContent(),
'is-language-in-content-top' => $this->isLanguagesInContentAt( 'top' ),
'is-language-in-content-bottom' => $this->isLanguagesInContentAt( 'bottom' ),
@ -277,16 +291,7 @@ class SkinVector22 extends SkinVector {
'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,
false,
Constants::SEARCH_BOX_INPUT_LOCATION_MOVED
),
$searchStickyHeader->getTemplateData(),
$featureManager->isFeatureEnabled(
Constants::FEATURE_STICKY_HEADER_EDIT
)

View file

@ -2,6 +2,8 @@
namespace MediaWiki\Skins\Vector;
use MediaWiki\Skins\Vector\Components\VectorComponentSearchBox;
/**
* @ingroup Skins
* @package Vector
@ -172,21 +174,27 @@ class SkinVectorLegacy extends SkinVector {
public function getTemplateData(): array {
$parentData = $this->decoratePortletsData( parent::getTemplateData() );
// SkinVector sometimes serves new Vector as part of removing the
// skin version user preference. To avoid T302461 we need to unset it here.
// This shouldn't be run on SkinVector22.
unset( $parentData['data-toc'] );
return array_merge( $parentData, [
'data-search-box' => $this->getSearchData(
$components = [
'data-search-box' => new VectorComponentSearchBox(
$parentData['data-search-box'],
false,
// is primary mode of search
true,
'searchform',
true,
true,
Constants::SEARCH_BOX_INPUT_LOCATION_DEFAULT
)
] );
$this->getConfig(),
Constants::SEARCH_BOX_INPUT_LOCATION_DEFAULT,
$this->getContext()
),
];
foreach ( $components as $key => $component ) {
$parentData[$key] = $component->getTemplateData();
}
// SkinVector sometimes serves new Vector as part of removing the
// skin version user preference. To avoid T302461 we need to unset it here.
// This shouldn't be run on SkinVector22.
unset( $parentData['data-toc'] );
return $parentData;
}
}

View file

@ -152,6 +152,7 @@
"MediaWiki\\Skins\\Vector\\": "includes/"
},
"TestAutoloadNamespaces": {
"MediaWiki\\Skins\\Vector\\": "includes/",
"MediaWiki\\Skins\\Vector\\Tests\\": "tests/phpunit/"
},
"ConfigRegistry": {