UNPKG

coveo-search-ui

Version:

Coveo JavaScript Search Framework

133 lines (118 loc) 4.08 kB
import { IFormWidget, IFormWidgetSettable } from './FormWidgets'; import { $$ } from '../../utils/Dom'; import * as _ from 'underscore'; import { l } from '../../strings/Strings'; import 'styling/vapor/_MultiSelect'; import { Utils } from '../../utils/Utils'; import { exportGlobally } from '../../GlobalExports'; /** * A multi select widget with standard styling. */ export class MultiSelect implements IFormWidget, IFormWidgetSettable { private element: HTMLSelectElement; static doExport() { exportGlobally({ MultiSelect: MultiSelect }); } /** * Creates a new `MultiSelect`. * @param onChange The function to call when the widget selected values change. This function takes the current * `MultiSelect` instance as an argument. * @param options The values which can be selected with the multi select. * @param label The label to display for the multi select. */ constructor( public onChange: (multiSelect: MultiSelect) => void = (multiSelect: MultiSelect) => {}, public options: string[], public label: string ) { this.buildContent(); } /** * Gets the element on which the multi select is bound. * @returns {HTMLSelectElement} The multi select element. */ public build(): HTMLElement { return this.element; } /** * Gets the element on which the multi select is bound. * @returns {HTMLSelectElement} The multi select element. */ public getElement(): HTMLElement { return this.element; } /** * Gets the currently selected values. * @returns {string[]} The array of selected multi select values. */ public getValue(): string[] { return _.chain(<any>this.element.options) .toArray() .filter((opt: HTMLOptionElement) => opt.selected) .map((selected: HTMLOptionElement) => selected.value) .value(); } /** * Gets the currently un-selected values. * @returns {string[]} The array of un-selected multi select values. */ public getUnselectedValues(): string[] { return _.chain(<any>this.element.options) .toArray() .filter((opt: HTMLOptionElement) => !opt.selected) .map((selected: HTMLOptionElement) => selected.value) .value(); } /** * Sets the currently selected values. * @param values The values to select. */ public setValue(values: string[]) { const currentlySelected = this.getValue(); const currentStateSplit = _.partition(_.toArray(this.element.options), (opt: HTMLOptionElement) => _.contains(currentlySelected, opt.value) ); const newStateToApplySplit = _.partition(_.toArray(this.element.options), (opt: HTMLOptionElement) => _.contains(values, opt.value)); _.each(newStateToApplySplit[0], (toSelect: HTMLOptionElement) => (toSelect.selected = true)); _.each(newStateToApplySplit[1], (toUnSelect: HTMLOptionElement) => (toUnSelect.selected = false)); let hasChanged = false; if (!Utils.arrayEqual(currentStateSplit[0], newStateToApplySplit[0], false)) { hasChanged = true; } if (!Utils.arrayEqual(currentStateSplit[1], newStateToApplySplit[1], false)) { hasChanged = true; } if (hasChanged) { $$(this.element).trigger('change'); } } /** * Resets the multi select. */ public reset() { const currentlySelected = this.getValue(); this.element.selectedIndex = -1; if (!Utils.isEmptyArray(currentlySelected)) { $$(this.element).trigger('change'); } } private buildContent() { this.element = <HTMLSelectElement>$$('select', { className: 'coveo-multi-select', multiple: '', size: this.options.length.toString() }).el; const optgroup = $$('optgroup', { className: 'coveo-list-group', label: this.label }); const options = _.map(this.options, opt => { return $$('option', { value: opt, className: 'coveo-list-item' }, l(opt)); }); _.each(options, opt => optgroup.append(opt.el)); this.element.appendChild(optgroup.el); $$(this.element).on('change', () => this.onChange(this)); } }