-
Notifications
You must be signed in to change notification settings - Fork 10
/
Copy pathindex.ts
93 lines (77 loc) · 3.54 KB
/
index.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
// istanbul ignore file: Covered by E2E
import { logFailure } from '@lib/util/async';
import { insertStylesheet } from '@lib/util/css';
import { onDocumentLoaded, qs, qsa, qsMaybe } from '@lib/util/dom';
import type { InfoCache } from './info-cache';
import { displayedCoverArtFactory, DisplayedQueuedUploadImage, displayInfoWhenInView } from './displayed-image';
import { setupExports } from './exports';
import { createCache } from './info-cache';
import css from './style.scss';
// Query for the span element containing the cover art image.
// Old class name is "cover-art-image", new (since beta.MBS of May 24 2024) is "artwork-image".
// TODO: Change this when new class name lands in production MBS.
const ARTWORK_QUERY = '.cover-art-image, .artwork-image';
function processPageChange(mutations: MutationRecord[], cache: InfoCache): void {
const addedNodes = mutations.flatMap((mutation) => [...mutation.addedNodes]);
for (const addedNode of addedNodes) {
if (!(addedNode instanceof HTMLImageElement)) continue;
const displayedImage = displayedCoverArtFactory(addedNode, cache);
if (displayedImage !== undefined) {
displayInfoWhenInView(displayedImage);
}
}
}
function observeQueuedUploads(queuedUploadTable: HTMLTableElement): void {
const queuedUploadObserver = new MutationObserver((mutations) => {
const addedNodes = mutations.flatMap((mutation) => [...mutation.addedNodes]);
// Looking for additions of table rows, this indicates a newly queued upload.
for (const addedNode of addedNodes) {
if (!(addedNode instanceof HTMLTableRowElement)) continue;
const image = qsMaybe<HTMLImageElement>('img', addedNode);
if (image !== null) {
displayInfoWhenInView(new DisplayedQueuedUploadImage(image));
}
}
});
queuedUploadObserver.observe(qs('tbody', queuedUploadTable), {
childList: true,
});
}
function detectAndObserveImages(cache: InfoCache): void {
// MB's react lazily loads images, and this might run before it was able
// to insert the <img> elements. So we'll use a mutation observer and
// process the image whenever it gets added.
const imageLoadObserver = new MutationObserver((mutations) => {
processPageChange(mutations, cache);
});
for (const container of qsa(ARTWORK_QUERY)) {
// Seems to cover all possible cover art images except for queued upload thumbnails
const imageElement = qsMaybe<HTMLImageElement>('img', container);
// Cover art not available or not loaded by react yet.
if (imageElement === null) {
imageLoadObserver.observe(container, {
childList: true,
});
} else {
const displayedImage = displayedCoverArtFactory(imageElement, cache);
if (!displayedImage) continue;
displayInfoWhenInView(displayedImage);
}
}
// Listen for new queued uploads on "add cover art" pages
const queuedUploadTable = qsMaybe<HTMLTableElement>('#add-cover-art > table');
if (queuedUploadTable !== null) {
observeQueuedUploads(queuedUploadTable);
}
}
const cachePromise = createCache();
// Need to setup the exports before we wait for the cache promise to resolve,
// since otherwise the exports might not yet be available for scripts that
// might need them.
setupExports(cachePromise);
onDocumentLoaded(() => {
insertStylesheet(css);
cachePromise.then((cache) => {
detectAndObserveImages(cache);
}).catch(logFailure());
});