mirror of
https://github.com/ajayyy/SponsorBlock.git
synced 2024-09-20 21:13:50 +02:00
Wait for hover preview using mutation observer
This commit is contained in:
parent
bf735f47b0
commit
002f22c040
4 changed files with 42 additions and 9 deletions
|
@ -92,8 +92,8 @@ const playerButtons: Record<string, {button: HTMLButtonElement, image: HTMLImage
|
||||||
|
|
||||||
// Direct Links after the config is loaded
|
// Direct Links after the config is loaded
|
||||||
utils.wait(() => Config.config !== null, 1000, 1).then(() => videoIDChange(getYouTubeVideoID(document)));
|
utils.wait(() => Config.config !== null, 1000, 1).then(() => videoIDChange(getYouTubeVideoID(document)));
|
||||||
// wait infinitely for hover preview
|
// wait for hover preview to appear, and refresh attachments if ever found
|
||||||
utils.wait(() => getHoverPreview(), 0, 500).then(() => refreshVideoAttachments())
|
window.addEventListener("DOMContentLoaded", () => utils.waitForElement(".ytp-inline-preview-ui").then(() => refreshVideoAttachments()));
|
||||||
addPageListeners();
|
addPageListeners();
|
||||||
addHotkeyListener();
|
addHotkeyListener();
|
||||||
|
|
||||||
|
|
39
src/utils.ts
39
src/utils.ts
|
@ -21,6 +21,10 @@ export default class Utils {
|
||||||
"popup.css"
|
"popup.css"
|
||||||
];
|
];
|
||||||
|
|
||||||
|
/* Used for waitForElement */
|
||||||
|
waitingMutationObserver:MutationObserver = null;
|
||||||
|
waitingElements: { selector: string, callback: (element: Element) => void }[] = [];
|
||||||
|
|
||||||
constructor(backgroundScriptContainer: BackgroundScriptContainer = null) {
|
constructor(backgroundScriptContainer: BackgroundScriptContainer = null) {
|
||||||
this.backgroundScriptContainer = backgroundScriptContainer;
|
this.backgroundScriptContainer = backgroundScriptContainer;
|
||||||
}
|
}
|
||||||
|
@ -29,6 +33,41 @@ export default class Utils {
|
||||||
return GenericUtils.wait(condition, timeout, check);
|
return GenericUtils.wait(condition, timeout, check);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Uses a mutation observer to wait asynchronously */
|
||||||
|
async waitForElement(selector: string): Promise<Element> {
|
||||||
|
return await new Promise((resolve) => {
|
||||||
|
this.waitingElements.push({
|
||||||
|
selector,
|
||||||
|
callback: resolve
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!this.waitingMutationObserver) {
|
||||||
|
this.waitingMutationObserver = new MutationObserver(() => {
|
||||||
|
const foundSelectors = [];
|
||||||
|
for (const { selector, callback } of this.waitingElements) {
|
||||||
|
const element = document.querySelector(selector);
|
||||||
|
if (element) {
|
||||||
|
callback(element);
|
||||||
|
foundSelectors.push(selector);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
this.waitingElements = this.waitingElements.filter((element) => !foundSelectors.includes(element.selector));
|
||||||
|
|
||||||
|
if (this.waitingElements.length === 0) {
|
||||||
|
this.waitingMutationObserver.disconnect();
|
||||||
|
this.waitingMutationObserver = null;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
this.waitingMutationObserver.observe(document.body, {
|
||||||
|
childList: true,
|
||||||
|
subtree: true
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
containsPermission(permissions: chrome.permissions.Permissions): Promise<boolean> {
|
containsPermission(permissions: chrome.permissions.Permissions): Promise<boolean> {
|
||||||
return new Promise((resolve) => {
|
return new Promise((resolve) => {
|
||||||
chrome.permissions.contains(permissions, resolve)
|
chrome.permissions.contains(permissions, resolve)
|
||||||
|
|
|
@ -1,11 +1,10 @@
|
||||||
/** Function that can be used to wait for a condition before returning. */
|
/** Function that can be used to wait for a condition before returning. */
|
||||||
async function wait<T>(condition: () => T | false, timeout = 5000, check = 100): Promise<T> {
|
async function wait<T>(condition: () => T | false, timeout = 5000, check = 100): Promise<T> {
|
||||||
return await new Promise((resolve, reject) => {
|
return await new Promise((resolve, reject) => {
|
||||||
const failTimeout = setTimeout(() => {
|
setTimeout(() => {
|
||||||
clearInterval(interval);
|
clearInterval(interval);
|
||||||
reject("TIMEOUT");
|
reject("TIMEOUT");
|
||||||
}, timeout);
|
}, timeout);
|
||||||
if (timeout === 0) clearTimeout(failTimeout);
|
|
||||||
|
|
||||||
const intervalCheck = () => {
|
const intervalCheck = () => {
|
||||||
const result = condition();
|
const result = condition();
|
||||||
|
|
|
@ -19,11 +19,6 @@ export function getControls(): HTMLElement | false {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function getHoverPreview(): Element | false {
|
|
||||||
const hoverPreview = document.querySelector(".ytp-inline-preview-ui");
|
|
||||||
return hoverPreview || false;
|
|
||||||
}
|
|
||||||
|
|
||||||
export function isVisible(element: HTMLElement): boolean {
|
export function isVisible(element: HTMLElement): boolean {
|
||||||
return element && element.offsetWidth > 0 && element.offsetHeight > 0;
|
return element && element.offsetWidth > 0 && element.offsetHeight > 0;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue