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