Source: components/filter/filter-tree/filter-refine-by/filter-refine-by.js

import jQ from 'jquery';

import BaseComponent from "../../../base-component";
import FilterTreeEnum from "../../../../enum/filter-tree-enum";
import Labels from "../../../../helpers/labels";
import FilterClearButton from '../filter-option-element/filter-clear-button';
import Class from '../../../../helpers/class';
import Globals from '../../../../helpers/globals';
import FilterRefineByItem from './filter-refine-by-item';
import FilterOptionEnum from '../../../../enum/filter-option-enum';
import Selector from "../../../../helpers/selector";

/**
 * The refine by element of the filter.
 * It contains list of refine by items, and a clear all button.
 * @extends BaseComponent
 */
class FilterRefineBy extends BaseComponent {
	/**
	 * Creates a new FilterRefineBy
	 * @param {FilterTreeEnum} filterTreeType - 'vertical' or 'horizontal'
	 */
	constructor(filterTreeType) {
		super();

		/**
		 * List of refine by items
		 * @type {Array}
		 */
		this.refineByItems = [];
		this.clearAllButton = null;

		this.filterTreeType = filterTreeType;
		this.$element = null;
	}

	init() {
		// Check separate refine by display vertical or horizontal
		if (Settings.getSettingValue('general.separateRefineByFromFilter')) {
			if (jQ(Selector.filterRefineByHorizontal).length > 0) {
				this.filterTreeType = FilterTreeEnum.FilterTreeType.HORIZONTAL;
			} else if (jQ(Selector.filterRefineByVertical).length > 0) {
				this.filterTreeType = FilterTreeEnum.FilterTreeType.VERTICAL;
			}
		}

		this.clearAllButton = new FilterClearButton(this.filterTreeType, FilterClearButton.ClearType.CLEAR_ALL);
		this.addComponent(this.clearAllButton);
	}

	/**
	 * Get the refine by's html template.
	 * Depending on its filterTreeType, it returns different templates for 'vertical' and 'horizontal'
	 * @returns {string} Raw html template
	 */
	getTemplate() {
		switch (this.filterTreeType) {
			case FilterTreeEnum.FilterTreeType.VERTICAL:
				return `
					<div class="{{class.filterRefineBy}}">
						<div class="{{class.filterOptionTitle}}">
							<h3><span>{{label}}</span></h3>
							{{clearAllButton}}
						</div>
						<div class="{{class.filterSelectedItems}}">{{refineByItems}}</div>
					</div>
				`;
			case FilterTreeEnum.FilterTreeType.HORIZONTAL:
				return `
					<div class="boost-pfs-filter-pc {{class.filterRefineBy}}">
						<span>{{label}}</span>
						<div class="{{class.filterSelectedItems}}">{{refineByItems}}</div>
						{{clearAllButton}}
					</div>
				`;
			default:
				throw Error('Wrong filterTreeType');		
		}
	}

	compileTemplate() {
		return this.getTemplate()
			.replace(/{{class.filterRefineBy}}/g, Class.filterRefineBy)
			.replace(/{{class.filterOptionTitle}}/g, Class.filterOptionTitle)
			.replace(/{{class.filterSelectedItems}}/g, Class.filterSelectedItems)
			.replace(/{{label}}/g, Labels.refine)
			.replace(/{{refineByItems}}/g, '')
			.replace(/{{clearAllButton}}/g, '');
	}

	render() {
		if (this.refineByItems && this.refineByItems.length > 0) {
			this.$element = jQ(this.compileTemplate());
			this.$refineByItemsContainer = this.$element.find('.' + Class.filterSelectedItems);
			
			this.refineByItems.forEach((refineByItem) => {
				this.$refineByItemsContainer.append(refineByItem.$element);
			})

			this.$clearAllButtonContainer = this.filterTreeType == FilterTreeEnum.FilterTreeType.VERTICAL ?
											this.$element.find('.' + Class.filterOptionTitle) : this.$element;

			this.$clearAllButtonContainer.append(this.clearAllButton.$element);								

		} else {
			this.$element = null;
		}
	}

