coveo-search-ui
Version:
Coveo JavaScript Search Framework
133 lines (118 loc) • 4.08 kB
text/typescript
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));
}
}