UNPKG

coveo-search-ui

Version:

Coveo JavaScript Search Framework

169 lines (149 loc) 6.44 kB
import { Component } from '../Base/Component'; import { ComponentOptions } from '../Base/ComponentOptions'; import { IComponentBindings } from '../Base/ComponentBindings'; import { Initialization } from '../Base/Initialization'; import { CardOverlayEvents } from '../../events/CardOverlayEvents'; import { $$ } from '../../utils/Dom'; import { Assert } from '../../misc/Assert'; import { KeyboardUtils, KEYBOARD } from '../../utils/KeyboardUtils'; import { exportGlobally } from '../../GlobalExports'; import 'styling/_CardOverlay'; import { SVGIcons } from '../../utils/SVGIcons'; import { SVGDom } from '../../utils/SVGDom'; import { Utils } from '../../utils/Utils'; import { l } from '../../strings/Strings'; export interface ICardOverlayOptions { title: string; icon?: string; } /** * The CardOverlay component displays a button that the user can click to toggle the visibility of an overlay on top of * an {@link IQueryResult}. While this component typically populates a {@link CardActionBar} component, it is actually * possible to place a CardOverlay component anywhere in any result. * * The primary purpose of the CardOverlay component is to display additional information about a result in a format that * fits well within a card result layout (see [Result Layouts](https://docs.coveo.com/en/360/)). * * When initialized, this component creates a `<div class="coveo-card-overlay">` element as the last child of its parent * IQueryResult, and displays a button which toggles the visibility of the overlay. */ export class CardOverlay extends Component { static ID = 'CardOverlay'; static doExport = () => { exportGlobally({ CardOverlay: CardOverlay }); }; private parentCard: HTMLElement; private overlay: HTMLElement; /** * @componentOptions */ static options: ICardOverlayOptions = { /** * Specifies the string to use for the overlay title and for the button text. * * Setting a value for this option is required for this component to work. */ title: ComponentOptions.buildLocalizedStringOption({ required: true, localizedString: () => l('NoTitle') }), /** * Specifies the icon to use for the overlay icon and for the button icon. * * The name of the icon to use should be specified in dashed case. ie: facet-expand */ icon: ComponentOptions.buildIconOption() }; /** * Creates a new CardOverlay component. * @param element The HTMLElement on which to instantiate the component. * @param options The options for the CardOverlay component. * @param bindings The bindings that the component requires to function normally. If not set, these will be * automatically resolved (with a slower execution time). */ constructor(public element: HTMLElement, public options?: ICardOverlayOptions, bindings?: IComponentBindings) { super(element, CardOverlay.ID, bindings); this.options = ComponentOptions.initComponentOptions(element, CardOverlay, options); this.parentCard = $$(this.element).closest('.CoveoResult'); Assert.exists(this.parentCard); $$(this.parentCard).addClass('coveo-with-card-overlay'); this.createOverlay(); this.createButton(this.element); this.closeOverlay(); } /** * Toggles the CardOverlay visibility. * * @param swtch Specifying a value for this parameter forces the component visibility to take the corresponding value * (`true` for visible; `false` for hidden). */ public toggleOverlay(swtch?: boolean) { if (swtch !== undefined) { swtch ? this.openOverlay() : this.closeOverlay(); } else { if ($$(this.overlay).hasClass('coveo-opened')) { this.closeOverlay(); } else { this.openOverlay(); } } } /** * Opens the CardOverlay. * * Also triggers the {@link CardOverlayEvents.openCardOverlay} event. */ public openOverlay() { $$(this.overlay).removeClass('coveo-hidden-for-tab-nav'); $$(this.overlay).addClass('coveo-opened'); $$(this.parentCard).addClass('coveo-card-overlay-opened'); this.bind.trigger(this.element, CardOverlayEvents.openCardOverlay); } /** * Closes the CardOverlay. * * Also triggers the {@link CardOverlayEvents.closeCardOverlay} event. */ public closeOverlay() { $$(this.overlay).addClass('coveo-hidden-for-tab-nav'); $$(this.overlay).removeClass('coveo-opened'); $$(this.parentCard).removeClass('coveo-card-overlay-opened'); this.bind.trigger(this.element, CardOverlayEvents.closeCardOverlay); } private createOverlay() { this.overlay = $$('div', { className: 'coveo-card-overlay' }).el; // Create header let overlayHeader = $$('div', { className: 'coveo-card-overlay-header' }).el; this.createButton(overlayHeader); this.overlay.appendChild(overlayHeader); // Create body let overlayBody = $$('div', { className: 'coveo-card-overlay-body' }).el; // Transfer all of element's children to the overlay while (this.element.childNodes.length > 0) { overlayBody.appendChild(this.element.firstChild); } this.overlay.appendChild(overlayBody); // Create footer const icon = $$('span', { className: 'coveo-icon coveo-open-card-overlay' }, SVGIcons.icons.arrowDown); SVGDom.addClassToSVGInContainer(icon.el, 'coveo-open-card-overlay-svg'); let overlayFooter = $$('div', { className: 'coveo-card-overlay-footer', tabindex: '0' }, icon.el); overlayFooter.on('click', () => this.toggleOverlay(false)); this.bind.on(overlayFooter.el, 'keyup', KeyboardUtils.keypressAction(KEYBOARD.ENTER, () => this.toggleOverlay(false))); this.overlay.appendChild(overlayFooter.el); this.parentCard.appendChild(this.overlay); } private createButton(element: HTMLElement) { if (this.options.icon) { const icon = $$('span', { className: 'coveo-icon ' }, SVGIcons.icons[this.options.icon]).el; element.appendChild(icon); SVGDom.addClassToSVGInContainer(element, `coveo-${Utils.toDashCase(this.options.icon)}-svg`); } element.appendChild($$('span', { className: 'coveo-label' }, this.options.title).el); element.setAttribute('tabindex', '0'); $$(element).on('click', () => this.toggleOverlay()); this.bind.on(element, 'keyup', KeyboardUtils.keypressAction(KEYBOARD.ENTER, () => this.toggleOverlay())); } } Initialization.registerAutoCreateComponent(CardOverlay);