UNPKG

coveo-search-ui

Version:

Coveo JavaScript Search Framework

198 lines (175 loc) • 6.68 kB
import { IComponentBindings } from '../Base/ComponentBindings'; import { ComponentOptions } from '../Base/ComponentOptions'; import { IQueryResult } from '../../rest/QueryResult'; import { Initialization } from '../Base/Initialization'; import { FieldValue, IFieldValueOptions } from '../FieldValue/FieldValue'; import { StringUtils } from '../../utils/StringUtils'; import { Assert } from '../../misc/Assert'; import { $$ } from '../../utils/Dom'; import * as _ from 'underscore'; import { exportGlobally } from '../../GlobalExports'; export interface IBadgeOptions extends IFieldValueOptions { colors: IBadgeColors; } /** * Badge Colors */ export interface IBadgeColors extends IBadgeColor { values?: { [value: string]: IBadgeColors }; } export interface IBadgeColor { icon?: string; text?: string; } /** * The Badge component outputs a field value with customizable colors and an icon preceding it. * * This component is a result template component (see [Result Templates](https://docs.coveo.com/en/413/)). It * extends the {@link FieldValue} component. Therefore all FieldValue options are also available for a Badge component. */ export class Badge extends FieldValue implements IComponentBindings { static ID = 'Badge'; static doExport = () => { exportGlobally({ Badge: Badge }); }; /** * The options for the component * @componentOptions */ static options: IBadgeOptions = { /** * Specifies the colors for the Badge component. * * You must specify the colors in a JSON format similar to what follows: * ```json * { * "values":{ * "foo":{ * "icon":"blue", * "text":"#222" * }, * "bar":{ * "icon":"green", * "text":"lightgreen" * } * }, * "icon":"red", * "text":"#9ab52b" * } * ``` * This format allows you to customize both the icon and text colors for each field value as well as the default * values. * * Colors can be specified in HTML or hexadecimal format. */ colors: ComponentOptions.buildCustomOption<IBadgeColors>((value: string) => Badge.parseColors(value), { defaultValue: { values: {} } }), textCaption: ComponentOptions.buildLocalizedStringOption() }; static parent = FieldValue; /** * Creates a new Badge component. * @param element The HTMLElement on which to instantiate the component. * @param options The options for the Badge 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(element: HTMLElement, public options: IBadgeOptions, bindings?: IComponentBindings, result?: IQueryResult) { super(element, ComponentOptions.initComponentOptions(element, Badge, options), bindings, result, Badge.ID); if (_.isString(this.options.colors)) { // to support the old string options this.options.colors = Badge.parseColors(<any>this.options.colors); } if (this.options.colors.values == null) { this.options.colors.values = {}; } } // The following regexes are used to match the old color format: // This one matches a single color, e.g. either "red" or "foo: blue". // Its capture groups will be the following : // 0:( 1:() 2:(red)) or 0:( 1:(foo) 2:(blue)) private static colorRegex = /(?:\s*((?:[^:;]|\\[;:])*)\s*:\s*)?(\w+|#[A-Fa-f0-9]{6}|#[A-Fa-f0-9]{3})/g; // This one matches all colors, separated by semicolons, e.g. "red; foo: blue; bar: green". // It wraps 'colorRegex' in other capture groups, such as the following: // 0:(red) 1:(foo: blue;) 2:(bar: green) private static colorsRegex = new RegExp('^(\\s*' + Badge.colorRegex.source + '\\s*;)*(\\s*' + Badge.colorRegex.source + ')?\\s*$'); /** * Parses a {@link Badge.options.colors} option string into a workable JSON format. * * @param colorsOption The colors option string to parse. See {@link Badge.options.colors}. */ public static parseColors(colorsOption: string): IBadgeColors { if (colorsOption) { if (Badge.colorsRegex.test(colorsOption)) { let badgeColors: IBadgeColors = { values: {} }; let colors: string[][] = StringUtils.match(colorsOption, Badge.colorRegex); _.each(colors, (color: string[]) => { let [, fieldValue, colorValue] = color; if (fieldValue != null) { badgeColors.values[fieldValue.replace(/\\(:|;)/g, '$1')] = { icon: colorValue }; } else { badgeColors.icon = colorValue; } }); return badgeColors; } try { return JSON.parse(colorsOption); } catch (e) { Assert.fail(`Invalid colors for badge '${colorsOption}'`); } } return {}; } /** * Gets the icon and text color of a field value. * * @param value The field value whose colors to return. * @returns {{icon: string, text: string}} An object with the `icon` and `text` keys. */ public getColor(value: string = ''): IBadgeColor { var colorKey = _.find(_.keys(this.options.colors.values), (key: string) => value.toLowerCase() == key.toLowerCase()); var color: IBadgeColor = colorKey ? this.options.colors.values[colorKey] : {}; return { icon: color.icon || this.options.colors.icon, text: color.text || this.options.colors.text }; } /** * Renders one string value with the appropriate colors and icon. * * @param value The field value to render. * @returns {HTMLElement} An HTML `<span>` tag containing the rendered value. */ public renderOneValue(value: string): HTMLElement { let valueDom = super.renderOneValue(value); $$(valueDom).addClass('coveo-value'); let color = this.getColor(value); var icon = $$('span', { className: 'coveo-badge-icon' }).el; if (color.icon != null) { icon.style.color = color.icon; } let label = $$('span', { className: 'coveo-badge-label' }, valueDom.innerHTML).el; if (color.text != null) { label.style.color = color.text; } $$(valueDom).empty(); valueDom.appendChild(icon); valueDom.appendChild(label); return valueDom; } // Override the protected method from FieldValue class to ignore a potential textCaption on a Badge. protected prependTextCaptionToDom(): void { return; } } Badge.options = _.omit(Badge.options, 'textCaption'); Initialization.registerAutoCreateComponent(Badge);