coveo-search-ui
Version:
Coveo JavaScript Search Framework
149 lines (131 loc) • 6.08 kB
text/typescript
import { Component } from '../Base/Component';
import { ComponentOptions } from '../Base/ComponentOptions';
import { IComponentBindings } from '../Base/ComponentBindings';
import { l } from '../../strings/Strings';
import { QueryEvents, IBuildingQueryEventArgs } from '../../events/QueryEvents';
import { BreadcrumbEvents, IPopulateBreadcrumbEventArgs } from '../../events/BreadcrumbEvents';
import { analyticsActionCauseList, IAnalyticsContextRemoveMeta } from '../Analytics/AnalyticsActionListMeta';
import { QUERY_STATE_ATTRIBUTES, QueryStateModel } from '../../models/QueryStateModel';
import { $$ } from '../../utils/Dom';
import { Utils } from '../../utils/Utils';
import { Initialization } from '../Base/Initialization';
import { Assert } from '../../misc/Assert';
import * as _ from 'underscore';
import { exportGlobally } from '../../GlobalExports';
import 'styling/_HiddenQuery';
import { SVGIcons } from '../../utils/SVGIcons';
export interface IHiddenQueryOptions {
maximumDescriptionLength: number;
title: string;
}
/**
* The HiddenQuery component handles a "hidden" query parameter (`hq`) and its description (`hd`).
*
* Concretely, this means that if a HiddenQuery component is present in your page and you load your search interface
* with `hq=foo&hd=bar` in the URL hash, the component adds `foo` as an expression to the query (`hq` is the hidden
* query) and renders `bar` in the {@link Breadcrumb} (`hd` is the hidden query description).
*/
export class HiddenQuery extends Component {
static ID = 'HiddenQuery';
static doExport = () => {
exportGlobally({
HiddenQuery: HiddenQuery
});
};
/**
* Possible options for the `HiddenQuery` component
* @componentOptions
*/
static options: IHiddenQueryOptions = {
/**
* Specifies the maximum number of characters from the hidden query description (`hd`) to display in the
* {@link Breadcrumb}.
*
* Beyond this length, the HiddenQuery component slices the rest of the description and replaces it by `...`.
*
* Default value is `100`. Minimum value is `0`.
*/
maximumDescriptionLength: ComponentOptions.buildNumberOption({ min: 0, defaultValue: 100 }),
/**
* Specifies the title that should appear in the {@link Breadcrumb} when the HiddenQuery populates it.
*
* Default value is the localized string f
* or `"Additional filters:"`
*/
title: ComponentOptions.buildLocalizedStringOption({
localizedString: () => l('AdditionalFilters') + ':'
})
};
/**
* Creates a new HiddenQuery component, which binds multiple events ({@link QueryEvents.buildingQuery},
* {@link BreadcrumbEvents.populateBreadcrumb} and {@link BreadcrumbEvents.clearBreadcrumb}).
* @param element The HTMLElement on which to instantiate the component.
* @param options The options for the HiddenQuery 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?: IHiddenQueryOptions, bindings?: IComponentBindings) {
super(element, HiddenQuery.ID, bindings);
this.options = ComponentOptions.initComponentOptions(element, HiddenQuery, options);
this.bind.onRootElement(QueryEvents.buildingQuery, (args: IBuildingQueryEventArgs) => this.handleBuildingQuery(args));
this.bind.onRootElement(BreadcrumbEvents.populateBreadcrumb, (args: IPopulateBreadcrumbEventArgs) =>
this.handlePopulateBreadcrumb(args)
);
this.bind.onRootElement(BreadcrumbEvents.clearBreadcrumb, () => this.setStateEmpty());
}
/**
* Clears any `hd` or `hq` set in the {@link QueryStateModel}.
* Also logs the `contextRemove` event in the usage analytics and triggers a new query.
*/
public clear() {
this.setStateEmpty();
const hiddenDescriptionRemoved = this.getDescription();
this.usageAnalytics.logSearchEvent<IAnalyticsContextRemoveMeta>(analyticsActionCauseList.contextRemove, {
contextName: hiddenDescriptionRemoved
});
this.queryController.executeQuery();
}
private setStateEmpty() {
this.queryStateModel.set(QUERY_STATE_ATTRIBUTES.HD, '');
this.queryStateModel.set(QUERY_STATE_ATTRIBUTES.HQ, '');
}
private handleBuildingQuery(data: IBuildingQueryEventArgs) {
Assert.exists(data);
const hiddenQuery = this.queryStateModel.get(QUERY_STATE_ATTRIBUTES.HQ);
if (Utils.isNonEmptyString(hiddenQuery)) {
data.queryBuilder.advancedExpression.add(hiddenQuery);
}
}
private handlePopulateBreadcrumb(args: IPopulateBreadcrumbEventArgs) {
const description = this.getDescription();
if (!_.isEmpty(description) && !_.isEmpty(this.queryStateModel.get(QUERY_STATE_ATTRIBUTES.HQ))) {
const elem = document.createElement('div');
$$(elem).addClass('coveo-hidden-query-breadcrumb');
const title = document.createElement('span');
$$(title).addClass('coveo-hidden-query-breadcrumb-title');
$$(title).text(this.options.title);
elem.appendChild(title);
const value = $$('span', { className: 'coveo-hidden-query-breadcrumb-value' }, _.escape(description)).el;
elem.appendChild(value);
const clear = $$('span', { className: 'coveo-hidden-query-breadcrumb-clear' }, SVGIcons.icons.mainClear);
value.appendChild(clear.el);
$$(value).on('click', () => this.clear());
args.breadcrumbs.push({
element: elem
});
}
}
private getDescription() {
let description = this.queryStateModel.get(QueryStateModel.attributesEnum.hd);
if (_.isEmpty(description)) {
description = this.queryStateModel.get(QueryStateModel.attributesEnum.hq);
}
if (!_.isEmpty(description)) {
if (description.length > this.options.maximumDescriptionLength) {
description = description.slice(0, this.options.maximumDescriptionLength) + ' ...';
}
}
return description;
}
}
Initialization.registerAutoCreateComponent(HiddenQuery);