1 import {elem} from './dom';
4 * Returns a function, that, as long as it continues to be invoked, will not
5 * be triggered. The function will be called after it stops being called for
6 * N milliseconds. If `immediate` is passed, trigger the function on the
7 * leading edge, instead of the trailing.
8 * @attribution https://davidwalsh.name/javascript-debounce-function
9 * @param {Function} func
10 * @param {Number} waitMs
11 * @param {Boolean} immediate
14 export function debounce(func, waitMs, immediate) {
16 return function debouncedWrapper(...args) {
18 const later = function debouncedTimeout() {
20 if (!immediate) func.apply(context, args);
22 const callNow = immediate && !timeout;
23 clearTimeout(timeout);
24 timeout = setTimeout(later, waitMs);
25 if (callNow) func.apply(context, args);
30 * Scroll and highlight an element.
31 * @param {HTMLElement} element
33 export function scrollAndHighlightElement(element) {
36 const parentDetails = element.closest('details');
37 if (parentDetails && !parentDetails.open) {
38 parentDetails.open = true;
41 element.scrollIntoView({behavior: 'smooth'});
43 const highlight = getComputedStyle(document.body).getPropertyValue('--color-link');
44 element.style.outline = `2px dashed ${highlight}`;
45 element.style.outlineOffset = '5px';
46 element.style.transition = null;
48 element.style.transition = 'outline linear 3s';
49 element.style.outline = '2px dashed rgba(0, 0, 0, 0)';
50 const listener = () => {
51 element.removeEventListener('transitionend', listener);
52 element.style.transition = null;
53 element.style.outline = null;
54 element.style.outlineOffset = null;
56 element.addEventListener('transitionend', listener);
61 * Escape any HTML in the given 'unsafe' string.
62 * Take from https://stackoverflow.com/a/6234804.
63 * @param {String} unsafe
66 export function escapeHtml(unsafe) {
68 .replace(/&/g, '&')
69 .replace(/</g, '<')
70 .replace(/>/g, '>')
71 .replace(/"/g, '"')
72 .replace(/'/g, ''');
76 * Generate a random unique ID.
80 export function uniqueId() {
81 // eslint-disable-next-line no-bitwise
82 const S4 = () => (((1 + Math.random()) * 0x10000) | 0).toString(16).substring(1);
83 return (`${S4() + S4()}-${S4()}-${S4()}-${S4()}-${S4()}${S4()}${S4()}`);
87 * Create a promise that resolves after the given time.
91 export function wait(timeMs) {
92 return new Promise(res => {
93 setTimeout(res, timeMs);