coveo-search-ui
Version:
Coveo JavaScript Search Framework
154 lines (139 loc) • 5.58 kB
text/typescript
import { Template, IFieldsToMatch, TemplateRole } from './Template';
import { Utils } from '../../utils/Utils';
import { TemplateConditionEvaluator } from './TemplateConditionEvaluator';
import { IComponentOptionsFieldsOption } from '../Base/IComponentOptions';
import { ComponentOptions } from '../Base/ComponentOptions';
import { $$, Dom } from '../../utils/Dom';
import { Initialization } from '../Base/Initialization';
import { ValidLayout } from '../ResultLayoutSelector/ValidLayout';
import { map, chain, each } from 'underscore';
export interface ITemplateFromStringProperties {
condition?: string;
layout?: ValidLayout;
mobile?: boolean;
tablet?: boolean;
desktop?: boolean;
fieldsToMatch?: IFieldsToMatch[];
role?: TemplateRole;
}
export class TemplateFromAScriptTag {
constructor(public template: Template, public scriptTag: HTMLElement) {
let condition = scriptTag.getAttribute('data-condition');
if (condition != null) {
// Allows to add quotes in data-condition on the templates
condition = condition.toString().replace(/"/g, '"');
template.setConditionWithFallback(condition);
} else {
const parsedFieldsAttributes = this.parseFieldsAttributes();
if (parsedFieldsAttributes && Utils.isNonEmptyArray(parsedFieldsAttributes)) {
this.template.fieldsToMatch = parsedFieldsAttributes;
}
}
this.template.layout = this.parseLayout();
this.template.mobile = this.parseScreenSize('data-mobile');
this.template.tablet = this.parseScreenSize('data-tablet');
this.template.desktop = this.parseScreenSize('data-desktop');
this.template.fields = TemplateConditionEvaluator.getFieldFromString(`${scriptTag.innerHTML} ${condition ? condition : ''}`);
this.template.role = <TemplateRole>scriptTag.getAttribute('data-role');
this.template.addFields(TemplateConditionEvaluator.getFieldFromString(scriptTag.innerHTML + ' ' + condition) || []);
// Additional fields that might be specified directly on the script element
const additionalFields = ComponentOptions.loadFieldsOption(scriptTag, 'fields', <IComponentOptionsFieldsOption>{
includeInResults: true
});
if (additionalFields != null) {
// remove the @
this.template.addFields(map(additionalFields, field => field.substr(1)));
}
// Additional fields that might be used to conditionally load the template when it's going to be rendered.
this.template.addFields(
map(this.template.fieldsToMatch, (toMatch: IFieldsToMatch) => {
return toMatch.field;
})
);
// Scan components in this template
// return the fields needed for the content of this template
const neededFieldsForComponents = chain(this.template.getComponentsInside(scriptTag.innerHTML))
.map((component: string) => {
return Initialization.getRegisteredFieldsComponentForQuery(component);
})
.flatten()
.value();
this.template.addFields(neededFieldsForComponents);
}
toHtmlElement(container?: Dom): HTMLElement {
if (!container) {
container = $$('code');
}
const condition = $$(this.scriptTag).getAttribute('data-condition');
if (condition) {
container.setAttribute('data-condition', condition);
}
container.setHtml(this.scriptTag.innerHTML);
return container.el;
}
parseFieldsAttributes(): IFieldsToMatch[] {
const dataSet = this.scriptTag.dataset;
return chain(dataSet)
.map((value, key: string) => {
const match = key.match(/field([a-zA-Z0-9_\.]*)/i);
if (match) {
let values;
if (value != null && value != 'null' && value != '') {
values = map(value.split(','), val => val.trim());
}
return {
field: match[1].toLowerCase(),
values
};
} else {
return undefined;
}
})
.compact()
.value();
}
parseScreenSize(attribute: string) {
return Utils.parseBooleanIfNotUndefined(this.scriptTag.getAttribute(attribute));
}
parseLayout(): ValidLayout {
const layout = this.scriptTag.getAttribute('data-layout');
return <ValidLayout>layout;
}
static fromString(
template: string,
properties: ITemplateFromStringProperties = {},
container = document.createElement('code')
): HTMLElement {
container.innerHTML = template;
if (properties.condition != null) {
container.setAttribute('data-condition', properties.condition);
}
if (properties.layout != null) {
container.setAttribute('data-layout', properties.layout);
} else {
container.setAttribute('data-layout', 'list');
}
if (properties.mobile != null) {
container.setAttribute('data-mobile', properties.mobile.toString());
}
if (properties.tablet != null) {
container.setAttribute('data-tablet', properties.tablet.toString());
}
if (properties.desktop != null) {
container.setAttribute('data-desktop', properties.desktop.toString());
}
if (properties.fieldsToMatch != null) {
each(properties.fieldsToMatch, (fieldToMatch: IFieldsToMatch) => {
if (fieldToMatch.values) {
container.setAttribute(`data-field-${fieldToMatch.field.toLowerCase()}`, fieldToMatch.values.join(','));
} else {
container.setAttribute(`data-field-${fieldToMatch.field.toLowerCase()}`, null);
}
});
}
if (properties.role != null) {
container.setAttribute('data-role', properties.role);
}
return container;
}
}