-
Notifications
You must be signed in to change notification settings - Fork 4
/
Copy pathdestroyer.js
172 lines (146 loc) · 5.63 KB
/
destroyer.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
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
"use strict";
(function() {
if (window.__dom_destroyer_disarm) {
window.__dom_destroyer_disarm();
return;
}
var mask = document.createElement('div');
mask.classList.add('dom-destroyer--mask');
var iframe_blinder = document.createElement('div');
iframe_blinder.classList.add('dom-destroyer--iframe-blinder');
var current_target;
var oopsies = []; // undo stack
var soft_disarm = false;
var last_target_during_soft_disarm;
var lock_on = function lock_on(el, rect) {
if (current_target) current_target.classList.remove('dom-destroyer--target');
current_target = el;
current_target.classList.add('dom-destroyer--target');
rect = rect || el.getBoundingClientRect();
mask.style.width = rect.width + 'px';
mask.style.left = rect.left + 'px';
mask.style.height = rect.height + 'px';
mask.style.top = rect.top + 'px';
mask.style.display = 'block';
}
var _rafref;
var follow = function() {
if (soft_disarm) return;
cancelAnimationFrame(_rafref);
_rafref = requestAnimationFrame(() => {
if (current_target) lock_on(current_target);
})
}
var lock_off = function lock_off() {
current_target = null;
mask.style.display = 'none';
}
var change_target = function change_target(event) {
if (soft_disarm) {
last_target_during_soft_disarm = el;
return;
};
var el = event.target;
var rect = el.getBoundingClientRect();
if (el === iframe_blinder) return;
iframe_blinder.remove();
// if we are on an iframe, put a blinder on top so it doesn't steal clicks
if (el.tagName.toLowerCase() === 'iframe') {
document.body.appendChild(iframe_blinder);
iframe_blinder.style.width = rect.width + 'px';
iframe_blinder.style.left = rect.left + 'px';
iframe_blinder.style.height = rect.height + 'px';
iframe_blinder.style.top = rect.top + 'px';
}
// get to the bottom of a nested container stack
while (el.parentNode && el.parentNode.getBoundingClientRect) {
var parentRect = el.parentNode.getBoundingClientRect();
if (rect.top !== parentRect.top ||
rect.right !== parentRect.right ||
rect.bottom !== parentRect.bottom ||
rect.left !== parentRect.left
) break;
el = el.parentNode;
rect = parentRect;
}
lock_on(el, rect);
};
var destroy = function destroy(event) {
if (event && event.button !== 0) return disarm(); // destroy only with primary button
if (soft_disarm) return;
if (event) {
event.stopImmediatePropagation();
event.stopPropagation();
event.preventDefault();
}
if (!current_target) return;
var rect = current_target.getBoundingClientRect();
var replacement = document.createElement('div');
replacement.classList.add('dom-destroyer--replacement');
replacement.style.height = rect.height + 'px';
replacement.style.width = rect.width + 'px';
var target_style = getComputedStyle(current_target);
if (target_style.position !== 'static') {
replacement.style.position = target_style.position;
replacement.style.left = target_style.left;
replacement.style.top = target_style.top;
}
replacement.style.margin = target_style.margin;
if (target_style.display.includes('inline')) {
replacement.style.display = 'inline-block';
}
oopsies.push({ref: current_target, replacedWith: replacement});
current_target.replaceWith(replacement);
current_target.classList.remove('dom-destroyer--target');
// need the next-next frame to ensure the transition happens :(
requestAnimationFrame(() => requestAnimationFrame(() =>
replacement.classList.add('dom-destroyer--replacement-poofed')));
setTimeout(() => {
replacement.classList.add('dom-destroyer--replacement-gone');
soft_disarm = false;
if (last_target_during_soft_disarm) {
change_target(last_target_during_soft_disarm);
last_target_during_soft_disarm = null;
}
mask.style.opacity = '1';
}, 200);
soft_disarm = true;
mask.style.opacity = '0';
lock_off();
iframe_blinder.remove();
};
var revive = function revive() {
var latest = oopsies.pop();
if (latest) latest.replacedWith.replaceWith(latest.ref);
};
var key_action = function keydown(event) {
if (['Escape', 'q'].includes(event.key)) disarm();
else if (['Backspace', 'Delete', 'Enter', 'd', 'x'].includes(event.key)) destroy();
else if (event.key == 'z' && (event.ctrlKey || event.metaKey)) revive();
};
var disarm = function disarm() {
if (current_target) current_target.classList.remove('dom-destroyer--target');
mask.remove();
for (var oops; oops = oopsies.pop();) oops.replacedWith.remove();
document.removeEventListener('mousemove', change_target);
document.removeEventListener('click', destroy, true);
document.removeEventListener('contextmenu', disarm);
document.removeEventListener('keydown', key_action);
document.removeEventListener('scroll', follow);
window.removeEventListener('blur', disarm);
chrome.runtime.sendMessage({ armed: false });
window.__dom_destroyer_disarm = null;
};
var arm_destroyer = function arm_destroyer() {
document.body.appendChild(mask);
document.addEventListener('mousemove', change_target);
document.addEventListener('click', destroy, true);
document.addEventListener('contextmenu', disarm);
document.addEventListener('keydown', key_action);
document.addEventListener('scroll', follow);
window.addEventListener('blur', disarm);
chrome.runtime.sendMessage({ armed: true });
window.__dom_destroyer_disarm = disarm;
};
arm_destroyer();
})();