/
pokemon-tcg-ext.js
101 lines (89 loc) · 3.04 KB
/
pokemon-tcg-ext.js
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
94
95
96
97
98
99
100
101
const PTCGO_CARD_PATTERN = new RegExp(/([A-Z-]{3,6} \d{1,3})/g);
const HIGHLIGHT_STYLES = `text-decoration: underline dashed darkred 2px;`;
let ALREADY_RUN = false;
browser.runtime.onMessage.addListener((message) => {
if (message.action === "scanAndHighlight") {
if (!ALREADY_RUN) {
scanAndHighlight();
ALREADY_RUN = true;
}
}
});
function highlightCard(event) {
const element = event.target;
const ptcgoCode = element.dataset?.ptcgo;
const imageSrc = element.dataset?.imageSrc;
if (ptcgoCode && !imageSrc) {
browser.runtime
.sendMessage({ action: "download", ptcgoCode })
.then((response) => {
if (response.status === 0) {
element.dataset.imageSrc = DOMPurify.sanitize(response.image);
showImage(element);
} else {
element.dataset.imageSrc = "n/a";
}
});
}
if (imageSrc) {
showImage(element);
}
}
function showImage(element) {
const imageSrc = element.dataset.imageSrc;
if (!imageSrc || imageSrc === "n/a") {
return;
}
const popUp = document.createElement("img");
popUp.src = DOMPurify.sanitize(imageSrc);
popUp.style = "width: 200px; position: absolute; z-index: 999";
element.appendChild(popUp);
}
function hideCard(event) {
const element = event.target;
const image = element.querySelector("img");
/* It's possible to trigger hide real quick before the image has been added to the DOM.
* In that case, the image stays in the DOM once it's added and can cause problems.
* This timeout runs the hideCard again after a short while to prevent this issue
*/
if (!image) {
setTimeout(() => hideCard(event), 50);
}
element.removeChild(image);
}
function scanAndHighlight() {
const location = window.location.hostname;
let content = "";
/* A few special cases for sites that often have decklists shared */
if (location.includes("youtube") || location.includes("youtu.be")) {
content = document.querySelectorAll(".yt-core-attributed-string");
} else if (location.includes("discord.com")) {
content = document.querySelectorAll("li > div");
} else {
content = document.querySelectorAll("div");
}
Object.values(content).forEach((node) => {
if (node.textContent.match(PTCGO_CARD_PATTERN)) {
node.innerHTML = DOMPurify.sanitize(
node.innerHTML.replaceAll(
PTCGO_CARD_PATTERN,
`<span class="pokemon-tcg-card" tabindex="0" style="${HIGHLIGHT_STYLES}" data-ptcgo="$&">$&</span>`
)
);
}
});
/* For hovering with mouse */
document
.querySelectorAll(".pokemon-tcg-card")
.forEach((node) => node.addEventListener("mouseenter", highlightCard));
document
.querySelectorAll(".pokemon-tcg-card")
.forEach((node) => node.addEventListener("mouseleave", hideCard));
/* For tabbing through with keyboard */
document
.querySelectorAll(".pokemon-tcg-card")
.forEach((node) => node.addEventListener("focusin", highlightCard));
document
.querySelectorAll(".pokemon-tcg-card")
.forEach((node) => node.addEventListener("focusout", hideCard));
}