-
Notifications
You must be signed in to change notification settings - Fork 1
/
content.js
147 lines (131 loc) · 4.32 KB
/
content.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
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
'use strict';
const ELEMENT_NODE = 1;
function* yield_added_nodes(mutation_records) {
for (const mutation_record of mutation_records) {
if (mutation_record.addedNodes === null) {
continue;
}
for (const node of mutation_record.addedNodes) {
yield node;
}
}
}
// It's difficult to tell if a room tracks a live battle, a replay, or an
// observed battle. This class watchs the room to see if the user is ever
// presented with the option to attack. If so, it's considered a live room, even
// if the battle has now ended.
class LiveBattleDiscoverer {
constructor(room_div) {
this.is_live = false;
(new MutationObserver((records, observer) => {
for (const node of yield_added_nodes(records)) {
if (node.nodeName === "DIV" && node.querySelector(".whatdo")) {
this.is_live = true;
observer.disconnect();
}
}
})).observe(room_div, {childList: true, subtree: true});
}
battleEnd() {
this.is_live = false;
}
}
function title_to_url(title) {
const pokemon = title
.replace(/ \((active|fainted)\)/, '') // trim any (active), (fainted)
.replace(/.*\((.*)\)/, "$1"); // whatever is in () is the actual pokemon
return "https://www.smogon.com/dex/ss/pokemon/" + pokemon;
}
function add_picon_links() {
const picons = document.querySelectorAll(".teamicons > .picon");
for (const picon of picons) {
const label = picon.getAttribute('aria-label')
if (label === "Not revealed") {
continue;
}
picon.onclick = () => window.open(title_to_url(label));
picon.style.cursor = "pointer";
}
}
function show_end_battle_notif(discoverer, mutation_records, observer) {
for (const node of yield_added_nodes(mutation_records)) {
if (
discoverer.is_live &&
node.innerText.match(/.*won the battle!/)
) {
chrome.runtime.sendMessage({
'type': 'notification',
'title': 'Battle complete!',
'message': node.innerText,
});
observer.disconnect();
discoverer.battleEnd();
break;
}
}
}
function add_calc_link() {
const spriteDiv = document.querySelector(".leftbar > .trainer > .trainersprite");
if (spriteDiv === null) {
return
}
spriteDiv.onclick = () => window.open("https://calc.pokemonshowdown.com/randoms.html?mode=randoms");
spriteDiv.style.cursor = "pointer";
}
function observe_room(room_div) {
const discoverer = new LiveBattleDiscoverer(room_div);
(new MutationObserver(() => add_picon_links()))
.observe(
room_div.querySelector('.battle'),
{childList: true, subtree: true}
);
(new MutationObserver(() => add_calc_link()))
.observe(
room_div.querySelector('.battle'),
{childList: true, subtree: true}
);
(new MutationObserver(
(records, observer) => show_end_battle_notif(discoverer, records, observer))
)
.observe(
room_div.querySelector('.battle-log'),
{childList: true, subtree: true}
);
}
function add_room_observers(mutation_records) {
for (const node of yield_added_nodes(mutation_records)) {
if (node.nodeName === "DIV" && node.id.match(/room-battle-.*/)) {
observe_room(node);
}
}
}
function handle_body_update(body_div, mutation_records) {
for (const node of yield_added_nodes(mutation_records)) {
if (node.nodeType === ELEMENT_NODE && node.id === "tooltipwrapper") {
const tooltip = node.querySelector('.tooltip');
if (tooltip === null) {
continue;
}
chrome.runtime.sendMessage({
'type': 'tooltip',
'contents': node.innerText,
});
}
}
}
// This script is run before the document is created, to make sure all of our
// listeners trigger when the corresponding DOM elements are created.
// So, we listen to the body element being created, and attach once it is.
new MutationObserver((mutation_records, observer) => {
for (const node of yield_added_nodes(mutation_records)) {
if (node.nodeName === "BODY") {
(new MutationObserver(add_room_observers))
.observe(node, {childList: true});
(new MutationObserver((records) => handle_body_update(node, records)))
.observe(node, {childList: true});
// Once we've started observing the body nothing else to do
observer.disconnect();
return;
}
}
}).observe(document.documentElement, {childList: true});