	/**
	 * Set data for refine by.
	 * It doesn't have input param, because it gets the data from existing filter option.
	 * Call this setData function after you've called setData on filter options.
	 */
	setData() {
		this.refineByItems = [];

		var filterOptionIds = Object.keys(Globals.queryParams).filter(key => key.startsWith(Globals.prefix));
		if (filterOptionIds && filterOptionIds.length > 0) {
			filterOptionIds.forEach((filterOptionId) => {
				var filterOption = this.parent.filterOptions.get(filterOptionId);

				var isCollectionTagFilter = filterOptionId.startsWith(Globals.prefix + '_ct_');
				if (isCollectionTagFilter){
					filterOption = this.parent.filterOptions.get(filterOptionId.replace(Globals.prefix + '_ct_', Globals.prefix + '_c_'));
				}

				var filterItemKeys = Globals.queryParams[filterOptionId];
				var isCollectionFilter = filterOptionId.startsWith(Globals.prefix + '_c_');
				if (isCollectionFilter && !Array.isArray(filterItemKeys)) {
					filterItemKeys = [filterItemKeys];
				}
				if (filterOption && filterItemKeys) {

					var isMultiLevel = filterOption.displayType == FilterOptionEnum.DisplayType.MULTI_LEVEL_COLLECTIONS
						|| filterOption.displayType == FilterOptionEnum.DisplayType.MULTI_LEVEL_TAG;
					var isRangeSlider = filterOption.displayType == FilterOptionEnum.DisplayType.RANGE;

					// Range slider has different refine by (from - to)
					if (isRangeSlider) {
						var refineByItem = new FilterRefineByItem(this.filterTreeType);
						var keyValue = '';
						if (filterOption.isNumberRangeSlider) {
							keyValue = filterItemKeys[0];
						} else {
							keyValue = filterItemKeys;
						}
						refineByItem.setData(filterOption, null, keyValue);
						this.refineByItems.push(refineByItem);
						this.addComponent(refineByItem);

					// Multi level has different refine by
					} else if (isMultiLevel) {

						var isMultiLevelSingle =
							(filterOption.displayType == FilterOptionEnum.DisplayType.MULTI_LEVEL_COLLECTIONS
								&& Settings.getSettingValue('general.multiLevelCollectionSelectType') == FilterOptionEnum.SelectType.SINGLE)
							|| (filterOption.displayType == FilterOptionEnum.DisplayType.MULTI_LEVEL_TAG
								&& filterOption.selectType == FilterOptionEnum.SelectType.SINGLE);

						Object.values(filterItemKeys).forEach(filterItemKey => {
							var combineKey = filterItemKey;
							if (isCollectionTagFilter) {
								combineKey = Globals.collectionId + ':' + filterItemKey;
							}
							var filterItem = filterOption.allNestedFilterItems.get(combineKey);

							// Collection multi level SINGLE only shows the deepest selected level
							if (isMultiLevelSingle && isCollectionFilter && filterItem && filterItem.isSelectedChild) {
								return;
							}

							var refineByItem = new FilterRefineByItem(this.filterTreeType);
							refineByItem.setData(filterOption, filterItem, filterItemKey);
							this.refineByItems.push(refineByItem);
							this.addComponent(refineByItem);
						})
					} else {
						Object.values(filterItemKeys).forEach(filterItemKey => {
							var filterItem = filterOption.filterItems.get(filterItemKey);
							var refineByItem = new FilterRefineByItem(this.filterTreeType);
							refineByItem.setData(filterOption, filterItem, filterItemKey);
							this.refineByItems.push(refineByItem);
							this.addComponent(refineByItem);
						})
					}
				}
			});
		}
	}
}
export default FilterRefineBy;