coveo-search-ui
Version:
Coveo JavaScript Search Framework
198 lines (170 loc) • 7.12 kB
text/typescript
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;
}
}
}