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();
this.adjustPosition(this.el);
// 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();
});
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
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
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);
}
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>