Repository navigation
Expand file tree
/
Copy pathcontent.js
More file actions
168 lines (142 loc) · 4.98 KB
/
Copy pathcontent.js
File metadata and controls
168 lines (142 loc) · 4.98 KB
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
/**
* TimeCat - Content Script
*
* Este script é injetado nas páginas web para criar e gerenciar o overlay de bloqueio.
*/
// Initialize Logger for Content Context
// Note: TimeCatLogger is available because utils/logger.js is loaded first via manifest
TimeCatLogger.initGlobalHandlers('CONTENT');
let overlayElement = null;
let observer = null;
let isBlockActive = false;
/**
* Cria o elemento de overlay se ele ainda não existir.
*/
function createOverlay() {
if (document.getElementById('time-cat-blocking-overlay')) return;
overlayElement = document.createElement('div');
overlayElement.id = 'time-cat-blocking-overlay';
overlayElement.className = 'time-cat-overlay';
overlayElement.innerHTML = `
<div class="time-cat-content">
<h1 class="time-cat-title">Time to Pause! 🐾</h1>
<p class="time-cat-message">You've reached your continuous usage limit. Take a short break.</p>
<div id="time-cat-timer" style="font-size: 2rem; font-weight: bold;">--:--</div>
</div>
`;
// Inserir como o primeiro filho do body ou documentElement para maior prioridade
(document.body || document.documentElement).appendChild(overlayElement);
document.body.classList.add('time-cat-blocked');
// Bloqueio extra: impedir propagação de eventos de teclado
window.addEventListener('keydown', blockEvents, true);
window.addEventListener('keyup', blockEvents, true);
window.addEventListener('keypress', blockEvents, true);
startAntiBypass();
}
/**
* Remove o overlay e restaura a interação.
*/
function removeOverlay() {
isBlockActive = false;
stopAntiBypass();
const el = document.getElementById('time-cat-blocking-overlay');
if (el) el.remove();
overlayElement = null;
document.body.classList.remove('time-cat-blocked');
window.removeEventListener('keydown', blockEvents, true);
window.removeEventListener('keyup', blockEvents, true);
window.removeEventListener('keypress', blockEvents, true);
}
/**
* Estratégia Anti-Bypass: MutationObserver
* Detecta se alguém tentar remover o overlay ou a classe do body.
*/
function startAntiBypass() {
if (observer) return;
observer = new MutationObserver((mutations) => {
if (!isBlockActive) return;
for (const mutation of mutations) {
// Se o overlay for removido, recria
if (!document.getElementById('time-cat-blocking-overlay')) {
createOverlay();
}
// Se a classe do body for removida, readiciona
if (!document.body.classList.contains('time-cat-blocked')) {
document.body.classList.add('time-cat-blocked');
}
}
});
observer.observe(document.documentElement, {
attributes: true,
childList: true,
subtree: true
});
// Verificação secundária periódica (fail-safe)
const heartbeat = setInterval(() => {
if (!isBlockActive) {
clearInterval(heartbeat);
return;
}
if (!document.getElementById('time-cat-blocking-overlay')) createOverlay();
if (!document.body.classList.contains('time-cat-blocked')) document.body.classList.add('time-cat-blocked');
}, 1000);
}
function stopAntiBypass() {
if (observer) {
observer.disconnect();
observer = null;
}
}
/**
* Função para capturar e anular eventos indesejados.
*/
function blockEvents(event) {
if (isBlockActive) {
event.stopImmediatePropagation();
}
}
/**
* Formata segundos em MM:SS
*/
function formatTime(seconds) {
const mins = Math.floor(seconds / 60);
const secs = seconds % 60;
return `${mins.toString().padStart(2, '0')}:${secs.toString().padStart(2, '0')}`;
}
/**
* Inicialização: Sincroniza o estado atual com o background script.
*/
function initialize() {
chrome.runtime.sendMessage({ action: "request_status" }, (response) => {
if (chrome.runtime.lastError) return;
if (response && response.isBlocked) {
isBlockActive = true;
createOverlay();
const timerElement = document.getElementById('time-cat-timer');
if (timerElement) {
timerElement.innerText = formatTime(response.secondsLeft);
}
}
});
}
// Executa a inicialização assim que o script for injetado
initialize();
/**
* Escuta mensagens do Background Service Worker
*/
chrome.runtime.onMessage.addListener((request, sender, sendResponse) => {
if (request.action === "block_page") {
isBlockActive = true;
createOverlay();
} else if (request.action === "unblock_page") {
removeOverlay();
} else if (request.action === "update_countdown") {
isBlockActive = true;
const timerElement = document.getElementById('time-cat-timer');
if (timerElement) {
timerElement.innerText = formatTime(request.secondsLeft);
} else {
createOverlay();
}
}
});