-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathcontent.js
152 lines (134 loc) · 4.52 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
148
149
150
151
152
chrome.storage.local.get(['activeHostnames', 'settings'], (result) => {
const hostname = window.location.hostname;
if (result.activeHostnames && result.activeHostnames.includes(hostname)) {
initializeFeatures(result.settings);
}
});
function initializeFeatures(settings) {
if (settings.copyProtection) {
enableRightClickAndCopy();
enableAbsoluteMode();
}
if (settings.alwaysActive) {
keepTabActive();
}
if (settings.dialogRemover) {
removeCopyProtectionDialogs();
}
}
// Enable right-click and copy functionality
function enableRightClickAndCopy() {
const events = ['contextmenu', 'copy', 'cut', 'paste', 'selectstart', 'select', 'keydown', 'keyup'];
events.forEach(event => {
document.addEventListener(event, (e) => e.stopPropagation(), true);
});
const css = `
*, *::before, *::after {
-webkit-user-select: text !important;
-moz-user-select: text !important;
-ms-user-select: text !important;
user-select: text !important;
pointer-events: auto !important;
}
`;
const style = document.createElement('style');
style.textContent = css;
document.head.appendChild(style);
}
// Absolute mode to remove event listeners that block copying
function enableAbsoluteMode() {
const events = [
'copy', 'cut', 'paste', 'select', 'selectstart', 'contextmenu',
'dragstart', 'mousedown', 'mouseup', 'mousemove', 'keydown', 'keyup',
'beforecopy', 'beforecut', 'beforepaste'
];
events.forEach(event => {
window.addEventListener(event, preventEvent, true);
document.addEventListener(event, preventEvent, true);
});
// Override Event.prototype.preventDefault
const originalPreventDefault = Event.prototype.preventDefault;
Event.prototype.preventDefault = function () {
if (events.includes(this.type)) {
return false;
}
return originalPreventDefault.apply(this, arguments);
};
}
function preventEvent(e) {
e.stopPropagation();
}
// Remove copy protection dialogs
function removeCopyProtectionDialogs() {
const observer = new MutationObserver((mutations) => {
mutations.forEach((mutation) => {
mutation.addedNodes.forEach((node) => {
if (node instanceof HTMLElement && node.matches('div[role="dialog"], .modal')) {
node.remove();
}
});
});
});
observer.observe(document.body, {
childList: true,
subtree: true
});
}
// Keep the tab active by overriding visibility properties and events
function keepTabActive() {
Object.defineProperty(document, 'visibilityState', {
get: () => 'visible',
configurable: true
});
Object.defineProperty(document, 'hidden', {
get: () => false,
configurable: true
});
const visibilityEvents = [
'visibilitychange', 'webkitvisibilitychange', 'mozvisibilitychange',
'mouseenter', 'mouseleave', 'focusin', 'focusout'
];
visibilityEvents.forEach(event => {
document.addEventListener(event, (e) => e.stopImmediatePropagation(), true);
});
const originalRequestAnimationFrame = window.requestAnimationFrame;
window.requestAnimationFrame = function (callback) {
return originalRequestAnimationFrame(function (timestamp) {
callback(timestamp);
window.requestAnimationFrame(callback);
});
};
}
// Handle messages from popup or background scripts
chrome.runtime.onMessage.addListener((message, sender, sendResponse) => {
if (message.action === 'updateSettings') {
initializeFeatures(message.settings);
sendResponse({ success: true });
} else if (message.action === 'keepAlive') {
sendResponse({ status: 'alive' });
}
});
// Update context menu with selected text
document.addEventListener('contextmenu', () => {
const selectedText = window.getSelection().toString();
if (selectedText) {
chrome.runtime.sendMessage({
action: 'updateContextMenu',
selectedText: selectedText
});
}
});
// Start features immediately
if (document.readyState === 'loading') {
document.addEventListener('DOMContentLoaded', () => initializeFeatures(defaultSettings()));
} else {
initializeFeatures(defaultSettings());
}
// Default settings in case storage is not ready
function defaultSettings() {
return {
copyProtection: true,
alwaysActive: true,
dialogRemover: true
};
}