coveo-search-ui
Version:
Coveo JavaScript Search Framework
167 lines (136 loc) • 5.92 kB
text/typescript
import { IQuickviewLoadedEventArgs, QuickviewEvents } from '../../events/QuickviewEvents';
import { IOpenQuickviewEventArgs } from '../../events/ResultListEvents';
import { Assert } from '../../misc/Assert';
import { IQuery } from '../../rest/Query';
import { IQueryResult } from '../../rest/QueryResult';
import { IViewAsHtmlOptions } from '../../rest/SearchEndpointInterface';
import { $$ } from '../../utils/Dom';
import { Utils } from '../../utils/Utils';
import { Component } from '../Base/Component';
import { IComponentBindings } from '../Base/ComponentBindings';
import { ComponentOptions } from '../Base/ComponentOptions';
import { Initialization } from '../Base/Initialization';
import { QuickviewDocumentIframe } from './QuickviewDocumentIframe';
import { QuickviewDocumentHeader } from './QuickviewDocumentHeader';
import { QuickviewDocumentWords } from './QuickviewDocumentWords';
import { each, keys } from 'underscore';
import { QuickviewDocumentWordButton } from './QuickviewDocumentWordButton';
import { QuickviewDocumentPreviewBar } from './QuickviewDocumentPreviewBar';
export const HIGHLIGHT_PREFIX = 'CoveoHighlight';
export interface IQuickviewDocumentOptions {
maximumDocumentSize?: number;
}
/**
* The `QuickviewDocument` component normally exists within a [`Quickview`]{@link Quickview} component. The sole purpose
* of this component is to add an `<iframe>` which loads the correct HTML version of the current item.
*
* The default [`contentTemplate`]{@link Quickview.options.contentTemplate} of the
* `Quickview` component includes the `QuickviewDocument` component.
*
* This component is a result template component (see [Result Templates](https://docs.coveo.com/en/413/)).
*/
export class QuickviewDocument extends Component {
static ID = 'QuickviewDocument';
/**
* The options for the component
* @componentOptions
*/
static options: IQuickviewDocumentOptions = {
/**
* Specifies the maximum preview size that the index should return.
*
* Default value is `0`, and the index returns the entire preview. Minimum value is `0`.
*/
maximumDocumentSize: ComponentOptions.buildNumberOption({ defaultValue: 0, min: 0 })
};
private iframe: QuickviewDocumentIframe;
private header: QuickviewDocumentHeader;
/**
* Creates a new `QuickviewDocument` component.
* @param element The HTMLElement on which to instantiate the component.
* @param options The options for the `QuickviewDocument` 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).
* @param result The current result.
*/
constructor(
public element: HTMLElement,
public options?: IQuickviewDocumentOptions,
bindings?: IComponentBindings,
public result?: IQueryResult
) {
super(element, QuickviewDocument.ID, bindings);
this.options = ComponentOptions.initComponentOptions(element, QuickviewDocument, options);
this.result = result || this.resolveResult();
Assert.exists(this.result);
}
public createDom() {
const container = $$('div', {
className: 'coveo-quickview-document'
});
this.element.appendChild(container.el);
this.header = new QuickviewDocumentHeader();
this.iframe = new QuickviewDocumentIframe();
container.append(this.header.el);
container.append(this.iframe.el);
}
public async open() {
this.ensureDom();
const beforeLoad = new Date().getTime();
const termsToHighlight = this.initialTermsToHighlight;
this.triggerOpenQuickViewEvent({ termsToHighlight });
const termsWereModified = this.wereTermsToHighlightModified(termsToHighlight);
if (termsWereModified) {
this.handleTermsToHighlight(termsToHighlight, this.query);
}
try {
const documentHTML = await this.queryController.getEndpoint().getDocumentHtml(this.result.uniqueId, {
queryObject: this.query,
requestedOutputSize: this.options.maximumDocumentSize
} as IViewAsHtmlOptions);
await this.iframe.render(documentHTML, this.result.title);
const documentWords = new QuickviewDocumentWords(this.iframe, this.result);
const previewBar = new QuickviewDocumentPreviewBar(this.iframe, documentWords);
each(documentWords.words, word => {
const button = new QuickviewDocumentWordButton(word, previewBar, this.iframe);
this.header.addWord(button);
});
const afterLoad = new Date().getTime();
this.triggerQuickviewLoaded(afterLoad - beforeLoad);
} catch (error) {
await this.iframe.renderError(error);
const afterLoad = new Date().getTime();
this.triggerQuickviewLoaded(afterLoad - beforeLoad);
}
}
private get initialTermsToHighlight() {
return keys(this.result.termsToHighlight);
}
private triggerOpenQuickViewEvent(args: IOpenQuickviewEventArgs) {
$$(this.root).trigger(QuickviewEvents.openQuickview, args);
}
private get query() {
return { ...this.queryController.getLastQuery() };
}
private triggerQuickviewLoaded(duration: number) {
$$(this.element).trigger(QuickviewEvents.quickviewLoaded, {
duration
} as IQuickviewLoadedEventArgs);
}
private handleTermsToHighlight(termsToHighlight: string[], queryObject: IQuery) {
for (const term in this.result.termsToHighlight) {
delete this.result.termsToHighlight[term];
}
let query = '';
each(termsToHighlight, term => {
query += term + ' ';
this.result.termsToHighlight[term] = [term];
});
query = query.substring(0, query.length - 1);
queryObject.q = query;
}
private wereTermsToHighlightModified(termsToHighlight: string[]) {
return !Utils.arrayEqual(termsToHighlight, this.initialTermsToHighlight);
}
}
Initialization.registerAutoCreateComponent(QuickviewDocument);