40 lines
1.5 KiB
TypeScript
40 lines
1.5 KiB
TypeScript
import { watch } from 'vue';
|
|
import { accessFileUrl, fileAccessRevision, retryFileAccess } from './file-access';
|
|
|
|
/** Renew editor resources without replacing the document or changing its undo history. */
|
|
export function bindFileAccessDom(root: HTMLElement) {
|
|
let scheduled = false;
|
|
let stopped = false;
|
|
const refresh = () => {
|
|
if (stopped) return;
|
|
for (const node of root.querySelectorAll<HTMLElement>('[src], [href], [poster]')) {
|
|
for (const attr of ['src', 'href', 'poster']) {
|
|
const source = node.getAttribute(attr);
|
|
if (!source) continue;
|
|
const target = accessFileUrl(source);
|
|
if (target !== source) node.setAttribute(attr, target);
|
|
}
|
|
}
|
|
};
|
|
const schedule = () => {
|
|
if (scheduled || stopped) return;
|
|
scheduled = true;
|
|
queueMicrotask(() => { scheduled = false; refresh(); });
|
|
};
|
|
const observer = new MutationObserver(schedule);
|
|
observer.observe(root, { subtree: true, childList: true, attributes: true, attributeFilter: ['src', 'href', 'poster'] });
|
|
const unwatch = watch(fileAccessRevision, schedule, { flush: 'post' });
|
|
const onError = (event: Event) => {
|
|
const node = event.target;
|
|
if (node instanceof HTMLElement) void retryFileAccess(node.getAttribute('src')).then(schedule);
|
|
};
|
|
root.addEventListener('error', onError, true);
|
|
refresh();
|
|
return () => {
|
|
stopped = true;
|
|
observer.disconnect();
|
|
unwatch();
|
|
root.removeEventListener('error', onError, true);
|
|
};
|
|
}
|