UNPKG

coveo-search-ui

Version:

Coveo JavaScript Search Framework

198 lines (170 loc) 7.12 kB
import { Component } from '../Base/Component'; import { ComponentOptions } from '../Base/ComponentOptions'; import { IComponentBindings } from '../Base/ComponentBindings'; import { SearchAlertsEvents, ISearchAlertsEventArgs, ISearchAlertsFailEventArgs, ISearchAlertsPopulateMessageEventArgs } from '../../events/SearchAlertEvents'; import { QueryEvents } from '../../events/QueryEvents'; import { SUBSCRIPTION_TYPE, ISubscriptionQueryRequest } from '../../rest/Subscription'; import { PopupUtils, PopupHorizontalAlignment, PopupVerticalAlignment } from '../../utils/PopupUtils'; import { l } from '../../strings/Strings'; import { $$, Dom } from '../../utils/Dom'; import * as _ from 'underscore'; import { ISearchAlertsPopulateMessageText } from '../../events/SearchAlertEvents'; import { SVGIcons } from '../../utils/SVGIcons'; import { SVGDom } from '../../utils/SVGDom'; export interface ISearchAlertMessageOptions { closeDelay: number; } /** * The SearchAlertsMessage component allows the {@link SearchAlerts} component to display messages. * * You should not include this component in your page. Instead, use a {@link SearchAlerts} component, and access the * {@link SearchAlerts.message} attribute. */ export class SearchAlertsMessage extends Component { static ID = 'SubscriptionsMessages'; /** * The options for the SearchAlertsMessage component * @componentOptions */ static options: ISearchAlertMessageOptions = { /** * Specifies how long to display the search alerts messages (in milliseconds). * * Default value is `2000`. Minimum value is `0`. */ closeDelay: ComponentOptions.buildNumberOption({ defaultValue: 2000, min: 0 }) }; private message: Dom; private closeTimeout: number; /** * Creates a new SearchAlertsMessage component * @param element The HTMLElement on which to instantiate the component. * @param options The options for the SearchAlertsMessage 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: ISearchAlertMessageOptions, public bindings?: IComponentBindings) { super(element, SearchAlertsMessage.ID, bindings); this.bind.onRootElement(SearchAlertsEvents.searchAlertsCreated, (args: ISearchAlertsEventArgs) => this.handleSubscriptionCreated(args)); this.bind.oneRootElement(SearchAlertsEvents.searchAlertsFail, (args: ISearchAlertsEventArgs) => this.handleSearchAlertsFail(args)); this.bind.oneRootElement(SearchAlertsEvents.searchAlertsDeleted, () => this.close()); this.bind.oneRootElement(QueryEvents.newQuery, () => this.close()); } public getCssClass(): string { return 'coveo-subscriptions-messages'; } public getFollowQueryMessage(query?: string, htmlFormatted = false): string { let populateMessageArguments: ISearchAlertsPopulateMessageEventArgs = { text: [] }; let getAdditionalTextFormatted = () => { return _.map(populateMessageArguments.text, text => { text = this.formatMessageArgumentsText(text); return `${htmlFormatted ? '<li>' : '('}${text}${htmlFormatted ? '</li>' : ')'}`; }).join(' '); }; $$(this.root).trigger(SearchAlertsEvents.searchAlertsPopulateMessage, populateMessageArguments); let additionalMessage = `${htmlFormatted ? '<ul>' : ''}${getAdditionalTextFormatted()}${htmlFormatted ? '</ul>' : ''}`; let automaticallyBuiltMessage: string; if (query && populateMessageArguments.text.length != 0) { automaticallyBuiltMessage = `${_.escape(query)} ${additionalMessage}`; } if (query && populateMessageArguments.text.length == 0) { automaticallyBuiltMessage = `${_.escape(query)}`; } if (!query && populateMessageArguments.text.length != 0) { automaticallyBuiltMessage = `${additionalMessage}`; } if (!query && populateMessageArguments.text.length == 0) { automaticallyBuiltMessage = htmlFormatted ? l('EmptyQuery') : _.unescape(l('EmptyQuery')); } return automaticallyBuiltMessage; } /** * Displays a message near the passed dom attribute. * @param dom Specifies where to display the message. * @param message The message. * @param error Specifies whether the message is an error message. */ public showMessage(dom: Dom, message: string, error: boolean) { this.message = $$('div', { className: 'coveo-subscriptions-messages' }); this.message.el.innerHTML = ` <div class='coveo-subscriptions-messages-message'> <div class='coveo-subscriptions-messages-content'><span>${message}</span></div> <div class='coveo-subscriptions-messages-info-close'>${SVGIcons.icons.checkboxHookExclusionMore}</div> </div>`; this.message.toggleClass('coveo-subscriptions-messages-error', error); let closeButton = this.message.find('.coveo-subscriptions-messages-info-close'); SVGDom.addClassToSVGInContainer(closeButton, 'coveo-subscript-messages-info-close-svg'); $$(closeButton).on('click', () => this.close()); PopupUtils.positionPopup( this.message.el, dom.el, this.root, { horizontal: PopupHorizontalAlignment.INNERLEFT, vertical: PopupVerticalAlignment.BOTTOM, verticalOffset: 12, horizontalClip: true }, this.root ); this.startCloseDelay(); this.message.on('mouseleave', () => { this.startCloseDelay(); }); this.message.on('mouseenter', () => { this.stopCloseDelay(); }); } private formatMessageArgumentsText(text: string | ISearchAlertsPopulateMessageText) { if (_.isString(text)) { text = _.escape(text); } else if (text.lineThrough) { text = '<span style="text-decoration:line-through">' + _.escape(text.value) + '</span>'; } else { text = _.escape(text.value); } return text; } private handleSubscriptionCreated(args: ISearchAlertsEventArgs) { this.close(); if (args.dom != null) { if (args.subscription.type == SUBSCRIPTION_TYPE.followQuery) { let typeConfig = <ISubscriptionQueryRequest>args.subscription.typeConfig; this.showMessage($$(args.dom), l('SubscriptionsMessageFollowQuery', this.getFollowQueryMessage(typeConfig.query.q, true)), false); } else { this.showMessage($$(args.dom), l('SubscriptionsMessageFollow'), false); } } } private handleSearchAlertsFail(args: ISearchAlertsFailEventArgs) { this.close(); if (args.dom != null) { this.showMessage($$(args.dom), l('SearchAlerts_Fail'), true); } } private startCloseDelay() { clearTimeout(this.closeTimeout); this.closeTimeout = window.setTimeout(() => { this.close(); }, this.options.closeDelay); } private stopCloseDelay() { clearTimeout(this.closeTimeout); } private close() { if (this.message != null) { clearTimeout(this.closeTimeout); this.message.remove(); this.message = null; } } }