Wire up sticky header search feature
Bug: T289724 Change-Id: I784ea5eb12b6f43d19769ff48a14d3fd4627853c
This commit is contained in:
parent
caed16e26f
commit
125ea5dea9
|
@ -87,3 +87,10 @@
|
||||||
.vector-user-menu-legacy #pt-userpage a {
|
.vector-user-menu-legacy #pt-userpage a {
|
||||||
background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAUCAYAAACNiR0NAAAAx0lEQVQ4jdXSzQmEQAwFYEuYUixhSwgkA8mQgKXYgS3YgXZgCZagHWgHuxf14t8osssGcv145CVJvjk+hBRFK2TrkK1D0cqHkN7CUBRI7L21KAqXMIDModiwD9oAkLlH0i3L+ooGiTWPAPPfJQTIHLGOB9h46YZnKS+3PI8PISW2GkV7FO2Jrb79h4+ODyElsYJYm437NSRWRCWdylgj++U0u+UAZI5E22hsWW03UWQtr2NT66zlCjz8uzNQbFiDN7F5/xB8aj57Ynp2FKI0bAAAAABJRU5ErkJggg==") !important;
|
background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAUCAYAAACNiR0NAAAAx0lEQVQ4jdXSzQmEQAwFYEuYUixhSwgkA8mQgKXYgS3YgXZgCZagHWgHuxf14t8osssGcv145CVJvjk+hBRFK2TrkK1D0cqHkN7CUBRI7L21KAqXMIDModiwD9oAkLlH0i3L+ooGiTWPAPPfJQTIHLGOB9h46YZnKS+3PI8PISW2GkV7FO2Jrb79h4+ODyElsYJYm437NSRWRCWdylgj++U0u+UAZI5E22hsWW03UWQtr2NT66zlCjz8uzNQbFiDN7F5/xB8aj57Ynp2FKI0bAAAAABJRU5ErkJggg==") !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.mw-ui-icon-wikimedia-speechBubbles:before {
|
||||||
|
background-image: linear-gradient(transparent, transparent), url("data:image/svg+xml,%3Csvg xmlns=%22http://www.w3.org/2000/svg%22 width=%2220%22 height=%2220%22 viewBox=%220 0 20 20%22%3E%3Ctitle%3Espeech bubbles%3C/title%3E%3Cg fill=%22%23000%22%3E%3Cpath d=%22M17 4v7a2 2 0 01-2 2H4v1a2 2 0 002 2h10l4 4V6a2 2 0 00-2-2zM6 10H0v6z%22/%3E%3Crect width=%2216%22 height=%2212%22 rx=%222%22/%3E%3C/g%3E%3C/svg%3E");
|
||||||
|
}
|
||||||
|
.mw-ui-icon-wikimedia-history:before {
|
||||||
|
background-image: linear-gradient(transparent, transparent), url("data:image/svg+xml,%3Csvg xmlns=%22http://www.w3.org/2000/svg%22 width=%2220%22 height=%2220%22 viewBox=%220 0 20 20%22%3E%3Ctitle%3Ehistory%3C/title%3E%3Cg fill=%22%23000%22%3E%3Cpath d=%22M9 6v5h.06l2.48 2.47 1.41-1.41L11 10.11V6z%22/%3E%3Cpath d=%22M10 1a9 9 0 00-7.85 13.35L.5 16H6v-5.5l-2.38 2.38A7 7 0 1110 17v2a9 9 0 000-18z%22/%3E%3C/g%3E%3C/svg%3E");
|
||||||
|
}
|
||||||
|
|
|
@ -329,21 +329,19 @@ class SkinVector extends SkinMustache {
|
||||||
/**
|
/**
|
||||||
* Generate data needed to generate the sticky header.
|
* Generate data needed to generate the sticky header.
|
||||||
* Lack of i18n is intentional and will be done as part of follow up work.
|
* Lack of i18n is intentional and will be done as part of follow up work.
|
||||||
|
* @param array $searchBoxData
|
||||||
* @return array
|
* @return array
|
||||||
*/
|
*/
|
||||||
private function getStickyHeaderData() {
|
private function getStickyHeaderData( $searchBoxData ) {
|
||||||
return [
|
return [
|
||||||
'data-primary-action' => !$this->shouldHideLanguages() ? $this->getULSButtonData() : null,
|
'data-primary-action' => !$this->shouldHideLanguages() ? $this->getULSButtonData() : null,
|
||||||
'data-button-start' => [
|
'data-button-start' => [
|
||||||
'href' => '#p-search',
|
|
||||||
'label' => $this->msg( 'search' ),
|
'label' => $this->msg( 'search' ),
|
||||||
'icon' => 'wikimedia-search',
|
'icon' => 'wikimedia-search',
|
||||||
'is-quiet' => true,
|
'is-quiet' => true,
|
||||||
'class' => 'vector-sticky-header-search-toggle',
|
'class' => 'vector-sticky-header-search-toggle',
|
||||||
],
|
],
|
||||||
'data-search' => [
|
'data-search' => $searchBoxData,
|
||||||
'class' => $this->shouldSearchExpand() ? self::SEARCH_EXPANDING_CLASS : '',
|
|
||||||
],
|
|
||||||
'data-buttons' => [
|
'data-buttons' => [
|
||||||
self::TALK_ICON, self::HISTORY_ICON, self::NO_ICON, self::NO_ICON
|
self::TALK_ICON, self::HISTORY_ICON, self::NO_ICON, self::NO_ICON
|
||||||
]
|
]
|
||||||
|
@ -385,9 +383,24 @@ class SkinVector extends SkinMustache {
|
||||||
|
|
||||||
'is-language-in-header' => $this->isLanguagesInHeader(),
|
'is-language-in-header' => $this->isLanguagesInHeader(),
|
||||||
|
|
||||||
|
'data-search-box' => $this->getSearchData(
|
||||||
|
$parentData['data-search-box'],
|
||||||
|
!$this->isLegacy(),
|
||||||
|
// is primary mode of search
|
||||||
|
true,
|
||||||
|
'searchform'
|
||||||
|
),
|
||||||
'data-vector-sticky-header' => VectorServices::getFeatureManager()->isFeatureEnabled(
|
'data-vector-sticky-header' => VectorServices::getFeatureManager()->isFeatureEnabled(
|
||||||
Constants::FEATURE_STICKY_HEADER
|
Constants::FEATURE_STICKY_HEADER
|
||||||
) ? $this->getStickyHeaderData() : false,
|
) ? $this->getStickyHeaderData(
|
||||||
|
$this->getSearchData(
|
||||||
|
$parentData['data-search-box'],
|
||||||
|
// Collapse inside search box is disabled.
|
||||||
|
false,
|
||||||
|
false,
|
||||||
|
'vector-sticky-search-form'
|
||||||
|
)
|
||||||
|
) : false,
|
||||||
] );
|
] );
|
||||||
|
|
||||||
if ( $skin->getUser()->isRegistered() ) {
|
if ( $skin->getUser()->isRegistered() ) {
|
||||||
|
@ -409,13 +422,6 @@ class SkinVector extends SkinMustache {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
$commonSkinData['data-search-box'] = $this->getSearchData(
|
|
||||||
$commonSkinData['data-search-box'],
|
|
||||||
!$this->isLegacy(),
|
|
||||||
true,
|
|
||||||
'searchform'
|
|
||||||
);
|
|
||||||
|
|
||||||
return $commonSkinData;
|
return $commonSkinData;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -14,7 +14,12 @@
|
||||||
class="vector-search-box-inner"
|
class="vector-search-box-inner"
|
||||||
{{#input-location}} data-search-loc="{{.}}"{{/input-location}}>
|
{{#input-location}} data-search-loc="{{.}}"{{/input-location}}>
|
||||||
<input class="vector-search-box-input"
|
<input class="vector-search-box-input"
|
||||||
{{{html-input-attributes}}} {{#is-primary}}id="searchInput"{{/is-primary}} />
|
{{#is-primary}}{{{html-input-attributes}}} id="searchInput"{{/is-primary}}
|
||||||
|
{{^is-primary}}
|
||||||
|
type="search" name="search"
|
||||||
|
placeholder="{{msg-searchsuggest-search}}"
|
||||||
|
{{/is-primary}}
|
||||||
|
/>
|
||||||
<input type="hidden" name="title" value="{{page-title}}"/>
|
<input type="hidden" name="title" value="{{page-title}}"/>
|
||||||
{{! We construct two buttons (for 'go' and 'fulltext' search modes), but only one will be
|
{{! We construct two buttons (for 'go' and 'fulltext' search modes), but only one will be
|
||||||
visible and actionable at a time (they are overlaid on top of each other in CSS).
|
visible and actionable at a time (they are overlaid on top of each other in CSS).
|
||||||
|
|
|
@ -7,9 +7,7 @@
|
||||||
{{/data-button-start}}
|
{{/data-button-start}}
|
||||||
</div>
|
</div>
|
||||||
{{#data-search}}
|
{{#data-search}}
|
||||||
<div class="vector-search-box {{class}}">
|
{{>SearchBox}}
|
||||||
<div class="vector-secondary-search" id="vector-sticky-header-search"></div>
|
|
||||||
</div>
|
|
||||||
{{/data-search}}
|
{{/data-search}}
|
||||||
<div class="vector-sticky-header-context-bar">
|
<div class="vector-sticky-header-context-bar">
|
||||||
<div class="vector-sticky-header-context-bar-primary">{{html-title}}</div>
|
<div class="vector-sticky-header-context-bar-primary">{{html-title}}</div>
|
||||||
|
|
|
@ -23,7 +23,6 @@ var /** @type {VectorResourceLoaderVirtualConfig} */
|
||||||
LOAD_START_MARK = 'mwVectorVueSearchLoadStart',
|
LOAD_START_MARK = 'mwVectorVueSearchLoadStart',
|
||||||
LOAD_END_MARK = 'mwVectorVueSearchLoadEnd',
|
LOAD_END_MARK = 'mwVectorVueSearchLoadEnd',
|
||||||
LOAD_MEASURE = 'mwVectorVueSearchLoadStartToLoadEnd',
|
LOAD_MEASURE = 'mwVectorVueSearchLoadStartToLoadEnd',
|
||||||
SEARCH_INPUT_ID = 'searchInput',
|
|
||||||
SEARCH_LOADING_CLASS = 'search-form__loader';
|
SEARCH_LOADING_CLASS = 'search-form__loader';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -75,8 +74,8 @@ function renderSearchLoadingIndicator( event ) {
|
||||||
|
|
||||||
if (
|
if (
|
||||||
!( event.currentTarget instanceof HTMLElement ) ||
|
!( event.currentTarget instanceof HTMLElement ) ||
|
||||||
!( event.target instanceof HTMLInputElement ) ||
|
!( event.target instanceof HTMLInputElement )
|
||||||
!( input.id === SEARCH_INPUT_ID ) ) {
|
) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -177,6 +176,14 @@ function initSearchLoader( document ) {
|
||||||
searchBoxes.forEach( function ( searchBox ) {
|
searchBoxes.forEach( function ( searchBox ) {
|
||||||
var searchInner = searchBox.querySelector( 'form > div' ),
|
var searchInner = searchBox.querySelector( 'form > div' ),
|
||||||
searchInput = searchBox.querySelector( 'input[name="search"]' ),
|
searchInput = searchBox.querySelector( 'input[name="search"]' ),
|
||||||
|
clearLoadingIndicators = function () {
|
||||||
|
setLoadingIndicatorListeners(
|
||||||
|
// @ts-ignore
|
||||||
|
searchInner,
|
||||||
|
false,
|
||||||
|
renderSearchLoadingIndicator
|
||||||
|
);
|
||||||
|
},
|
||||||
isPrimarySearch = searchInput && searchInput.getAttribute( 'id' ) === 'searchInput';
|
isPrimarySearch = searchInput && searchInput.getAttribute( 'id' ) === 'searchInput';
|
||||||
|
|
||||||
if ( !searchInput || !searchInner ) {
|
if ( !searchInput || !searchInner ) {
|
||||||
|
@ -190,15 +197,12 @@ function initSearchLoader( document ) {
|
||||||
searchInput,
|
searchInput,
|
||||||
'skins.vector.search',
|
'skins.vector.search',
|
||||||
isPrimarySearch ? LOAD_START_MARK : null,
|
isPrimarySearch ? LOAD_START_MARK : null,
|
||||||
|
// Make sure we clearLoadingIndicators so that event listeners are removed.
|
||||||
|
// Note, loading Vue.js will remove the element from the DOM.
|
||||||
isPrimarySearch ? function () {
|
isPrimarySearch ? function () {
|
||||||
markLoadEnd( LOAD_START_MARK, LOAD_END_MARK, LOAD_MEASURE );
|
markLoadEnd( LOAD_START_MARK, LOAD_END_MARK, LOAD_MEASURE );
|
||||||
setLoadingIndicatorListeners(
|
clearLoadingIndicators();
|
||||||
// @ts-ignore
|
} : clearLoadingIndicators
|
||||||
searchInner,
|
|
||||||
false,
|
|
||||||
renderSearchLoadingIndicator
|
|
||||||
);
|
|
||||||
} : null
|
|
||||||
);
|
);
|
||||||
} );
|
} );
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
var
|
var
|
||||||
STICKY_HEADER_ID = 'vector-sticky-header',
|
STICKY_HEADER_ID = 'vector-sticky-header',
|
||||||
|
initSearchToggle = require( './searchToggle.js' ),
|
||||||
STICKY_HEADER_APPENDED_ID = '-sticky-header',
|
STICKY_HEADER_APPENDED_ID = '-sticky-header',
|
||||||
STICKY_HEADER_VISIBLE_CLASS = 'vector-sticky-header-visible',
|
STICKY_HEADER_VISIBLE_CLASS = 'vector-sticky-header-visible',
|
||||||
STICKY_HEADER_USER_MENU_CONTAINER_CLASS = 'vector-sticky-header-icon-end',
|
STICKY_HEADER_USER_MENU_CONTAINER_CLASS = 'vector-sticky-header-icon-end',
|
||||||
|
@ -158,14 +159,7 @@ function setupSearchIfNeeded( header ) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Load the `skins.vector.search` module here or setup an event handler to
|
initSearchToggle( searchToggle );
|
||||||
// load it depending on the outcome of T289718. After it loads, initialize the
|
|
||||||
// search toggle.
|
|
||||||
//
|
|
||||||
// Example:
|
|
||||||
// mw.loader.using( 'skins.vector.search', function () {
|
|
||||||
// initSearchToggle( searchToggle );
|
|
||||||
// } );
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -36,6 +36,11 @@
|
||||||
display: none;
|
display: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Hide any open menus/search results unless sticky header is visible
|
||||||
|
&:not( .vector-sticky-header-visible ) > div {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
&-visible {
|
&-visible {
|
||||||
transform: translateY( 0% );
|
transform: translateY( 0% );
|
||||||
}
|
}
|
||||||
|
|
|
@ -53,6 +53,7 @@
|
||||||
"search",
|
"search",
|
||||||
"searchbutton",
|
"searchbutton",
|
||||||
"searcharticle",
|
"searcharticle",
|
||||||
|
"searchsuggest-search",
|
||||||
"sitesubtitle",
|
"sitesubtitle",
|
||||||
"sitetitle",
|
"sitetitle",
|
||||||
"tagline"
|
"tagline"
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
import template from '!!raw-loader!../includes/templates/StickyHeader.mustache';
|
import template from '!!raw-loader!../includes/templates/StickyHeader.mustache';
|
||||||
import Button from '!!raw-loader!../includes/templates/Button.mustache';
|
import Button from '!!raw-loader!../includes/templates/Button.mustache';
|
||||||
|
import { searchBoxData } from './SearchBox.stories.data';
|
||||||
|
|
||||||
const NO_ICON = {
|
const NO_ICON = {
|
||||||
icon: 'none',
|
icon: 'none',
|
||||||
|
@ -7,6 +8,18 @@ const NO_ICON = {
|
||||||
class: 'sticky-header-icon'
|
class: 'sticky-header-icon'
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const TALK_ICON = {
|
||||||
|
icon: 'none',
|
||||||
|
'is-quiet': true,
|
||||||
|
class: 'sticky-header-icon mw-ui-icon-wikimedia-speechBubbles'
|
||||||
|
};
|
||||||
|
|
||||||
|
const HISTORY_ICON = {
|
||||||
|
icon: 'none',
|
||||||
|
'is-quiet': true,
|
||||||
|
class: 'sticky-header-icon mw-ui-icon-wikimedia-history'
|
||||||
|
};
|
||||||
|
|
||||||
const data = {
|
const data = {
|
||||||
title: 'Audre Lorde',
|
title: 'Audre Lorde',
|
||||||
heading: 'Introduction',
|
heading: 'Introduction',
|
||||||
|
@ -18,19 +31,16 @@ const data = {
|
||||||
label: '196 languages',
|
label: '196 languages',
|
||||||
'html-vector-button-icon': `<span class="mw-ui-icon mw-ui-icon-wikimedia-language"></span>`
|
'html-vector-button-icon': `<span class="mw-ui-icon mw-ui-icon-wikimedia-language"></span>`
|
||||||
},
|
},
|
||||||
'data-search': {
|
'data-search': searchBoxData,
|
||||||
class: ''
|
|
||||||
},
|
|
||||||
'data-button-start': {
|
'data-button-start': {
|
||||||
icon: 'wikimedia-search',
|
icon: 'wikimedia-search',
|
||||||
href: '#',
|
class: 'vector-sticky-header-search-toggle',
|
||||||
class: 'search-toggle',
|
|
||||||
'is-quiet': true,
|
'is-quiet': true,
|
||||||
label: 'Search'
|
label: 'Search'
|
||||||
},
|
},
|
||||||
'data-button-end': NO_ICON,
|
'data-button-end': NO_ICON,
|
||||||
'data-buttons': [
|
'data-buttons': [
|
||||||
NO_ICON, NO_ICON, NO_ICON, NO_ICON
|
TALK_ICON, HISTORY_ICON, NO_ICON, NO_ICON
|
||||||
]
|
]
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue