"use strict"; class Hist { static hashChange ({isForceLoad, isBlankFilterLoad = false} = {}) { if (Hist.isHistorySuppressed) { Hist.setSuppressHistory(false); return; } const [link, ...sub] = Hist.getHashParts(); if (link !== Hist.lastLoadedLink || sub.length === 0 || isForceLoad) { Hist.lastLoadedLink = link; if (link === HASH_BLANK) { isBlankFilterLoad = true; } else { const listItem = Hist.getActiveListItem(link); if (listItem == null) { if (typeof pHandleUnknownHash === "function" && window.location.hash.length && Hist._lastUnknownLink !== link) { Hist._lastUnknownLink = link; pHandleUnknownHash(link, sub); return; } else { Hist._freshLoad(); return; } } const toLoad = listItem.ix; if (toLoad === undefined) Hist._freshLoad(); else { Hist.lastLoadedId = listItem.ix; loadHash(listItem.ix); document.title = `${listItem.name ? `${listItem.name} - ` : ""}5etools`; } } } if (typeof loadSubHash === "function" && (sub.length > 0 || isForceLoad)) loadSubHash(sub); if (isBlankFilterLoad) Hist._freshLoad(); } static init (initialLoadComplete) { window.onhashchange = () => Hist.hashChange({isForceLoad: true}); if (window.location.hash.length) { Hist.hashChange(); } else { Hist._freshLoad(); } if (initialLoadComplete) Hist.initialLoad = false; } /** * Allows the hash to be modified without triggering a hashchange * @param val */ static setSuppressHistory (val) { Hist.isHistorySuppressed = val; } static _listPage = null; static setListPage (listPage) { this._listPage = listPage; } static getSelectedListItem () { const [link] = Hist.getHashParts(); return Hist.getActiveListItem(link); } static getSelectedListElementWithLocation () { const [link] = Hist.getHashParts(); return Hist.getActiveListItem(link, true); } static getHashParts () { return Hist.util.getHashParts(window.location.hash); } static getActiveListItem (link, getIndex) { const primaryLists = this._listPage.primaryLists; if (primaryLists && primaryLists.length) { for (let x = 0; x < primaryLists.length; ++x) { const list = primaryLists[x]; const foundItemIx = list.items.findIndex(it => it.values.hash === link); if (~foundItemIx) { if (getIndex) return {item: list.items[foundItemIx], x: x, y: foundItemIx, list}; return list.items[foundItemIx]; } } } } static _freshLoad () { // defer this, in case the list needs to filter first setTimeout(() => { const goTo = $("#listcontainer").find(".list a").attr("href"); if (goTo) { const parts = location.hash.split(HASH_PART_SEP); const fullHash = `${goTo}${parts.length > 1 ? `${HASH_PART_SEP}${parts.slice(1).join(HASH_PART_SEP)}` : ""}`; location.replace(fullHash); } }, 1); } static cleanSetHash (toSet) { window.location.hash = Hist.util.getCleanHash(toSet); } static getHashSource () { const [link] = Hist.getHashParts(); // by convention, the source is the last hash segment return link ? link.split(HASH_LIST_SEP).last() : null; } static getSubHash (key) { return Hist.util.getSubHash(window.location.hash, key); } /** * Sets a subhash with the key specified, overwriting any existing. * @param key Subhash key. * @param val Subhash value. Passing a nully object removes the k/v pair. */ static setSubhash (key, val) { const nxtHash = Hist.util.setSubhash(window.location.hash, key, val); Hist.cleanSetHash(nxtHash); } static setMainHash (hash) { const subHashPart = Hist.util.getHashParts(window.location.hash, key, val).slice(1).join(HASH_PART_SEP); Hist.cleanSetHash([hash, subHashPart].filter(Boolean).join(HASH_PART_SEP)); } static replaceHistoryHash (hash) { window.history.replaceState( {}, document.title, `${location.origin}${location.pathname}${hash ? `#${hash}` : ""}`, ); } } Hist.lastLoadedLink = null; Hist._lastUnknownLink = null; Hist.lastLoadedId = null; Hist.initialLoad = true; Hist.isHistorySuppressed = false; Hist.util = class { static getCleanHash (hash) { return hash.replace(/,+/g, ",").replace(/,$/, "").toLowerCase(); } static _SYMS_NO_ENCODE = [/(,)/g, /(:)/g, /(=)/g]; static getHashParts (location, {isReturnEncoded = false} = {}) { if (location[0] === "#") location = location.slice(1); // Handle junk from external ads if (location === "google_vignette") location = ""; if (isReturnEncoded) { return location .split(HASH_PART_SEP); } // region Normalize encoding let pts = [location]; this._SYMS_NO_ENCODE.forEach(re => { pts = pts.map(pt => pt.split(re)).flat(); }); pts = pts.map(pt => { if (this._SYMS_NO_ENCODE.some(re => re.test(pt))) return pt; return decodeURIComponent(pt).toUrlified(); }); location = pts.join(""); // endregion return location .split(HASH_PART_SEP); } static getSubHash (location, key) { const [link, ...sub] = Hist.util.getHashParts(location); const hKey = `${key}${HASH_SUB_KV_SEP}`; const part = sub.find(it => it.startsWith(hKey)); if (part) return part.slice(hKey.length); return null; } static setSubhash (location, key, val) { if (key.endsWith(HASH_SUB_KV_SEP)) key = key.slice(0, -1); const [link, ...sub] = Hist.util.getHashParts(location); if (!link) return ""; const hKey = `${key}${HASH_SUB_KV_SEP}`; const out = [link]; if (sub.length) sub.filter(it => !it.startsWith(hKey)).forEach(it => out.push(it)); if (val != null) out.push(`${hKey}${val}`); return Hist.util.getCleanHash(out.join(HASH_PART_SEP)); } }; globalThis.Hist = Hist;