coveo-search-ui
Version:
Coveo JavaScript Search Framework
208 lines (189 loc) • 8.29 kB
text/typescript
import { Component } from '../Base/Component';
import { IComponentBindings } from '../Base/ComponentBindings';
import { ComponentOptions } from '../Base/ComponentOptions';
import { IFieldConditionOption } from '../Base/IComponentOptions';
import { IQueryResult } from '../../rest/QueryResult';
import { Assert } from '../../misc/Assert';
import { QueryUtils } from '../../utils/QueryUtils';
import { Initialization } from '../Base/Initialization';
import { Utils } from '../../utils/Utils';
import { FileTypes, IFileTypeInfo } from '../Misc/FileTypes';
import { $$ } from '../../utils/Dom';
import { exportGlobally } from '../../GlobalExports';
import { TemplateFieldsEvaluator } from '../Templates/TemplateFieldsEvaluator';
/**
* Available options for the {@link Icon} component.
*/
export interface IIconOptions {
value?: string;
small?: boolean;
withLabel?: boolean;
labelValue?: string;
conditions?: IFieldConditionOption[];
}
/**
* The Icon component outputs the corresponding icon for a given file type. The component searches for a suitable icon
* from those available in the Coveo JavaScript Search Framework. If the component finds no suitable icon, it instead
* outputs a generic icon.
*
* This component is a result template component (see [Result Templates](https://docs.coveo.com/en/413/)).
*/
export class Icon extends Component {
static ID = 'Icon';
static doExport = () => {
exportGlobally({
Icon: Icon
});
};
/**
* The options for the Icon
* @componentOptions
*/
static options: IIconOptions = {
/**
* Specifies the value that the Icon component should output as its CSS class instead of the auto-selected value.
*
* Default value is `undefined`, which means that the Coveo JavaScript Search Framework outputs a suitable icon
* depending on the result file type.
*/
value: ComponentOptions.buildStringOption(),
/**
* Specifies whether the Icon component should output the smaller version of the icon instead of the regular one.
*
* Default value is `undefined`.
*/
small: ComponentOptions.buildBooleanOption(),
/**
* Specifies whether the Icon component should force the output icon to display its caption/label.
*
* **Note:**
*
* > Due to limited screen real estate, setting this option to `true` has no effect on icons used inside Coveo for
* > Salesforce Insight Panels.
*
* Default value is `undefined`, which means that the Coveo JavaScript Search Framework determines whether the icon
* needs to display a caption/label depending on the result file type.
*/
withLabel: ComponentOptions.buildBooleanOption(),
/**
* Specifies what text to display as the icon caption/label.
*
* Default value is `undefined`, which means that the Coveo JavaScript Search Framework determines what text the icon
* needs to display depending on the result file type.
*/
labelValue: ComponentOptions.buildLocalizedStringOption(),
/**
* A field-based condition that must be satisfied by the query result item for the component to be rendered.
*
* Note: This option uses a distinctive markup configuration syntax allowing multiple conditions to be expressed. Its underlying logic is the same as that of the field value conditions mechanism used by result templates.
*
* **Examples:**
* Render the component if the query result item's @documenttype field value is Article or Documentation.
* ```html
* <div class="CoveoIcon" data-field="@author" data-condition-field-documenttype="Article, Documentation"></div>
* ```
*
* Render the component if the query result item's @documenttype field value is anything but Case.
* ```html
* <div class="CoveoIcon" data-field="@author" data-condition-field-not-documenttype="Case"></div>
* ```
* Render the component if the query result item's @documenttype field value is Article, and if its @author field value is anything but Anonymous.
* ```html
* <div class="CoveoIcon" data-field="@author" data-condition-field-documenttype="Article" data-condition-field-not-author="Anonymous"></div>
* ```
* Default value is `undefined`.
*/
conditions: ComponentOptions.buildFieldConditionOption()
};
/**
* Creates a new Icon component.
* @param element The HTMLElement on which to instantiate the component.
* @param options The options for the Icon 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?: IIconOptions, bindings?: IComponentBindings, public result?: IQueryResult) {
super(element, Icon.ID, bindings);
this.options = ComponentOptions.initComponentOptions(element, Icon, options);
this.result = this.result || this.resolveResult();
Assert.exists(this.result);
if (TemplateFieldsEvaluator.evaluateFieldsToMatch(this.options.conditions, this.result)) {
this.initialize(element, bindings);
} else if (this.element.parentElement != null) {
this.element.parentElement.removeChild(this.element);
}
}
private initialize(element: HTMLElement, bindings: IComponentBindings) {
const possibleInternalQuickview = $$(this.element).find('.' + Component.computeCssClassNameForType('Quickview'));
if (!Utils.isNullOrUndefined(possibleInternalQuickview) && QueryUtils.hasHTMLVersion(this.result)) {
$$(this.element).addClass('coveo-with-quickview');
$$(this.element).on('click', () => {
const qv = <any>Component.get(possibleInternalQuickview);
qv.open();
});
}
Icon.createIcon(this.result, this.options, element, bindings);
}
static createIcon(result: IQueryResult, options: IIconOptions = {}, element: HTMLElement = $$('div').el, bindings?: IComponentBindings) {
let info = FileTypes.get(result);
if (!bindings && result.searchInterface) {
// try to resolve results bindings automatically
bindings = result.searchInterface.getBindings();
}
info = Icon.preprocessIconInfo(options, info);
$$(element).toggleClass('coveo-small', options.small === true);
if (options.value != undefined) {
if (options.small === true) {
if (options.value.indexOf('-small') == -1) {
info.icon += '-small';
}
}
if (options.small === false) {
if (options.value.indexOf('-small') != -1) {
info.icon = info.icon.replace('-small', '');
}
}
}
$$(element).addClass(info.icon);
element.setAttribute('title', info.caption);
if (Icon.shouldDisplayLabel(options, bindings)) {
element.appendChild(
$$(
'span',
{
className: 'coveo-icon-caption-overlay'
},
info.caption
).el
);
$$(element).addClass('coveo-icon-with-caption-overlay');
$$(element).setAttribute('data-with-label', 'true');
}
return element;
}
static shouldDisplayLabel(options: IIconOptions, bindings: IComponentBindings) {
// If withLabel is explicitely set to false, the label will never display
// If withLabel is explicitely set to true, the label will always display
// If withLabel is set to default value (not a hard true or false), the label will display based on ./core/filetypes/**.json
// with the property shouldDisplayLabel set on each file type/ objecttype
// In this case, the generated css will take care of outputting the correct css to display : block
return options.withLabel !== false;
}
static preprocessIconInfo(options: IIconOptions, info: IFileTypeInfo) {
if (options.labelValue != null) {
info.caption = options.labelValue;
}
if (options.value != null) {
info.icon = 'coveo-icon ' + options.value;
}
if (info.caption == null) {
info.caption = '';
}
if (info.icon == null) {
info.icon = 'coveo-icon coveo-sprites-custom';
}
return info;
}
}
Initialization.registerAutoCreateComponent(Icon);