Newer
Older
url: string;
description: string;
menuLinkId: string;
isExternal: string;
}
export interface SearchLabels {
label?: string;
declare global {
interface Window {
CludoSayt: any;
}
}
import {Component, Prop, h, Watch, State, Listen, Host, Event, EventEmitter, Element} from '@stencil/core';
Markus Kalijärvi
committed
import {ComponentLabels} from '../site-header';
import {ColorVariant} from '../../../utils/utils';
@Component({
tag: 'hy-site-search',
styleUrl: 'site-search.scss',
shadow: true,
@Prop() color: ColorVariant = ColorVariant.black;
@Prop() isAlternative: boolean = false;
@Prop() searchLabels: string;
@Prop() searchTools: string;
private _searchTools: SearchTools[];
@Prop() showLabel: boolean = false;
@Prop() size: number;
private _searchLabels: SearchLabels[];
private searchTitleLabel: string;
private searchCloseLabel: string;
private searchToolsLabel: string;
private searchDescriptionLabel: string;
@State() isSearchPanelOpen: boolean = false;
@Event() searchPanelToggled: EventEmitter;
private _labels: ComponentLabels[];
@Watch('labels') labelsWatcher(data: ComponentLabels[] | string) {
this._labels = typeof data === 'string' ? JSON.parse(data) : data;
}
// Special search tools.
if (this.searchTools) {
this._searchTools = JSON.parse(this.searchTools);
}
if (this.searchLabels) {
this._searchLabels = JSON.parse(this.searchLabels);
this.searchTitleLabel = this._searchLabels['search_label'];
this.searchCloseLabel = this._searchLabels['search_close_label'];
this.searchToolsLabel = this._searchLabels['search_tools_label'];
this.searchDescriptionLabel = this._searchLabels['search_description'];
componentWillRender() {
this.labelsWatcher(this.labels);
}
// CLose the search panel if user opens the desktop menu panel.
@Listen('menuDesktopToggled', {target: 'document'})
desktopMenuToggled() {
}
// CLose the search panel if user opens the mobile menu panel.
@Listen('menuMobileToggled', {target: 'document'})
mobileMenuToggled() {
}
// CLose the search panel if user opens the language menu.
@Listen('menuLanguageToggled', {target: 'document'})
menuLanguageToggled() {
// Close the search panel if user opens University main menu
@Listen('universityMainMenuToggled', {target: 'document'})
universityMainMenuPanelToggled() {
this.closeSearchPanel();
}
// CLose the search panel on Scroll down.
@Listen('headerScrollDown', {target: 'document'})
headerScrollDown() {
this.closeSearchPanel();
}
closeSearchPanel() {
let cludoSayt = document.querySelectorAll('stencil-cludo-sayt')[0] as HTMLElement;
if (cludoSayt) {
let CludoSayt = window.CludoSayt;
if (typeof CludoSayt !== 'undefined') {
CludoSayt.hide();
}
this.isSearchPanelOpen = !this.isSearchPanelOpen;
if (this.isSearchPanelOpen) {
//const searchPanelSelector = this.el as HTMLElement;
// Close desktop menu panel and lang menu panel if they are open.
this.searchPanelToggled.emit();
let hyHeader = this.el.closest('.hy-site-header') as HTMLElement;
const headerHeight = hyHeader.classList.contains('hy-site-header--sticky-active')
? `${hyHeader.offsetHeight}px`
: `${hyHeader.offsetTop + hyHeader.offsetHeight}px`;
const searchPanel = this.el.shadowRoot.querySelectorAll(`.site-search__panel`)[0] as HTMLElement;
searchPanel.style.top = headerHeight;
// Add shadow backdrop
let rect = searchPanel.getBoundingClientRect();
let shadowTop = hyHeader.classList.contains('hy-site-header--sticky-active')
? hyHeader.offsetHeight + rect.height
: hyHeader.offsetTop + hyHeader.offsetHeight + rect.height;
this.showBackdropShadow('open', shadowTop);
*/
// Remove hidden class from cludo suggestions
let cludoSayt = document.querySelectorAll('stencil-cludo-sayt')[0] as HTMLElement;
if (cludoSayt) {
cludoSayt.classList.remove('hidden');
}
// Without setTimeout it will not focus the input because it hasn't rendered yet.
setTimeout(() => {
const searchInput = this.el.shadowRoot.querySelector('input#search') as HTMLElement;
searchInput.focus();
});
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
adjustPosition(target) {
let headerHeight = '0';
let shadowTop = 0;
const searchPanel = target.shadowRoot.querySelectorAll(`.site-search__panel`)[0] as HTMLElement;
let rect = searchPanel.getBoundingClientRect();
if (this.isGroup) {
let hyHeader = target.closest('.hy-site-header__content-top') as HTMLElement;
if (hyHeader) {
let rectHeader = hyHeader.getBoundingClientRect();
headerHeight = `${rectHeader.height}px`;
// Add shadow backdrop
//@todo For some reason rect (Search Panel) is {
// "x": 0,
// "y": 0,
// "width": 0,
// "height": 0,
// "top": 0,
// "right": 0,
// "bottom": 0,
// "left": 0
// }
shadowTop = hyHeader.offsetHeight + rect.height;
}
} else {
let hyHeader = target.closest('.hy-site-header') as HTMLElement;
headerHeight = hyHeader.classList.contains('hy-site-header--sticky-active')
? `${hyHeader.offsetHeight}px`
: `${hyHeader.offsetTop + hyHeader.offsetHeight}px`;
// Add shadow backdrop
shadowTop = hyHeader.classList.contains('hy-site-header--sticky-active')
? hyHeader.offsetHeight + rect.height
: hyHeader.offsetTop + hyHeader.offsetHeight + rect.height;
}
searchPanel.style.top = headerHeight;
this.showBackdropShadow('open', shadowTop);
/*
let hyTopHeader = this.el.closest('.hy-site-header__content-top') as HTMLElement;
if (hyTopHeader && hyTopHeader.hasAttribute('is-mobile')) {
console.log('do mobile stuff');
} else {
let mainMenuToggle = target.shadowRoot.querySelector('.menu--main-group__toggle') as HTMLElement;
let mainMenuDropdown = target.shadowRoot.querySelector('.menu--main-group__dropdown') as HTMLElement;
let mainMenuList = target.shadowRoot.querySelector('.list') as HTMLElement;
if (mainMenuDropdown && mainMenuList && mainMenuToggle) {
let rectHeader = hyTopHeader.getBoundingClientRect();
let rectMenuToggle = mainMenuToggle.getBoundingClientRect();
mainMenuDropdown.style.top = `${rectHeader.height}px`;
mainMenuList.style.left = `${rectMenuToggle.left}px`;
}
}
*/
}
showBackdropShadow(state = 'close', top = 0) {
let hyHeader = this.el.closest('.hy-site-header') as HTMLElement;
let hyBackdropDiv = hyHeader.children[0] as HTMLElement;
if (hyBackdropDiv) {
if (state === 'open') {
let me = window.outerHeight - top;
hyBackdropDiv.style.height = `${me}px`;
hyBackdropDiv.style.top = `${top}px`;
hyBackdropDiv.style.position = 'absolute';
hyBackdropDiv.classList.add('is-active');
} else {
hyBackdropDiv.removeAttribute('style');
hyBackdropDiv.classList.remove('is-active');
}
}
}
'site-search': true,
'site-search__is-open': this.isSearchPanelOpen,
aria-expanded={`${this.isSearchPanelOpen}`}
group: this.isGroup,
'is-open--menu': this.isAlternative,
'is-open': this.isSearchPanelOpen,
}}
{this.showLabel ? (
<span class={{'button--search__label': true, 'button--search__label__group': this.isGroup}}>
{this._labels['label']}
</span>
) : (
''
)}
<hy-icon icon={'hy-icon-search'} size={this.size} fill={this.color} />
</button>
<div
class={{
'site-search__panel': true,
'site-search__panel__is-open': this.isSearchPanelOpen,
}}
aria-hidden={`${!this.isSearchPanelOpen}`}
<div class="site-search__panel__wrapper">
<div class="site-search__panel__title">
<div class="site-search__panel__title__group">
<h1>{this.searchTitleLabel}</h1>
<div class="description">{this.searchDescriptionLabel}</div>
<div id="cludo-search-results" class="container_12">
<div class="search-banner"></div>
<div class="search-filters search-filters-mobile"></div>
<div class="col-md-12">
<div style={{margin: '20px 0 32px'}} id="cludo-search-content-form">
<hy-search-field input-id="search" label=""></hy-search-field>
</div>
</div>
<div class="col-md-3">
<div class="search-filters" aria-controls="search-results"></div>
</div>
<div class="col-md-9">
<div class="search-results-container">
<hy-paragraph-text>
<div class="search-result-count"></div>
</hy-paragraph-text>
<div class="search-did-you-mean" role="Complementary"></div>
<div class="search-results" role="region" id="search-results" aria-live="polite"></div>
</div>
</div>
{this._searchTools && this._searchTools.length > 0 && (
<div class="title">{this.searchToolsLabel}</div>
<div class="list">
{this._searchTools.map((i) => {
let searchToolTarget = i.isExternal ? '_blank' : '_self';
return (
<a class="search-special-tool" href={i.url} target={searchToolTarget}>
<hy-icon icon={'hy-icon-arrow-to-right'} size={14} fill={ColorVariant.black} />
<span class="label">{i.label}</span>
<span class="description">{i.description}</span>
</a>
);
})}
</div>
class={{
'site-search__panel__panel-toggle': true,
}}
aria-label={this.searchCloseLabel}
aria-expanded={`${this.isSearchPanelOpen}`}
>
<span class="site-search__panel__panel-toggle__label">
<span class="site-search__panel__panel-toggle__label__title" tabindex="0">
{this.searchCloseLabel}
</span>
<hy-icon icon={'hy-icon-remove'} size={16} fill={ColorVariant.black} />
</span>
</button>