Repository navigation
Expand file tree
/
Copy pathtest.html
More file actions
351 lines (315 loc) · 16.7 KB
/
Copy pathtest.html
File metadata and controls
351 lines (315 loc) · 16.7 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
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width,initial-scale=1" />
<title>Toxic Shield — Comprehensive Test Page</title>
<style>
:root{--card-bg:#fff;--muted:#666}
body{font-family:Inter,Segoe UI,Arial,sans-serif;max-width:1100px;margin:20px auto;padding:20px;background:#f7f8fb;color:#111}
header{display:flex;align-items:center;gap:16px}
h1{margin:0;font-size:1.4rem}
.grid{display:grid;grid-template-columns:1fr 360px;gap:20px;margin-top:16px}
.card{background:var(--card-bg);border:1px solid #e3e6ee;padding:16px;border-radius:8px;box-shadow:0 1px 0 rgba(16,24,40,0.02)}
.section{margin-bottom:12px}
label{display:block;font-weight:600;margin-bottom:6px}
input[type="text"], textarea, .contenteditable{width:100%;padding:8px;border-radius:6px;border:1px solid #d6d9e6}
.contenteditable{min-height:100px}
button{padding:8px 10px;border-radius:6px;border:1px solid #cbd5e1;background:#fff;cursor:pointer}
.btn-primary{background:#0b69ff;color:#fff;border-color:#0857d6}
.controls{display:flex;flex-wrap:wrap;gap:8px;margin-top:8px}
.phrases{display:flex;flex-direction:column;gap:8px}
.log{height:300px;overflow:auto;background:#0b0f1a;color:#e6eef8;padding:10px;border-radius:6px;font-family:monospace;font-size:12px}
.muted{color:var(--muted);font-size:13px}
.row{display:flex;gap:8px;align-items:center}
.small{font-size:12px}
.highlight{outline:3px solid rgba(255,80,80,0.12)}
.samples{display:flex;gap:8px;flex-wrap:wrap}
.samples button{padding:6px 8px}
footer{margin-top:20px;font-size:13px;color:var(--muted)}
</style>
</head>
<body>
<header>
<h1>🔬 Toxic Shield — Comprehensive Test Page</h1>
<div class="muted">Use this page to exercise inputs, dynamic elements, shadow DOM, iframes, paste events, and simulated typing.</div>
</header>
<div class="grid">
<main class="card">
<section class="section">
<label>Target selector / focus</label>
<div class="row">
<select id="targetSelect">
<option value="input">Input[type=text]</option>
<option value="textarea">Textarea</option>
<option value="content">Contenteditable DIV</option>
<option value="shadow">Shadow DOM input</option>
<option value="iframe">Iframe input</option>
<option value="dynamic">Last created dynamic element</option>
</select>
<button id="focusTarget">Focus target</button>
<button id="clearLog">Clear Log</button>
</div>
</section>
<section class="section">
<label>1) Basic interactive inputs</label>
<div class="section">
<input id="testInput" type="text" placeholder="Type toxic words here..." />
<textarea id="testTextarea" placeholder="Paste or type long content here..."></textarea>
<div id="testContent" class="contenteditable" contenteditable="true">Click here and start typing or paste content.</div>
</div>
</section>
<section class="section">
<label>2) Shadow DOM & Iframe</label>
<div class="row" style="gap:12px">
<div id="shadowHost" class="card" style="padding:8px;min-width:200px">Shadow host (created below)</div>
<div>
<button id="createShadow">Create Shadow Input</button>
</div>
<div style="margin-left:auto">
<button id="createIframe">Create Test Iframe</button>
</div>
</div>
<div id="iframeContainer" style="margin-top:8px"></div>
</section>
<section class="section">
<label>3) Dynamic content (adds inputs/contenteditable on demand)</label>
<div class="controls">
<button id="addInput">Add input[type=text]</button>
<button id="addTextarea">Add textarea</button>
<button id="addContent">Add contenteditable div</button>
<button id="addComplex">Add complex node (with nested inputs)</button>
</div>
<div id="dynamicArea" style="margin-top:8px"></div>
</section>
<section class="section">
<label>4) Sample phrases</label>
<div class="phrases">
<div class="samples">
<button class="sample" data-text="Hello, how are you?">Safe</button>
<button class="sample" data-text="You're amazing and helpful.">Compliment</button>
<button class="sample" data-text="You're stupid and an idiot">Mildly Toxic</button>
<button class="sample" data-text="I will hurt you!">Threat / Severe</button>
<button class="sample" data-text="Die you motherfucker.">Offensive</button>
</div>
<div class="row small" style="margin-top:8px">
<button id="pasteSample">Paste selected into target (simulates paste)</button>
<button id="typeSample">Simulate typing into target</button>
<label class="muted" style="margin-left:auto">Typing speed: <input id="typeSpeed" type="range" min="10" max="200" value="60"/></label>
</div>
</div>
</section>
<section class="section">
<label>5) Paste / Drop tests</label>
<div class="muted">Try pasting text from the clipboard into the focused target; the log will capture paste events.</div>
</section>
<section class="section">
<label>6) Logs & event capture</label>
<div id="log" class="log"></div>
</section>
</main>
<aside class="card">
<h3 style="margin-top:0">Quick checklist</h3>
<ul>
<li>Focus different targets and type toxic phrases</li>
<li>Paste long content and observe extension behavior</li>
<li>Create dynamic inputs and confirm MutationObserver picks them up</li>
<li>Test shadow DOM and iframe inputs (extension should ignore cross-origin iframes)</li>
</ul>
<hr />
<h4 style="margin-bottom:6px">Selected phrase</h4>
<div id="selectedPhrase" class="muted">(none)</div>
<hr />
<h4 style="margin-bottom:6px">Notes</h4>
<div class="muted small">This page is designed to exercise common input types used by web apps (text inputs, textareas, contenteditable regions, shadow DOM inputs and iframes). When testing with the extension, ensure the content script is injected (look for a data attribute like <code>data-toxiguard-loaded</code> on the document element).</div>
</aside>
</div>
<footer class="muted">Toxic Shield — Test harness · Use with extension loaded in developer mode</footer>
<script>
// Utility: logging
const logEl = document.getElementById('log');
function log(...args){
const ts = new Date().toISOString().slice(11,23);
logEl.innerText = `${ts} | ${args.map(a=>typeof a==='object'?JSON.stringify(a):a).join(' ')}\n` + logEl.innerText;
}
// Elements
const testInput = document.getElementById('testInput');
const testTextarea = document.getElementById('testTextarea');
const testContent = document.getElementById('testContent');
const dynamicArea = document.getElementById('dynamicArea');
const targetSelect = document.getElementById('targetSelect');
const selectedPhraseEl = document.getElementById('selectedPhrase');
let lastDynamic = null;
let selectedPhrase = '';
// Attach basic event listeners to capture events from these elements
function attachLogging(el){
if(!el) return;
if(el.__tox_logger_attached) return;
['input','keydown','keyup','paste','focus','blur'].forEach(evt=>{
el.addEventListener(evt,e=>{
log(`event:${evt}`, el.tagName.toLowerCase(), el.type||'', (e.clipboardData ? e.clipboardData.getData('text') : ''));
},{capture:false});
});
el.__tox_logger_attached = true;
}
[testInput,testTextarea,testContent].forEach(attachLogging);
// Samples selection
document.querySelectorAll('.sample').forEach(btn=>{
btn.addEventListener('click',()=>{
selectedPhrase = btn.dataset.text;
selectedPhraseEl.innerText = selectedPhrase;
});
});
// Paste sample into target (simulate paste event)
document.getElementById('pasteSample').addEventListener('click',()=>{
const target = getTargetElement();
if(!target){ log('No target found to paste'); return; }
pasteTextInto(target, selectedPhrase || document.querySelector('.sample').dataset.text);
});
// Simulate typing
document.getElementById('typeSample').addEventListener('click',()=>{
const text = selectedPhrase || document.querySelector('.sample').dataset.text;
simulateTypingInto(getTargetElement(), text, Number(document.getElementById('typeSpeed').value));
});
function getTargetElement(){
const sel = targetSelect.value;
if(sel === 'input') return testInput;
if(sel === 'textarea') return testTextarea;
if(sel === 'content') return testContent;
if(sel === 'shadow') return document.querySelector('#shadowHost input');
if(sel === 'iframe'){
const f = document.querySelector('#iframeContainer iframe');
if(!f) return null;
try{ return f.contentDocument.querySelector('input, textarea, [contenteditable]'); }catch(e){ return null; }
}
if(sel === 'dynamic') return lastDynamic;
return null;
}
document.getElementById('focusTarget').addEventListener('click',()=>{
const t = getTargetElement(); if(t && t.focus) t.focus(); log('focusTarget', !!t);
});
// Paste helper that dispatches paste event where possible
function pasteTextInto(target, text){
if(!target) return log('paste: no target');
// For contenteditable
if(target.isContentEditable){
target.focus();
document.execCommand('insertText', false, text);
const ev = new Event('input', {bubbles:true}); target.dispatchEvent(ev);
log('pasted into contenteditable', text);
return;
}
// For input/textarea
const start = target.selectionStart || 0;
const end = target.selectionEnd || start;
const val = (target.value||'');
const newVal = val.slice(0,start) + text + val.slice(end);
target.value = newVal;
target.selectionStart = target.selectionEnd = start + text.length;
target.dispatchEvent(new Event('input',{bubbles:true}));
log('pasted into input', text);
}
// Simulate typing (character by character)
async function simulateTypingInto(target, text, delayMs=60){
if(!target){ log('type: no target'); return; }
if(target.isContentEditable){
target.focus(); target.innerText = '';
for(let ch of text){
await new Promise(r=>setTimeout(r,delayMs));
document.execCommand('insertText', false, ch);
target.dispatchEvent(new Event('input',{bubbles:true}));
}
} else {
target.focus(); target.value = '';
for(let ch of text){
await new Promise(r=>setTimeout(r,delayMs));
target.value += ch;
target.dispatchEvent(new Event('input',{bubbles:true}));
}
}
log('typing finished', text);
}
// Dynamic element creators
document.getElementById('addInput').addEventListener('click',()=>{
const inp = document.createElement('input'); inp.type='text'; inp.placeholder='Dynamically added input'; inp.style.marginTop='8px';
dynamicArea.appendChild(inp); attachLogging(inp); lastDynamic = inp; log('added input');
});
document.getElementById('addTextarea').addEventListener('click',()=>{
const ta = document.createElement('textarea'); ta.placeholder='Dynamically added textarea'; ta.style.marginTop='8px';
dynamicArea.appendChild(ta); attachLogging(ta); lastDynamic = ta; log('added textarea');
});
document.getElementById('addContent').addEventListener('click',()=>{
const d = document.createElement('div'); d.contentEditable='true'; d.className='contenteditable'; d.innerText='Dynamically added contenteditable'; d.style.marginTop='8px';
dynamicArea.appendChild(d); attachLogging(d); lastDynamic = d; log('added contenteditable');
});
document.getElementById('addComplex').addEventListener('click',()=>{
const wrapper = document.createElement('div'); wrapper.style.marginTop='8px';
wrapper.innerHTML = `<label>Complex node</label><div><input type='text' placeholder='nested input'/></div>`;
dynamicArea.appendChild(wrapper);
attachLogging(wrapper.querySelector('input'));
lastDynamic = wrapper.querySelector('input'); log('added complex node');
});
// Shadow DOM
document.getElementById('createShadow').addEventListener('click',()=>{
const host = document.getElementById('shadowHost'); host.innerHTML = '';
const shadow = host.attachShadow({mode:'open'});
const inp = document.createElement('input'); inp.placeholder='Shadow DOM input'; shadow.appendChild(inp);
attachLogging(inp);
log('created shadow input');
});
// Iframe
document.getElementById('createIframe').addEventListener('click',()=>{
const container = document.getElementById('iframeContainer'); container.innerHTML = '';
const iframe = document.createElement('iframe'); iframe.style.width='100%'; iframe.style.height='120px';
container.appendChild(iframe);
const doc = iframe.contentDocument || iframe.contentWindow.document;
doc.open(); doc.write(`<body style="font-family:Arial;padding:8px"><input placeholder='iframe input' style='width:100%'/></body>`); doc.close();
try{ attachLogging(iframe.contentDocument.querySelector('input')); log('created iframe and attached logger (same-origin)'); }
catch(e){ log('iframe created (cross-origin or inaccessible for script)'); }
});
// Global: monitor DOM for newly added inputs and attach logger
const mo = new MutationObserver(muts=>{
muts.forEach(m=>{
m.addedNodes.forEach(node=>{
if(node.nodeType!==1) return;
if(node.matches && (node.matches('input[type="text"]') || node.matches('textarea') || node.isContentEditable)){
attachLogging(node); log('mutation: attached to newly added node', node.tagName);
}
// also scan descendants
node.querySelectorAll && node.querySelectorAll('input[type="text"], textarea, [contenteditable="true"]').forEach(el=>{ attachLogging(el); log('mutation: attached descendant', el.tagName); });
});
});
});
mo.observe(document.body,{childList:true,subtree:true});
// Capture capture-level events for testing that extension's content script receives input events
['input','paste','keydown'].forEach(evt=>{
document.addEventListener(evt,e=>{
// annotate the doc for manual inspection
if(!document.documentElement.hasAttribute('data-test-events')) document.documentElement.setAttribute('data-test-events','true');
// basic log
// don't spam for every keydown
if(evt==='keydown') return;
log('document event', evt, e.type, e.target && (e.target.tagName||e.target.nodeName));
},{capture:false});
});
// Keep a visible hint if content script sets data-toxiguard-loaded
new MutationObserver(()=>{
if(document.documentElement.hasAttribute('data-toxiguard-loaded')){
log('content-script: data-toxiguard-loaded present');
}
}).observe(document.documentElement,{attributes:true});
// Clear log
document.getElementById('clearLog').addEventListener('click',()=>{ logEl.innerText=''; });
// Initialize: attach to dynamic elements already present
lastDynamic = null;
// Auto-select first sample
const first = document.querySelector('.sample'); if(first){ selectedPhrase = first.dataset.text; selectedPhraseEl.innerText = selectedPhrase; }
// Accessibility: keyboard shortcuts for convenience (F1-F3)
window.addEventListener('keydown', (e)=>{
if(e.key==='F1'){ e.preventDefault(); document.getElementById('typeSample').click(); }
if(e.key==='F2'){ e.preventDefault(); document.getElementById('pasteSample').click(); }
if(e.key==='F3'){ e.preventDefault(); document.getElementById('addInput').click(); }
});
</script>
</body>
</html>