UNPKG

coveo-search-ui

Version:

Coveo JavaScript Search Framework

257 lines (213 loc) • 8.54 kB
import 'styling/DynamicHierarchicalFacet/_DynamicHierarchicalFacetValues'; import { IFacetResponse, IFacetResponseValue } from '../../../rest/Facet/FacetResponse'; import { DynamicHierarchicalFacetValue } from './DynamicHierarchicalFacetValue'; import { FacetUtils } from '../../Facet/FacetUtils'; import { $$ } from '../../../utils/Dom'; import { find } from 'underscore'; import { FacetValueState } from '../../../rest/Facet/FacetValueState'; import { Utils } from '../../../utils/Utils'; import { l } from '../../../strings/Strings'; import { DynamicFacetValueShowMoreLessButton } from '../../DynamicFacet/DynamicFacetValues/DynamicFacetValueMoreLessButton'; import { IDynamicHierarchicalFacetValues, IDynamicHierarchicalFacet, IDynamicHierarchicalFacetValue } from '../IDynamicHierarchicalFacet'; import { SVGIcons } from '../../../utils/SVGIcons'; import { HashUtils } from '../../../utils/HashUtils'; import { getDynamicFacetHeaderId } from '../../DynamicFacet/DynamicFacetHeader/DynamicFacetHeader'; export class DynamicHierarchicalFacetValues implements IDynamicHierarchicalFacetValues { private facetValues: IDynamicHierarchicalFacetValue[] = []; private _selectedPath: string[] = []; private list = $$('ul', { className: 'coveo-dynamic-hierarchical-facet-values', 'aria-labelledby': getDynamicFacetHeaderId(this.facet.options.id), role: 'group' }).el; constructor(private facet: IDynamicHierarchicalFacet) {} private formatDisplayValue(value: string) { let returnValue = FacetUtils.tryToGetTranslatedCaption(<string>this.facet.options.field, value); return this.facet.options.valueCaption[value] || returnValue; } public createFromResponse(response: IFacetResponse) { this.clearPath(); this.facetValues = response.values.map(responseValue => this.createFacetValueFromResponse(responseValue)); } public reorderValues(pathsOrder: string[][]) { const order = pathsOrder.map(path => HashUtils.encodeArray(path)); if (!this.hasSelectedValue) { this.facetValues = Utils.reorderValuesByKeys(this.facetValues, order, value => HashUtils.encodeArray(value.path)); } else { const parentFacetValue = this.findValueWithPath(this.selectedPath); parentFacetValue.children = Utils.reorderValuesByKeys(parentFacetValue.children, order, value => HashUtils.encodeArray(value.path)); } } private createFacetValueFromResponse(responseValue: IFacetResponseValue, path: string[] = []): IDynamicHierarchicalFacetValue { const newPath = [...path, responseValue.value]; const displayValue = FacetUtils.getDisplayValueFromValueCaption( responseValue.value, this.facet.options.field as string, this.facet.options.valueCaption ); const children = responseValue.children ? responseValue.children.map(responseValue => this.createFacetValueFromResponse(responseValue, newPath)) : []; if (responseValue.state === FacetValueState.selected) { this._selectedPath = newPath; } return new DynamicHierarchicalFacetValue( { value: responseValue.value, numberOfResults: responseValue.numberOfResults, state: responseValue.state, moreValuesAvailable: responseValue.moreValuesAvailable, path: newPath, isLeafValue: responseValue.isLeafValue, displayValue, children }, this.facet ); } public get allFacetValues() { return this.facetValues; } public get hasSelectedValue() { return !!this._selectedPath.length; } public get selectedPath() { return [...this._selectedPath]; } public resetValues() { this.facetValues = []; this.clearPath(); } public clearPath() { this._selectedPath = []; } private findValueWithPath(path: string[]) { let facetValues = this.facetValues; let facetValue: IDynamicHierarchicalFacetValue; let remainingPath = [...path]; do { const value = remainingPath.shift(); facetValue = find(facetValues, facetValue => facetValue.value === value); if (!facetValue) { return null; } facetValues = facetValue.children; } while (remainingPath.length); return facetValue; } private createFacetValueWithPath(path: string[], children: IDynamicHierarchicalFacetValue[] = []): IDynamicHierarchicalFacetValue { const value = path[path.length - 1]; return new DynamicHierarchicalFacetValue( { value, path, displayValue: this.formatDisplayValue(value), numberOfResults: 0, state: FacetValueState.idle, isLeafValue: !children.length, moreValuesAvailable: false, children }, this.facet ); } private getOrCreateFacetValueWithPath(path: string[]) { const existingFacetValue = this.findValueWithPath(path); if (existingFacetValue) { return existingFacetValue; } const newFacetValue = this.createFacetValueWithPath(path); const siblingValues = path.length === 1 ? this.facetValues : this.getOrCreateFacetValueWithPath(path.slice(0, -1)).children; siblingValues.push(newFacetValue); return newFacetValue; } private filterHierarchyAtPathLevel(facetValues: IDynamicHierarchicalFacetValue[], path: string[], level = 1) { const filteredFacetValues = facetValues.filter(facetValue => { const targetPath = path.slice(0, level); return Utils.arrayEqual(targetPath, facetValue.path); }); filteredFacetValues.forEach(facetValue => { facetValue.state = FacetValueState.idle; facetValue.children = this.filterHierarchyAtPathLevel(facetValue.children, path, level + 1); }); return filteredFacetValues; } private filterHierarchyWithPath(path: string[]) { this.facetValues = this.filterHierarchyAtPathLevel(this.facetValues, path); } public selectPath(path: string[]) { this.filterHierarchyWithPath(path); this.getOrCreateFacetValueWithPath(path).select(); this._selectedPath = [...path]; } private prependAllCategories() { const clearButton = $$( 'button', { className: 'coveo-dynamic-hierarchical-facet-all', type: 'button', title: this.facet.options.clearLabel }, this.facet.options.clearLabel ); clearButton.toggleClass('coveo-show-when-collapsed', this.facet.values.selectedPath.length === 1); const arrowIcon = $$('div', { className: 'coveo-dynamic-hierarchical-facet-value-arrow-left' }, SVGIcons.icons.arrowDown); clearButton.prepend(arrowIcon.el); const clear = $$('li', { role: 'none' }, clearButton); clear.on('click', () => this.facet.header.options.clear()); $$(this.list).prepend(clear.el); } private buildShowLess() { const showLess = new DynamicFacetValueShowMoreLessButton({ className: 'coveo-dynamic-hierarchical-facet-show-less', ariaLabel: l('ShowLessFacetResults', this.facet.options.title), label: l('ShowLess'), action: () => { this.facet.enableFreezeFacetOrderFlag(); this.facet.showLessValues(); } }); return showLess.element; } private buildShowMore() { const showMore = new DynamicFacetValueShowMoreLessButton({ className: 'coveo-dynamic-hierarchical-facet-show-more', ariaLabel: l('ShowMoreFacetResults', this.facet.options.title), label: l('ShowMore'), action: () => { this.facet.enableFreezeFacetOrderFlag(); this.facet.showMoreValues(); } }); return showMore.element; } private get shouldEnableShowLess() { return this.facetValues.length > this.facet.options.numberOfValues; } private get shouldEnableShowMore() { return this.facet.moreValuesAvailable && !this.hasSelectedValue; } private appendShowMoreLess(fragment: DocumentFragment) { if (!this.facet.options.enableMoreLess) { return; } if (this.shouldEnableShowLess) { fragment.appendChild(this.buildShowLess()); } if (this.shouldEnableShowMore) { fragment.appendChild(this.buildShowMore()); } } public render() { const fragment = document.createDocumentFragment(); $$(this.list).empty(); this.facetValues.forEach(facetValue => { facetValue.render(fragment); }); $$(this.list).toggleClass('coveo-with-space', !!this._selectedPath.length); this._selectedPath.length && this.prependAllCategories(); this.appendShowMoreLess(fragment); this.list.appendChild(fragment); return this.list; } }