import jQ from 'jquery';
import Utils from '../helpers/utils';
import Globals from '../helpers/globals';
import Settings from '../helpers/settings';
import FilterApi from '../api/filter-api';
import BoostPFS from '../boost-pfs';
/**
* The current history state object
* @type {Object}
*/
var historyState = {};
var defaultParamValues = {};
var newAddressBarPath = window.location.pathname;
var newWindowTitle = document.title;
var currentUrl = "";
var shortParamsMap = new Map();
var longParamMap = new Map();
/**
* Init history state with default values.
* Bind to 'popstate' event to reinit the history
*/
const init = () => {
currentUrl = Utils.getWindowLocation().href;
defaultParamValues = {
page: 1,
limit: Settings.getSettingValue('general.limit'),
sort: Utils.isSearchPage() ? 'relevance' : Globals.defaultSorting,
display: Settings.getSettingValue('general.defaultDisplay'),
tab: Settings.getSettingValue('general.searchPanelDefault'),
}
// Bind back button event
jQ(window).on('popstate', Navigation.onPopState);
// Init shortParamsMap and longParamMap
Navigation.initShortenUrl();
}
/**
* On back button
*/
const onPopState = (event) => {
historyState = event.originalEvent.state;
var boostPFSFilterInstance = BoostPFS.instance.filter;
// Hash change also fires popstate event, so we need to check for hashchange, and return without re-init filter
var url = Utils.getWindowLocation().href;
var isHashChange = (url.includes('#') || currentUrl.includes('#')) && url.split('#')[0] == currentUrl;
if (!boostPFSFilterInstance || isHashChange) return;
// Trigger click on tab Product in Search Page Display
if (Utils.isSearchPage() && jQ('.' + Class.searchResultPanelItem).length > 0) {
jQ('.' + Class.searchResultPanelItem).first().trigger('click');
}
// Re-init filter
boostPFSFilterInstance.filterLoadingIcon.setShow(true);
FilterApi.updateParamsFromUrl();
FilterApi.getFilterData('history', boostPFSFilterInstance.setData.bind(boostPFSFilterInstance));
}
/**
* Init mapping for shorten URL params
*/
const initShortenUrl = () => {
// Check settings
var shortParamSettings = Settings.getSettingValue('general.shortenUrlParamList');
if (Settings.getSettingValue('general.isShortenUrlParam') && Array.isArray(shortParamSettings)) {
shortParamSettings.forEach(paramSetting => {
if (typeof paramSetting == 'string') {
// 'paramSetting' has the format 'filter_option_id:short_id', for example: 'pf_opt_color:color'.
var splitParams = paramSetting.split(':');
if (splitParams.length == 2) {
var filterOptionParam = splitParams[0].trim();
var shortFilterOptionParam = splitParams[1].trim();
if (filterOptionParam && shortFilterOptionParam) {
shortParamsMap.set(filterOptionParam, shortFilterOptionParam);
longParamMap.set(shortFilterOptionParam, filterOptionParam);
}
}
}
})
}
}
/**
* Update the address bar using Globals.queryParams object
* Push new state to history
*/
const updateAddressBar = () => {
if (Settings.getSettingValue('general.urlScheme') == 0 || !window.history || typeof window.history.pushState != 'function') return;
var newUrl = buildAddressBarUrl();
// Remove functions from query params
var cleanQueryParams = JSON.parse(JSON.stringify(Globals.queryParams));
Globals.queryParams = cleanQueryParams;
// Save to history
history.pushState({
param: Globals.queryParams
}, newWindowTitle, newUrl);
currentUrl = newUrl;
const event = new Event('boost-pfs-change-address-bar');
window.dispatchEvent(event);
}
/**
* Build address bar URL from Globals.queryParams object.
* @returns {string} - New URL
*/
const buildAddressBarUrl = () => {
var queryParams = Globals.queryParams;
var urlPath = window.location.protocol + "//" + window.location.hostname + newAddressBarPath;
var urlQueryString = Utils.getWindowLocation().search;
var urlSearchParams = new URLSearchParams(urlQueryString);
var hasFilterOptionParam = false;
var urlScheme = Settings.getSettingValue('general.urlScheme');
// Add & update param values
Object.keys(queryParams).forEach(key => {
var value = queryParams[key];
// Filter params
if (key.startsWith(Globals.prefix)) {
// Get the short url param key
var shortKey = shortParamsMap.get(key);
if (!shortKey) shortKey = key;
urlSearchParams.delete(shortKey);
if (Array.isArray(value)) {
// Build urlSearchParams by urlScheme
switch (urlScheme) {
case 0:
// Don't build filter params
break;
case 2:
// Example: color=red,blue
urlSearchParams.set(shortKey, value);
break;
case 1:
default:
// Example: color=red&color=blue
value.forEach((singleValue) => {
urlSearchParams.append(shortKey, singleValue);
})
break;
}
hasFilterOptionParam = true;
} else if (typeof value !== 'undefined' && value !== null) {
urlSearchParams.set(shortKey, value);
hasFilterOptionParam = true;
}
// Search query param
} else if (key == Globals.searchTermKey && typeof value == 'string') {
urlSearchParams.set(key, value);
// Other params: page, limit, display, sort: remove these params if they're at default value
} else if (Globals.otherParams.includes(key)) {
if (value == defaultParamValues[key]) {
urlSearchParams.delete(key);
} else {
urlSearchParams.set(key, value);
}
}
});
// Remove non-existing params values
var keysToBeRemoved = []
for (var key of urlSearchParams.keys()) {
var longKey = longParamMap.get(key);
if (!longKey) longKey = key;
if (longKey.startsWith(Globals.prefix) || Globals.imutableFilterTree.includes(longKey) || longKey == Globals.searchTermKey) {
if (!queryParams.hasOwnProperty(longKey)) {
keysToBeRemoved.push(key);
}
}
}
keysToBeRemoved.forEach(key => {
urlSearchParams.delete(key);
})
Globals.hasFilterOptionParam = hasFilterOptionParam;
// Uncomment to add "_=pf" param
// Globals.hasFilterOptionParam = hasFilterOptionParam;
// if (hasFilterOptionParam) {
// urlSearchParams.set('_', Globals.prefix);
// } else {
// urlSearchParams.delete('_');
// }
var url = urlPath;
var queryString = urlSearchParams.toString();
if (queryString) {
if (urlScheme == 2) {
queryString = queryString.replace(/%2C/g,",");
}
url += ('?' + queryString);
}
return url;
}
/**
* Set the new address bar path (when changing collections/tags)
* after filtering
* @param {string} path
*/
const setAddressBarPathAfterFilter = (path) => {
if (typeof path == 'string' && path.startsWith('/')) {
newAddressBarPath = path;
} else {
newAddressBarPath = window.location.pathname;
}
}
/**
* Set the new window title (when changing collections/tags/pages)
* after filtering
* @param {string} title
*/
const setWindowTitleAfterFilter = (title) => {
if (typeof title == 'string' && title != '' && !title.includes('undefined') && !title.includes('null')) {
newWindowTitle = title;
} else {
newWindowTitle = document.title;
}
}
const getHistoryState = () => {
return historyState;
}
const Navigation = {
init: init,
initShortenUrl: initShortenUrl,
updateAddressBar: updateAddressBar,
buildAddressBarUrl: buildAddressBarUrl,
setAddressBarPathAfterFilter: setAddressBarPathAfterFilter,
setWindowTitleAfterFilter: setWindowTitleAfterFilter,
getHistoryState: getHistoryState,
onPopState: onPopState,
shortParamsMap: shortParamsMap,
longParamMap: longParamMap
}
export default Navigation;