import jQ from 'jquery';
import FilterOptionItem from './filter-option-item';
import Class from '../../../../helpers/class';
import Utils from '../../../../helpers/utils';
import FilterApi from "../../../../api/filter-api";
import Globals from "../../../../helpers/globals";
import Navigation from "../../../../helpers/navigation";
import FilterTreeEnum from "../../../../enum/filter-tree-enum";
import FilterOptionEnum from "../../../../enum/filter-option-enum";
import Settings from "../../../../helpers/settings";
/**
* Filter option item for displayType = 'multi_level_collections'
* @extends FilterOptionItem
*/
class FilterOptionItemMultiLevelCollections extends FilterOptionItem {
constructor(filterTreeType) {
super(filterTreeType);
this.$element = null;
this.$itemElement = null;
this.$childContainerElement = null;
}
static getLevelOpenStateData(filterItem) {
var filterOptionId = filterItem.filterOption.filterOptionId;
var collectionId = filterItem.collectionId;
var tagValue = filterItem.tag;
var combineKey = filterOptionId + ":" + collectionId + (tagValue ? (":" + tagValue) : '');
return levelOpenStateData.get(combineKey);
}
static setLevelOpenStateData(filterItem, isOpen) {
var filterOptionId = filterItem.filterOption.filterOptionId;
var collectionId = filterItem.collectionId;
var tagValue = filterItem.tag;
var combineKey = filterOptionId + ":" + collectionId + (tagValue ? (":" + tagValue) : '');
levelOpenStateData.set(combineKey, isOpen);
}
init() {
var selectType = this.filterOption ? this.filterOption.selectType : this.parent.selectType;
this.requestInstantly = this.filterTreeType == FilterTreeEnum.FilterTreeType.VERTICAL
|| selectType == FilterOptionEnum.SelectType.SINGLE
|| Settings.getSettingValue('general.requestInstantly');
}
getTemplate() {
return `
<li class="boost-pfs-filter-option-multi-level-item boost-pfs-filter-option-first-level-item">
<div class="{{class.filterOptionItem}} {{class.filterOptionLabel}}">
<a class="{{class.button}}" data-action="select-filter-item" href="{{href}}">
<span class="boost-pfs-filter-option-value">{{label}}</span>
</a>
{{arrow}}
</div>
<div class="boost-pfs-filter-option-multi-level-list boost-pfs-filter-option-second-level-list">
{{childItems}}
</div>
</li>
`;
}
getArrowTemplate() {
return `
<button class="{{class.button}} {{class.button}}-arrow" data-action="expand-filter-item" aria-label="{{label.ada.toggleMultiLevel}}">
<span class="boost-pfs-arrow"></span>
</button>
`;
}
compileArrowTemplate() {
if (this.level != 3 && this.children && this.children.length > 0) {
return this.getArrowTemplate()
.replace(/{{label.ada.toggleMultiLevel}}/g, Labels.ada.toggleMultiLevel.replace(/{{filterItem}}/g, this.label));
} else {
return '';
}
}
compileTemplate() {
return this.getTemplate()
.replace(/{{class.filterOptionItem}}/g, Class.filterOptionItem)
.replace(/{{class.filterOptionLabel}}/g, Class.filterOptionLabel)
.replace(/{{label}}/g, this.label)
.replace(/{{href}}/g, this.href)
.replace(/{{arrow}}/g, this.compileArrowTemplate())
.replace(/{{class.button}}/g, Class.button)
.replace(/{{childItems}}/g, '');
}
render() {
if (!this.$element) {
this.$element = jQ(this.compileTemplate());
this.$itemElement = this.$element.find('> .' + Class.filterOptionItem);
this.$itemClickElement = this.$itemElement.find('[data-action="select-filter-item"]');
this.$toggleClickElement = this.$itemElement.find('[data-action="expand-filter-item"]');
this.$childContainerElement = this.$element.find('> .boost-pfs-filter-option-multi-level-list');
if (this.$childContainerElement && this.children && this.children.length > 0) {
this.children.forEach(child => {
if (child.$element) {
this.$childContainerElement.append(child.$element);
}
})
}
}
if (this.$itemElement) {
if (this.isSelected || this.isSelectedChild) {
this.$itemElement.addClass('selected');
} else {
this.$itemElement.removeClass('selected');
}
var isOpen = FilterOptionItemMultiLevelCollections.getLevelOpenStateData(this);
var openLevelByDefault = Settings.getSettingValue('general.openMultiLevelByDefault');
if (isOpen
|| (Array.isArray(openLevelByDefault) && openLevelByDefault.includes(this.level))
|| (isOpen == null && this.isSelectedChild)) {
this.$itemElement.addClass('boost-pfs-open');
FilterOptionItemMultiLevelCollections.setLevelOpenStateData(this, true);
} else {
FilterOptionItemMultiLevelCollections.setLevelOpenStateData(this, false);
}
}
}
bindEvents() {
if (this.$itemClickElement) {
this.$itemClickElement.on('click', this.onClick.bind(this));
}
if (this.$toggleClickElement) {
this.$toggleClickElement.on('click', this.onClickToggle.bind(this));
}
}
onClick(event) {
if (event) {
event.preventDefault();
}
this.setCollectionParams();
this.clearAllTagParams();
// Reset the page param
FilterApi.setParam('page', 1);
// Expand the children
if (this.children && this.children.length > 0) {
FilterOptionItemMultiLevelCollections.setLevelOpenStateData(this, true);
}
if (this.requestInstantly) {
FilterApi.applyFilter('collection');
}
}
onClickToggle() {
this.$itemElement.toggleClass('boost-pfs-open');
if (this.$itemElement.hasClass('boost-pfs-open')) {
FilterOptionItemMultiLevelCollections.setLevelOpenStateData(this, true);
} else {
FilterOptionItemMultiLevelCollections.setLevelOpenStateData(this, false);
}
}
isAppliedFilter() {
return Globals.collectionId == this.collectionId;
}
setCollectionParams() {
// Set address bar to know which collection is being selected
// On search page: add param pf_c_collection
if (Utils.isSearchPage()) {
FilterApi.setParam(this.filterOption.filterOptionId, this.collectionId);
// On collection page: change collection path
} else {
Navigation.setAddressBarPathAfterFilter(this.href);
Navigation.setWindowTitleAfterFilter(this.label + ' - ' + Globals.shopName);
// Set new sort order on collection pages
FilterApi.setParam('sort', this.sortOrder);
}
Globals.collectionId = this.collectionId;
FilterApi.setParam('collection_scope', this.collectionId);
}
clearAllTagParams() {
// Clear the pf_ct_collection and collectionTags query
var filterOptionTagId = this.filterOption.filterOptionId.replace(Globals.prefix + '_c', Globals.prefix + '_ct');
FilterApi.setParam(filterOptionTagId, null);
Globals.collectionTags = [];
// Clear all filter option params except collection
var currentFilterOptionIds = [];
Object.keys(Globals.queryParams).forEach(queryParam => {
if (queryParam.startsWith(Globals.prefix) && !queryParam.startsWith(Globals.prefix + '_c')) {
currentFilterOptionIds.push(queryParam);
}
});
currentFilterOptionIds.forEach(filterOptionId => {
FilterApi.setParam(filterOptionId, null);
});
}
setData(data) {
super.setData(data);
this.filterOption = this.parent;
this.level = 1;
this.href = Utils.isSearchPage() ? 'javascript:void(0);' : '/collections/' + this.handle;
this.sortOrder = data.sort_order ? data.sort_order : Globals.defaultSorting;
this.children = [];
if (Array.isArray(data.tags)) {
data.tags.forEach(tagData => {
if (tagData.tag) {
var childItem = new FilterOptionItemSecondLevelCollections(this.filterTreeType);
this.addComponent(childItem);
childItem.setData(tagData);
}
})
}
this.isSelected = this.isAppliedFilter();
this.isSelectedChild = this.children.some(x => x.isSelected || x.isSelectedChild);
this.filterOption.allNestedFilterItems.set(this.collectionId, this);
}
}
/**
* The second level (tag) of the multi level collection.
* This class is not exported.
* @extends FilterOptionItemMultiLevelCollections
*/
class FilterOptionItemSecondLevelCollections extends FilterOptionItemMultiLevelCollections {
getTemplate() {
return `
<div class="boost-pfs-filter-option-multi-level-item boost-pfs-filter-option-second-level-item">
<div class="{{class.filterOptionItem}} {{class.filterOptionLabel}}">
<a class="{{class.button}}" data-action="select-filter-item" href="{{href}}">
<span class="boost-pfs-check-box"></span>
<span class="boost-pfs-filter-option-value">{{label}}</span>
</a>
{{arrow}}
</div>
<div class="boost-pfs-filter-option-multi-level-list boost-pfs-filter-option-third-level-list">
{{childItems}}
</div>
</div>
`;
}
onClick(event) {
if (event) {
event.preventDefault();
}
// If clicking on tag from a different collection, clear all previous tags
if (this.collectionId != Globals.collectionId || Settings.getSettingValue('general.multiLevelCollectionSelectType') == FilterOptionEnum.SelectType.SINGLE) {
this.clearAllTagParams();
}
this.setCollectionParams();
this.setTagParams();
// Reset the page param
FilterApi.setParam('page', 1);
// Expand the children
if (this.children && this.children.length > 0) {
FilterOptionItemMultiLevelCollections.setLevelOpenStateData(this, true);
}
if (this.requestInstantly) {
FilterApi.applyFilter('collection');
}
}
setTagParams() {
// Change address bar to know which tag is being selected
// On search page, or using OR condition for tags: add param pf_ct_collection
if (Utils.isSearchPage() || Settings.getSettingValue('general.multiLevelCollectionSelectType') == FilterOptionEnum.SelectType.MULTIPLE) {
if (!Array.isArray(Globals.collectionTags)) {
Globals.collectionTags = [];
}
var tagIndex = Globals.collectionTags.indexOf(this.tag);
if (tagIndex > -1) {
Globals.collectionTags.splice(tagIndex, 1);
} else {
Globals.collectionTags.push(this.tag);
}
Settings.general.tagMode = '2';
// Set address bar to know which tag is being selected: add pf_ct_collection=tag
var filterOptionTagId = this.filterOption.filterOptionId.replace(Globals.prefix + '_c_', Globals.prefix + '_ct_');
if (Array.isArray(Globals.collectionTags) && Globals.collectionTags.length > 0) {
FilterApi.setParam(filterOptionTagId, Globals.collectionTags);
} else {
FilterApi.setParam(filterOptionTagId, null);
}
// On collection page and using AND condition for tags: use 'collection/tags' path (like shopify link list)
} else {
Globals.collectionTags = this.tag;
Navigation.setAddressBarPathAfterFilter(this.href);
}
}
isAppliedFilter() {
var isIncludeTag = (Array.isArray(Globals.collectionTags) && Globals.collectionTags.includes(this.tag)) || Globals.collectionTags == this.tag;
return Globals.collectionId == this.collectionId && isIncludeTag;
}
setData(data) {
this.tag = data.tag;
this.slugifyTag = Utils.slugify(this.tag);
this.label = data.displayName ? data.displayName : data.tag;
this.filterOption = this.parent.filterOption;
this.requestInstantly = this.parent.requestInstantly;
this.collectionId = this.parent.collectionId;
this.handle = this.parent.handle;
this.level = 2;
this.href = (Utils.isSearchPage() || Settings.getSettingValue('general.multiLevelCollectionSelectType') == FilterOptionEnum.SelectType.MULTIPLE) ?
'javascript:void(0);' : '/collections/' + this.handle + '/' + this.slugifyTag;
this.sortOrder = this.parent.sortOrder ? this.parent.sortOrder : Globals.defaultSorting;
this.children = [];
if (Array.isArray(data.subTags)) {
data.subTags.forEach(tagData => {
if (tagData.tag) {
var childItem = new FilterOptionItemThirdLevelCollections(this.filterTreeType);
this.addComponent(childItem);
childItem.setData(tagData);
}
})
}
// Format the label
this.label = this.buildLabel();
this.isSelected = this.isAppliedFilter();
this.isSelectedChild = this.children.some(x => x.isSelected || x.isSelectedChild);
this.filterOption.allNestedFilterItems.set(this.collectionId + ':' + this.tag, this);
}
}
/**
* The third level (subTag) of the multi level collection.
* This class is not exported.
* @extends FilterOptionItemSecondLevelCollections
*/
class FilterOptionItemThirdLevelCollections extends FilterOptionItemSecondLevelCollections {
getTemplate() {
return `
<div class="boost-pfs-filter-option-multi-level-item boost-pfs-filter-option-third-level-item">
<div class="{{class.filterOptionItem}} {{class.filterOptionLabel}}">
<a class="{{class.button}}" data-action="select-filter-item" href="{{href}}">
<span class="boost-pfs-check-box"></span>
<span class="boost-pfs-filter-option-value">{{label}}</span>
</a>
</div>
</div>
`;
}
setData(data) {
this.tag = data.tag;
this.slugifyTag = Utils.slugify(this.tag);
this.label = data.displayName ? data.displayName : data.tag;
this.filterOption = this.parent.filterOption;
this.requestInstantly = this.parent.requestInstantly;
this.collectionId = this.parent.collectionId;
this.handle = this.parent.handle;
this.level = 3;
this.href = (Utils.isSearchPage() || Settings.getSettingValue('general.multiLevelCollectionSelectType') == FilterOptionEnum.SelectType.MULTIPLE) ?
'javascript:void(0);' : '/collections/' + this.handle + '/' + this.slugifyTag;
this.filterOption.allNestedFilterItems.set(this.collectionId + ':' + this.tag, this);
this.sortOrder = this.parent.sortOrder ? this.parent.sortOrder : Globals.defaultSorting;
// Format the label
this.label = this.buildLabel();
this.isSelected = this.isAppliedFilter();
}
}
var levelOpenStateData = new Map();
export default FilterOptionItemMultiLevelCollections;
export { FilterOptionItemSecondLevelCollections, FilterOptionItemThirdLevelCollections };