UNPKG

coveo-search-ui

Version:

Coveo JavaScript Search Framework

156 lines (144 loc) 5.57 kB
import { each } from 'underscore'; import { exportGlobally } from '../../GlobalExports'; import { Assert } from '../../misc/Assert'; import { IQueryResult } from '../../rest/QueryResult'; import { $$ } from '../../utils/Dom'; import { Component } from '../Base/Component'; import { IComponentBindings } from '../Base/ComponentBindings'; import { ComponentOptions } from '../Base/ComponentOptions'; import { IInitializationParameters, Initialization } from '../Base/Initialization'; import { TemplateComponentOptions } from '../Base/TemplateComponentOptions'; import { Template } from '../Templates/Template'; export interface ITemplateLoaderOptions { template: Template; condition?: String; } /** * The TemplateLoader component can load one result template into another. You should normally declare any reusable * result template outside of the {@link ResultList} component. Otherwise, the framework will evaluate the * `data-condition` of the reusable result template and possibly render it. * * **Example:** * * ```html * [ ... ] * * <!-- A reusable result template. Note that it is important to declare it outside of the ResultList component. --> * <script type='text/underscore' class='result-template' id='ReusableTemplate'> * <table class='CoveoFieldTable'> * <tr data-field='@source' data-caption='Source'></tr> * <tr data-field='@percentScore' data-caption='Score'></tr> * </table> * </script> * * [ ... ] * * <div class="CoveoResultList" data-wait-animation="fade" data-auto-select-fields-to-include="true"> * * <!-- A custom result template for Lithium messages. --> * <script type='text/underscore' class='result-template' data-condition='raw.filetype == "lithiummessage"'> * <div> * <img class='CoveoIcon' data-small='true'> * <a class='CoveoResultLink'></a> * <div class='CoveoTemplateLoader' data-template-id='ReusableTemplate'></div> * </div> * </script> * * <!-- A custom result template for images. --> * <script type='text/underscore' class='result-template' data-condition='raw.filetype == "Image"'> * <div> * <img class='CoveoIcon' data-small='true'></img> * <a class='CoveoResultLink'> * <img class='CoveoThumbnail'> * </a> * <div class='CoveoTemplateLoader' data-template-id='ReusableTemplate'></div> * </div> * </script> * </div> * * [ ... ] * ``` * * See [Result Templates](https://docs.coveo.com/en/413/). */ export class TemplateLoader extends Component { static ID = 'TemplateLoader'; static doExport = () => { exportGlobally({ TemplateLoader: TemplateLoader }); }; /** * The possible options for a TemplateLoader. * @componentOptions */ static options: ITemplateLoaderOptions = { /** * Specifies how to find the template. This can be either a CSS selector or an HTML `id` attribute. * * **Examples:** * * - With a CSS selector: `data-template-selector='.MySelector'` * - With an HTML `id`: `data-template-id='MyId'` */ template: TemplateComponentOptions.buildTemplateOption(), /** * Specifies the boolean condition that the result must satisfy in order for the template to load. * * **Example:** * * `data-condition='percentScore > 80'` */ condition: ComponentOptions.buildStringOption() }; /** * Creates a new TemplateLoader. * @param element The HTMLElement on which to instantiate the component. * @param options The options for the TemplateLoader 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 result to associate the component with. */ constructor( public element: HTMLElement, public options?: ITemplateLoaderOptions, public bindings?: IComponentBindings, public result?: IQueryResult ) { super(element, TemplateLoader.ID, bindings); this.options = ComponentOptions.initComponentOptions(element, TemplateLoader, options); this.result = this.result || this.resolveResult(); Assert.exists(this.result); if (this.options.condition != null) { var conditionFunction = new Function('obj', 'with(obj||{}){return ' + this.options.condition + '}'); if (conditionFunction(this.result)) { this.initialize(); } } else { this.initialize(); } } private initialize() { if (this.options.template != null) { var initOptions = this.searchInterface.options; var initParameters: IInitializationParameters = { options: initOptions, bindings: this.bindings, result: this.result }; var parents = $$(this.element).parents(Component.computeCssClassName(TemplateLoader)); each(parents, (parent: HTMLElement) => { let clone = <HTMLElement>parent.cloneNode(); $$(clone).empty(); let outerHTMLParent = clone.outerHTML; Assert.check(outerHTMLParent.indexOf(this.element.outerHTML) === -1, 'TemplateLoader cannot load a template into itself.'); }); this.element.innerHTML = this.options.template.instantiateToString(this.result, { checkCondition: false, responsiveComponents: this.bindings ? this.bindings.searchInterface.responsiveComponents : null }); Initialization.automaticallyCreateComponentsInside(this.element, initParameters); } } } Initialization.registerAutoCreateComponent(TemplateLoader);