coveo-search-ui
Version:
Coveo JavaScript Search Framework
188 lines (169 loc) • 7.4 kB
text/typescript
import { Template } from '../Templates/Template';
import { Component } from '../Base/Component';
import { IComponentBindings } from '../Base/ComponentBindings';
import { ComponentOptions } from '../Base/ComponentOptions';
import { DefaultResultAttachmentTemplate } from './DefaultResultAttachmentTemplate';
import { IQueryResult } from '../../rest/QueryResult';
import { Utils } from '../../utils/Utils';
import { QueryUtils } from '../../utils/QueryUtils';
import { Initialization, IInitializationParameters } from '../Base/Initialization';
import { Assert } from '../../misc/Assert';
import { $$ } from '../../utils/Dom';
import * as _ from 'underscore';
import { exportGlobally } from '../../GlobalExports';
import 'styling/_ResultAttachments';
import { TemplateComponentOptions } from '../Base/TemplateComponentOptions';
export interface IResultAttachmentsOptions {
resultTemplate?: Template;
subResultTemplate?: Template;
maximumAttachmentLevel?: number;
}
/**
* The `ResultAttachments` component renders attachments in a result set, for example when displaying emails. This
* component is usable inside a result template when there is an active [`Folding`]{@link Folding} component in the
* page.
*
* This component is a result template component (see [Result Templates](https://docs.coveo.com/en/413/)).
* @notSupportedIn salesforcefree
*/
export class ResultAttachments extends Component {
static ID = 'ResultAttachments';
static doExport = () => {
exportGlobally({
ResultAttachments: ResultAttachments,
DefaultResultAttachmentTemplate: DefaultResultAttachmentTemplate
});
};
/**
* The options for the component
* @componentOptions
*/
static options: IResultAttachmentsOptions = {
/**
* Specifies the template to use to render each attachment for a top result.
*
* You can specify a previously registered template to use either by referring to its HTML `id` attribute or to a
* CSS selector (see {@link TemplateCache}).
*
* **Examples:**
*
* Specifying a previously registered template by referring to its HTML `id` attribute:
*
* ```html
* <div class="CoveoResultAttachments" data-result-template-id="Foo"></div>
* ```
*
* Specifying a previously registered template by referring to a CSS selector:
*
* ```html
* <div class='CoveoResultAttachments' data-result-template-selector=".Foo"></div>
* ```
*
* If you do not specify a custom folding template, the component uses the default result attachment template.
*/
resultTemplate: TemplateComponentOptions.buildTemplateOption({
defaultFunction: e => new DefaultResultAttachmentTemplate()
}),
/**
* Specifies the template to use to render sub-attachments, which are attachments within attachments, for example
* when multiple files are embedded within a `.zip` attachment.
*
* Sub-attachments can themselves contain sub-attachments, and so on up to a certain level (see the
* [`maximumAttachmentLevel`]{@link ResultAttachments.options.maximumAttachmentLevel} option).
*
* You can specify a previously registered template to use either by referring to its HTML `id` attribute or to a
* CSS selector (see {@link TemplateCache}).
*
* **Example:**
*
* Specifying a previously registered template by referring to its HTML `id` attribute:
*
* ```html
* <div class="CoveoResultAttachments" data-sub-result-template-id="Foo"></div>
* ```
*
* Specifying a previously registered template by referring to a CSS selector:
*
* ```html
* <div class="CoveoResultAttachments" data-sub-result-template-selector=".Foo"></div>
* ```
*
* By default, this option uses the same template you specify for the
* [`resultTemplate`]{@link ResultAttachments.options.resultTemplate} option.
*/
subResultTemplate: TemplateComponentOptions.buildTemplateOption({
postProcessing: (value: Template, options: IResultAttachmentsOptions) => (value != null ? value : options.resultTemplate)
}),
/**
* Specifies the maximum nesting depth. Beyond this depth, the component stops rendering sub-attachments.
*
* Default value is `5`. Minimum value is `0`.
*/
maximumAttachmentLevel: ComponentOptions.buildNumberOption({ defaultValue: 5, min: 0 })
};
private attachments: IQueryResult[];
/**
* Creates a new `ResultAttachments` component.
* @param element The HTMLElement on which to instantiate the component.
* @param options The options for the `ResultAttachments` 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.
* @param attachmentLevel The nesting depth.
*/
constructor(
public element: HTMLElement,
public options?: IResultAttachmentsOptions,
public bindings?: IComponentBindings,
result?: IQueryResult,
public attachmentLevel = 0
) {
super(element, ResultAttachments.ID, bindings);
this.options = ComponentOptions.initComponentOptions(element, ResultAttachments, options);
this.attachments = result.attachments;
if (Utils.isNonEmptyArray(this.attachments)) {
this.renderAttachments();
}
}
private renderAttachments() {
_.each(this.attachments, attachment => {
QueryUtils.setStateObjectOnQueryResult(this.queryStateModel.get(), attachment);
QueryUtils.setSearchInterfaceObjectOnQueryResult(this.searchInterface, attachment);
let subTemplatePromise =
this.attachmentLevel > 0
? this.options.subResultTemplate.instantiateToElement(attachment)
: this.options.resultTemplate.instantiateToElement(attachment);
subTemplatePromise.then((container: HTMLElement) => {
this.autoCreateComponentsInsideResult(container, _.extend({}, attachment, { attachments: [] }));
$$(container).addClass('coveo-result-attachments-container');
this.element.appendChild(container);
if (this.attachmentHasSubAttachment(attachment) && this.attachmentLevel < this.options.maximumAttachmentLevel) {
var childAttachmentContainer = $$('div').el;
container.appendChild(childAttachmentContainer);
new ResultAttachments(childAttachmentContainer, this.options, this.bindings, attachment, this.attachmentLevel + 1);
}
});
});
}
private attachmentHasSubAttachment(attachment: IQueryResult) {
if (Utils.isNonEmptyArray(attachment.attachments)) {
return true;
} else if (Utils.isNonEmptyArray(attachment.childResults)) {
attachment.attachments = attachment.childResults;
return true;
} else {
return false;
}
}
private autoCreateComponentsInsideResult(element: HTMLElement, result: IQueryResult) {
Assert.exists(element);
var initOptions = this.searchInterface.options;
var initParameters: IInitializationParameters = {
options: initOptions,
bindings: this.getBindings(),
result: result
};
Initialization.automaticallyCreateComponentsInside(element, initParameters, [ResultAttachments.ID]);
}
}
Initialization.registerAutoCreateComponent(ResultAttachments);