diff --git a/packages/webawesome/docs/assets/scripts/permalink.js b/packages/webawesome/docs/assets/scripts/permalink.js deleted file mode 100644 index 9a167cf47..000000000 --- a/packages/webawesome/docs/assets/scripts/permalink.js +++ /dev/null @@ -1,178 +0,0 @@ -import { deepEach, deepGet, deepSet } from './util/deep.js'; -import { camelCase, kebabCase } from './util/string.js'; - -export default class Permalink extends URLSearchParams { - /** Params changed since last URL I/O */ - changed = false; - - constructor(params) { - super(location.search); - this.params = params; - } - - toJSON() { - return Object.fromEntries(this.entries()); - } - - /** - * Set multiple values from an object. Nested values will be joined with a hyphen. - * @param {object} values - The object containing the values to set. - * @param {object} defaults - The object containing the default values. - * - */ - setAll(values, defaults) { - deepEach(values, (value, key, parent, path) => { - let fullPath = [...path, key]; - let param = fullPath.map(kebabCase).join('-'); - - if (typeof value === 'object') { - // We'll handle this when we descend into it - return; - } - - let defaultValue = deepGet(defaults, fullPath); - - if (equals(value, defaultValue)) { - // Remove the param from the URL - this.delete(param); - return; - } - - this.set(param, value); - }); - } - - /** - * Convert the URL params to a (potentially nested) object. - * @param {object} options - Options object. - * @param {(key: string, value: string) => string[]} options.getPath - Function to get the path of a param. - * @returns {object} The nested object. - */ - toObject(options = {}) { - // Default getPath() assumes hyphens always mean nesting - let { ignoreKeys = [], getPath = param => param.split('-') } = options; - - // Get all values as a nested object - - let obj = {}; - - for (let [key, value] of this.entries()) { - let path = getPath(key, value); - - if (path === null || ignoreKeys.includes(key)) { - // Skip this param - continue; - } - - // Default to key if `getPath()` returns undefined - path ??= key; - - path = Array.isArray(path) ? path : [path]; - - // Camel case any remaining hyphens - path = path.map(camelCase); - - deepSet(obj, path, value); - } - - return obj; - } - - delete(key, value) { - let hadValue = this.has(key); - super.delete(key, value); - - if (hadValue) { - this.changed = true; - } - } - - set(key, value, defaultValue) { - if (equals(value, defaultValue) || equals(value, '')) { - value = null; - } - - value ??= null; // undefined -> null - - let oldValue = Array.isArray(value) ? this.getAll(key) : this.get(key); - let changed = !equals(value, oldValue); - - if (!changed) { - // Nothing to do here - return; - } - - if (Array.isArray(value)) { - super.delete(key); - value = value.slice(); - - for (let v of value) { - if (v || v === 0) { - if (typeof v === 'object') { - super.append(key, JSON.stringify(v)); - } else { - super.append(key, v); - } - } - } - } else if (value === null) { - super.delete(key); - } else { - super.set(key, value); - } - - this.sort(); - this.changed ||= changed; - } - - /** - * Update page URL if it has changed since last time - */ - updateLocation() { - if (this.changed) { - // If there’s already a search, replace it. - // We don’t want to clog the user’s history while they iterate - let search = this.toString(); - let historyAction = location.search && search ? 'replaceState' : 'pushState'; - history[historyAction](null, '', `?${search}`); - this.changed = false; - } - } -} - -function equals(value, oldValue) { - if (Array.isArray(value) || Array.isArray(oldValue)) { - value = toArray(value); - oldValue = toArray(oldValue); - - if (value.length !== oldValue.length) { - return false; - } - - return value.every((v, i) => equals(v, oldValue[i])); - } - - // (value ?? oldValue ?? true) returns true if they're both empty (null or undefined) - [value, oldValue] = [value, oldValue].map(v => (!v && v !== false && v !== 0 ? null : v)); - return value === oldValue || String(value) === String(oldValue); -} - -/** - * Convert a value to an array. `undefined` and `null` values are converted to an empty array. - * @param {*} value - The value to convert. - * @returns {any[]} The converted array. - */ -function toArray(value) { - value ??= []; - - if (Array.isArray(value)) { - return value; - } - - // Don't convert "foo" into ["f", "o", "o"] - if (typeof value !== 'string' && typeof value[Symbol.iterator] === 'function') { - return Array.from(value); - } - - return [value]; -} diff --git a/packages/webawesome/docs/assets/scripts/scroll.js b/packages/webawesome/docs/assets/scripts/scroll.js index 609c29d5e..eb376a613 100644 --- a/packages/webawesome/docs/assets/scripts/scroll.js +++ b/packages/webawesome/docs/assets/scripts/scroll.js @@ -34,7 +34,8 @@ document.addEventListener('click', event => { top: target.offsetTop - headerHeight, behavior: 'smooth', }); - history.pushState(undefined, undefined, `#${id}`); + + history.replaceState(history.state, '', `#${id}`); } } });