Skip to content

Instantly share code, notes, and snippets.

@oops-wrong
Created May 29, 2024 19:28
Show Gist options
  • Save oops-wrong/08ae8f571e9087b1c694bf25f292fcf1 to your computer and use it in GitHub Desktop.
Save oops-wrong/08ae8f571e9087b1c694bf25f292fcf1 to your computer and use it in GitHub Desktop.
import { AiMessages } from '../ai';
import { ContentMessages } from '../content';
export * from './copy-to-clipboard-formatted';
export const delay = (value: number) => {
return new Promise((resolve) => {
setTimeout(() => {
resolve(undefined);
}, value);
});
};
export function throttle(fn, delayMs: number) {
let lastCall = 0;
let timeoutId = null;
let isThrottled = false;
return function (...args) {
const now = new Date().getTime();
if (!isThrottled) {
// @ts-ignore
fn.apply(this, args);
isThrottled = true;
timeoutId = setTimeout(() => {
lastCall = now;
isThrottled = false;
}, delayMs);
} else if (!timeoutId) {
timeoutId = setTimeout(() => {
lastCall = now;
isThrottled = false;
// @ts-ignore
fn.apply(this, args);
timeoutId = null;
}, delayMs - (now - lastCall));
}
};
}
export function throttleWithLastCall(func, delayMs: number) {
let timeoutId;
let lastExecTime = 0;
return function (...args) {
const currentTime = Date.now();
const elapsedTime = currentTime - lastExecTime;
const execute = () => {
// @ts-ignore
func.apply(this, args);
lastExecTime = currentTime;
};
clearTimeout(timeoutId);
if (elapsedTime > delayMs) {
execute();
} else {
timeoutId = setTimeout(execute, delayMs - elapsedTime);
}
};
}
export const observeDOM = (() => {
const MutationObserver = window.MutationObserver;
return (
obj: Element,
callback: () => any,
options: MutationObserverInit = {},
): MutationObserver => {
if (!obj || obj.nodeType !== 1) return;
if (MutationObserver) {
// define a new observer
const mutationObserver = new MutationObserver(callback);
// have the observer observe for changes in children
mutationObserver.observe(obj, {
childList: true,
subtree: true,
attributes: true,
characterData: true,
...options,
});
return mutationObserver;
}
// browser support fallback
else if (window.addEventListener) {
obj.addEventListener('DOMNodeInserted', callback, false);
obj.addEventListener('DOMNodeRemoved', callback, false);
}
};
})();
export const messageToBackground = (type: ContentMessages | AiMessages, payload: any = {}) => {
chrome.runtime.sendMessage({
type,
payload,
});
};
export const getElemWhenAppear = (
container: HTMLElement,
selector: string,
timeoutMs: number,
styles?: { [style: string]: string },
): Promise<HTMLElement> => {
return new Promise((resolve) => {
let observer;
const timeout = setTimeout(() => {
observer?.disconnect();
resolve(undefined);
}, timeoutMs);
const handler = () => {
const elem = container.querySelector(selector) as HTMLElement;
if (elem) {
if (styles) {
Object.entries(styles).forEach(([style, value]) => {
elem.style[style] = value;
});
}
observer?.disconnect();
clearTimeout(timeout);
resolve(elem);
}
};
const throttledHandler = throttleWithLastCall(handler, 50);
observer = observeDOM(container, throttledHandler);
});
};
export const getPromiseListener: (config: {
type: string;
before?: () => void;
onResolve: (data: any) => void;
timer: number;
}) => Promise<any> = (config) => {
config.before?.();
return new Promise((resolve) => {
const timer = setTimeout(() => {
window.removeEventListener('message', listener, false);
resolve(null);
}, config.timer);
const listener = (e) => {
if (e.data?.type === config.type) {
config.onResolve(e.data);
clearTimeout(timer);
window.removeEventListener('message', listener);
resolve(undefined);
}
};
window.addEventListener('message', listener, false);
});
};
export const copyToClipboard = (text: string) => {
const textarea = document.createElement('textarea');
textarea.value = text;
document.body.appendChild(textarea);
textarea.select();
// noinspection JSDeprecatedSymbols
document.execCommand('copy');
document.body.removeChild(textarea);
};
export const countWords = (value: string): number => {
const text = value?.trim();
if (!text) {
return 0;
}
return text?.split(/\s+/).length;
};
export const mouseClick = (element: Element) => {
element.dispatchEvent(new MouseEvent('mousedown', { bubbles: true, cancelable: true }));
element.dispatchEvent(new MouseEvent('mouseup', { bubbles: true, cancelable: true }));
};
export const getPromiseMessage = <T extends any>(type: ContentMessages | AiMessages): Promise<T> => {
return new Promise((resolve) => {
const handler = async (e) => {
if (e.data?.toBackground) {
return;
}
if (e.data?.type === type) {
window.removeEventListener('message', handler, false);
resolve(e.data?.payload);
}
};
window.addEventListener('message', handler, false);
});
};
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment