insikt.js 1.1.0 → 1.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +110 -78
- package/dist/insikt.es.js +2117 -414
- package/dist/insikt.es.js.map +1 -1
- package/dist/insikt.umd.js +1 -1
- package/dist/insikt.umd.js.map +1 -1
- package/package.json +1 -1
package/dist/insikt.es.js
CHANGED
|
@@ -1,4 +1,8 @@
|
|
|
1
1
|
(function() {
|
|
2
|
+
const VERSION = "1.2.0";
|
|
3
|
+
const BUFFER_KEY = "__insikt_buffer__";
|
|
4
|
+
const SETTINGS_KEY = "__dc_settings";
|
|
5
|
+
const BODY_DISPLAY_LIMIT = 10 * 1024;
|
|
2
6
|
const css = `
|
|
3
7
|
@import url('https://fonts.googleapis.com/css2?family=JetBrains+Mono:wght@400;500;600;700&family=Syne:wght@400;600;700;800&display=swap');
|
|
4
8
|
|
|
@@ -21,11 +25,11 @@
|
|
|
21
25
|
--dc-sans: 'Syne', sans-serif;
|
|
22
26
|
}
|
|
23
27
|
|
|
24
|
-
/* Scope resets strictly to our elements */
|
|
25
28
|
#dc-panel, #dc-fab { box-sizing: border-box; }
|
|
26
29
|
#dc-panel *, #dc-fab * { box-sizing: inherit; }
|
|
27
30
|
|
|
28
31
|
/* ── FAB ────────────────────────────── */
|
|
32
|
+
|
|
29
33
|
#dc-fab {
|
|
30
34
|
position: fixed;
|
|
31
35
|
bottom: 20px;
|
|
@@ -49,7 +53,11 @@
|
|
|
49
53
|
margin: 0;
|
|
50
54
|
}
|
|
51
55
|
|
|
52
|
-
#dc-fab:hover {
|
|
56
|
+
#dc-fab:hover {
|
|
57
|
+
transform: scale(1.05);
|
|
58
|
+
box-shadow: 0 6px 30px rgba(124,106,247,0.7);
|
|
59
|
+
}
|
|
60
|
+
|
|
53
61
|
#dc-fab:active { transform: scale(0.95); }
|
|
54
62
|
|
|
55
63
|
.dc-fab-badge {
|
|
@@ -70,7 +78,8 @@
|
|
|
70
78
|
font-family: var(--dc-mono);
|
|
71
79
|
}
|
|
72
80
|
|
|
73
|
-
/* ──
|
|
81
|
+
/* ── PANEL ───────────────────────────── */
|
|
82
|
+
|
|
74
83
|
#dc-panel {
|
|
75
84
|
position: fixed;
|
|
76
85
|
bottom: 0;
|
|
@@ -98,10 +107,11 @@
|
|
|
98
107
|
|
|
99
108
|
@keyframes dcSlideUp {
|
|
100
109
|
from { transform: translateY(100%); opacity: 0; }
|
|
101
|
-
to { transform: translateY(0);
|
|
110
|
+
to { transform: translateY(0); opacity: 1; }
|
|
102
111
|
}
|
|
103
112
|
|
|
104
|
-
/*
|
|
113
|
+
/* ── DRAG HANDLE ─────────────────────── */
|
|
114
|
+
|
|
105
115
|
#dc-drag {
|
|
106
116
|
width: 100%;
|
|
107
117
|
height: 22px;
|
|
@@ -127,7 +137,8 @@
|
|
|
127
137
|
|
|
128
138
|
#dc-drag:hover::before { background: var(--dc-accent); }
|
|
129
139
|
|
|
130
|
-
/*
|
|
140
|
+
/* ── HEADER ──────────────────────────── */
|
|
141
|
+
|
|
131
142
|
#dc-header {
|
|
132
143
|
display: flex;
|
|
133
144
|
align-items: center;
|
|
@@ -157,8 +168,14 @@
|
|
|
157
168
|
}
|
|
158
169
|
|
|
159
170
|
@keyframes dcPulse {
|
|
160
|
-
0%,100% {
|
|
161
|
-
|
|
171
|
+
0%,100% {
|
|
172
|
+
opacity: 1;
|
|
173
|
+
box-shadow: 0 0 0 0 rgba(61,255,160,0.4);
|
|
174
|
+
}
|
|
175
|
+
50% {
|
|
176
|
+
opacity: 0.6;
|
|
177
|
+
box-shadow: 0 0 0 5px rgba(61,255,160,0);
|
|
178
|
+
}
|
|
162
179
|
}
|
|
163
180
|
|
|
164
181
|
.dc-hbtn {
|
|
@@ -177,9 +194,13 @@
|
|
|
177
194
|
padding: 0;
|
|
178
195
|
}
|
|
179
196
|
|
|
180
|
-
.dc-hbtn:hover {
|
|
197
|
+
.dc-hbtn:hover {
|
|
198
|
+
background: var(--dc-border);
|
|
199
|
+
color: var(--dc-text0);
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
/* ── TABS ────────────────────────────── */
|
|
181
203
|
|
|
182
|
-
/* Tabs */
|
|
183
204
|
#dc-tabs {
|
|
184
205
|
display: flex;
|
|
185
206
|
background: var(--dc-bg0);
|
|
@@ -229,7 +250,8 @@
|
|
|
229
250
|
margin-left: 5px;
|
|
230
251
|
}
|
|
231
252
|
|
|
232
|
-
/*
|
|
253
|
+
/* ── PANEL CONTENT ───────────────────── */
|
|
254
|
+
|
|
233
255
|
.dc-panel-content {
|
|
234
256
|
display: none;
|
|
235
257
|
flex-direction: column;
|
|
@@ -248,12 +270,16 @@
|
|
|
248
270
|
}
|
|
249
271
|
|
|
250
272
|
.dc-scroll::-webkit-scrollbar { width: 4px; }
|
|
251
|
-
.dc-scroll::-webkit-scrollbar-thumb {
|
|
273
|
+
.dc-scroll::-webkit-scrollbar-thumb {
|
|
274
|
+
background: var(--dc-border);
|
|
275
|
+
border-radius: 2px;
|
|
276
|
+
}
|
|
252
277
|
|
|
253
278
|
/* ── LOG ENTRIES ──────────────────────── */
|
|
279
|
+
|
|
254
280
|
.dc-entry {
|
|
255
281
|
display: flex;
|
|
256
|
-
align-items:
|
|
282
|
+
align-items: flex-start;
|
|
257
283
|
gap: 8px;
|
|
258
284
|
padding: 5px 8px;
|
|
259
285
|
border-radius: 5px;
|
|
@@ -262,15 +288,91 @@
|
|
|
262
288
|
line-height: 1.5;
|
|
263
289
|
word-break: break-word;
|
|
264
290
|
animation: dcFadeIn 0.1s ease;
|
|
291
|
+
position: relative;
|
|
292
|
+
}
|
|
293
|
+
|
|
294
|
+
@keyframes dcFadeIn {
|
|
295
|
+
from {
|
|
296
|
+
opacity: 0;
|
|
297
|
+
transform: translateY(2px);
|
|
298
|
+
}
|
|
299
|
+
to {
|
|
300
|
+
opacity: 1;
|
|
301
|
+
transform: none;
|
|
302
|
+
}
|
|
303
|
+
}
|
|
304
|
+
|
|
305
|
+
.dc-entry-log {
|
|
306
|
+
color: var(--dc-text0);
|
|
307
|
+
}
|
|
308
|
+
|
|
309
|
+
.dc-entry-warn {
|
|
310
|
+
color: var(--dc-orange);
|
|
311
|
+
background: rgba(255,179,71,0.07);
|
|
312
|
+
border-left: 2px solid var(--dc-orange);
|
|
313
|
+
}
|
|
314
|
+
|
|
315
|
+
.dc-entry-error {
|
|
316
|
+
color: var(--dc-red);
|
|
317
|
+
background: rgba(255,92,110,0.07);
|
|
318
|
+
border-left: 2px solid var(--dc-red);
|
|
319
|
+
}
|
|
320
|
+
|
|
321
|
+
.dc-entry-info {
|
|
322
|
+
color: var(--dc-blue);
|
|
323
|
+
background: rgba(91,206,250,0.06);
|
|
324
|
+
border-left: 2px solid var(--dc-blue);
|
|
265
325
|
}
|
|
266
326
|
|
|
267
|
-
|
|
327
|
+
.dc-entry-cmd {
|
|
328
|
+
color: var(--dc-accent);
|
|
329
|
+
background: rgba(124,106,247,0.06);
|
|
330
|
+
}
|
|
331
|
+
|
|
332
|
+
.dc-entry-table {
|
|
333
|
+
color: var(--dc-text0);
|
|
334
|
+
background: rgba(124,106,247,0.04);
|
|
335
|
+
border-left: 2px solid var(--dc-accent);
|
|
336
|
+
display: block;
|
|
337
|
+
}
|
|
338
|
+
|
|
339
|
+
.dc-entry-group {
|
|
340
|
+
color: var(--dc-accent);
|
|
341
|
+
background: rgba(124,106,247,0.05);
|
|
342
|
+
cursor: pointer;
|
|
343
|
+
user-select: none;
|
|
344
|
+
font-weight: 600;
|
|
345
|
+
}
|
|
346
|
+
|
|
347
|
+
.dc-entry-group:hover {
|
|
348
|
+
background: rgba(124,106,247,0.10);
|
|
349
|
+
}
|
|
350
|
+
|
|
351
|
+
.dc-group-arrow {
|
|
352
|
+
display: inline-block;
|
|
353
|
+
width: 12px;
|
|
354
|
+
color: var(--dc-text2);
|
|
355
|
+
font-size: 9px;
|
|
356
|
+
transition: transform 0.15s;
|
|
357
|
+
}
|
|
358
|
+
|
|
359
|
+
.dc-group-arrow.open {
|
|
360
|
+
transform: rotate(90deg);
|
|
361
|
+
}
|
|
362
|
+
|
|
363
|
+
.dc-group-children {
|
|
364
|
+
display: block;
|
|
365
|
+
}
|
|
366
|
+
|
|
367
|
+
.dc-group-children.collapsed {
|
|
368
|
+
display: none;
|
|
369
|
+
}
|
|
268
370
|
|
|
269
|
-
.dc-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
371
|
+
.dc-grouped {
|
|
372
|
+
margin-left: 18px;
|
|
373
|
+
border-left: 1px solid var(--dc-border);
|
|
374
|
+
border-radius: 0;
|
|
375
|
+
}
|
|
274
376
|
|
|
275
377
|
.dc-ts {
|
|
276
378
|
color: var(--dc-text2);
|
|
@@ -278,21 +380,135 @@
|
|
|
278
380
|
font-weight: 400;
|
|
279
381
|
flex-shrink: 0;
|
|
280
382
|
letter-spacing: 0;
|
|
383
|
+
white-space: nowrap;
|
|
281
384
|
}
|
|
282
385
|
|
|
283
|
-
.dc-entry
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
386
|
+
.dc-entry-body {
|
|
387
|
+
min-width: 0;
|
|
388
|
+
flex: 1;
|
|
389
|
+
}
|
|
390
|
+
|
|
391
|
+
/* ── OBJECT INSPECTOR ───────────────── */
|
|
392
|
+
|
|
393
|
+
.dc-value {
|
|
394
|
+
font-family: var(--dc-mono);
|
|
395
|
+
font-size: inherit;
|
|
396
|
+
line-height: 1.5;
|
|
397
|
+
}
|
|
398
|
+
|
|
399
|
+
.dc-primitive-string { color: var(--dc-green); }
|
|
400
|
+
.dc-primitive-number { color: var(--dc-blue); }
|
|
401
|
+
.dc-primitive-boolean { color: var(--dc-orange); }
|
|
402
|
+
.dc-primitive-null,
|
|
403
|
+
.dc-primitive-undefined {
|
|
404
|
+
color: var(--dc-text2);
|
|
405
|
+
}
|
|
406
|
+
|
|
407
|
+
.dc-primitive-bigint { color: var(--dc-blue); }
|
|
408
|
+
.dc-primitive-symbol { color: var(--dc-accent2); }
|
|
409
|
+
.dc-primitive-function { color: var(--dc-accent2); }
|
|
410
|
+
|
|
411
|
+
.dc-object-node {
|
|
412
|
+
display: inline;
|
|
413
|
+
}
|
|
414
|
+
|
|
415
|
+
.dc-object-toggle {
|
|
416
|
+
display: inline-flex;
|
|
417
|
+
align-items: center;
|
|
418
|
+
gap: 3px;
|
|
419
|
+
cursor: pointer;
|
|
420
|
+
user-select: none;
|
|
421
|
+
color: var(--dc-text1);
|
|
422
|
+
border-radius: 3px;
|
|
423
|
+
padding: 0 2px;
|
|
424
|
+
}
|
|
425
|
+
|
|
426
|
+
.dc-object-toggle:hover {
|
|
427
|
+
background: var(--dc-bg3);
|
|
428
|
+
}
|
|
429
|
+
|
|
430
|
+
.dc-object-arrow {
|
|
431
|
+
color: var(--dc-text2);
|
|
432
|
+
width: 10px;
|
|
433
|
+
font-size: 9px;
|
|
434
|
+
display: inline-block;
|
|
435
|
+
}
|
|
436
|
+
|
|
437
|
+
.dc-object-summary {
|
|
438
|
+
color: var(--dc-text1);
|
|
439
|
+
}
|
|
440
|
+
|
|
441
|
+
.dc-object-children {
|
|
442
|
+
display: none;
|
|
443
|
+
margin-left: 14px;
|
|
444
|
+
border-left: 1px solid var(--dc-border);
|
|
445
|
+
padding-left: 8px;
|
|
446
|
+
margin-top: 2px;
|
|
447
|
+
margin-bottom: 2px;
|
|
448
|
+
}
|
|
449
|
+
|
|
450
|
+
.dc-object-children.open {
|
|
451
|
+
display: block;
|
|
452
|
+
}
|
|
453
|
+
|
|
454
|
+
.dc-object-row {
|
|
455
|
+
display: block;
|
|
456
|
+
padding: 1px 0;
|
|
457
|
+
}
|
|
458
|
+
|
|
459
|
+
.dc-object-key {
|
|
460
|
+
color: var(--dc-accent2);
|
|
461
|
+
}
|
|
462
|
+
|
|
463
|
+
.dc-object-key-index {
|
|
464
|
+
color: var(--dc-text2);
|
|
465
|
+
}
|
|
466
|
+
|
|
467
|
+
.dc-object-more {
|
|
468
|
+
color: var(--dc-text2);
|
|
469
|
+
font-style: italic;
|
|
470
|
+
}
|
|
471
|
+
|
|
472
|
+
/* ── TABLE ───────────────────────────── */
|
|
473
|
+
|
|
474
|
+
.dc-table-wrap {
|
|
475
|
+
overflow-x: auto;
|
|
289
476
|
margin-top: 4px;
|
|
290
|
-
|
|
291
|
-
|
|
477
|
+
border: 1px solid var(--dc-border);
|
|
478
|
+
border-radius: 6px;
|
|
479
|
+
}
|
|
480
|
+
|
|
481
|
+
.dc-console-table {
|
|
292
482
|
width: 100%;
|
|
483
|
+
border-collapse: collapse;
|
|
484
|
+
font-family: var(--dc-mono);
|
|
485
|
+
font-size: 10px;
|
|
486
|
+
min-width: 280px;
|
|
487
|
+
}
|
|
488
|
+
|
|
489
|
+
.dc-console-table th {
|
|
490
|
+
background: var(--dc-bg3);
|
|
491
|
+
color: var(--dc-accent);
|
|
492
|
+
font-weight: 600;
|
|
493
|
+
text-align: left;
|
|
494
|
+
padding: 5px 7px;
|
|
495
|
+
border-bottom: 1px solid var(--dc-border);
|
|
496
|
+
white-space: nowrap;
|
|
497
|
+
}
|
|
498
|
+
|
|
499
|
+
.dc-console-table td {
|
|
500
|
+
padding: 5px 7px;
|
|
501
|
+
border-bottom: 1px solid var(--dc-border);
|
|
502
|
+
color: var(--dc-text1);
|
|
503
|
+
vertical-align: top;
|
|
504
|
+
}
|
|
505
|
+
|
|
506
|
+
.dc-console-table tr:last-child td {
|
|
507
|
+
border-bottom: none;
|
|
293
508
|
}
|
|
294
509
|
|
|
295
|
-
/* ── REPL
|
|
510
|
+
/* ── REPL ────────────────────────────── */
|
|
511
|
+
|
|
296
512
|
.dc-repl {
|
|
297
513
|
display: flex;
|
|
298
514
|
gap: 8px;
|
|
@@ -315,7 +531,10 @@
|
|
|
315
531
|
transition: border-color 0.15s;
|
|
316
532
|
}
|
|
317
533
|
|
|
318
|
-
.dc-input:focus {
|
|
534
|
+
.dc-input:focus {
|
|
535
|
+
border-color: var(--dc-accent);
|
|
536
|
+
box-shadow: 0 0 0 2px rgba(124,106,247,0.15);
|
|
537
|
+
}
|
|
319
538
|
|
|
320
539
|
.dc-run-btn {
|
|
321
540
|
padding: 8px 14px;
|
|
@@ -334,7 +553,29 @@
|
|
|
334
553
|
.dc-run-btn:hover { background: #8f7ffb; }
|
|
335
554
|
.dc-run-btn:active { transform: scale(0.96); }
|
|
336
555
|
|
|
337
|
-
/* ──
|
|
556
|
+
/* ── RELOAD SEPARATOR ────────────────── */
|
|
557
|
+
|
|
558
|
+
.dc-reload-separator {
|
|
559
|
+
display: flex;
|
|
560
|
+
align-items: center;
|
|
561
|
+
gap: 8px;
|
|
562
|
+
margin: 10px 0;
|
|
563
|
+
color: var(--dc-text2);
|
|
564
|
+
font-size: 9px;
|
|
565
|
+
letter-spacing: 0.1em;
|
|
566
|
+
text-transform: uppercase;
|
|
567
|
+
}
|
|
568
|
+
|
|
569
|
+
.dc-reload-separator::before,
|
|
570
|
+
.dc-reload-separator::after {
|
|
571
|
+
content: '';
|
|
572
|
+
height: 1px;
|
|
573
|
+
background: var(--dc-border);
|
|
574
|
+
flex: 1;
|
|
575
|
+
}
|
|
576
|
+
|
|
577
|
+
/* ── NETWORK ─────────────────────────── */
|
|
578
|
+
|
|
338
579
|
.dc-net-filter {
|
|
339
580
|
display: flex;
|
|
340
581
|
gap: 8px;
|
|
@@ -369,7 +610,10 @@
|
|
|
369
610
|
cursor: pointer;
|
|
370
611
|
}
|
|
371
612
|
|
|
372
|
-
.dc-clear-btn:hover {
|
|
613
|
+
.dc-clear-btn:hover {
|
|
614
|
+
border-color: var(--dc-red);
|
|
615
|
+
color: var(--dc-red);
|
|
616
|
+
}
|
|
373
617
|
|
|
374
618
|
.dc-req {
|
|
375
619
|
padding: 9px 10px;
|
|
@@ -416,9 +660,9 @@
|
|
|
416
660
|
}
|
|
417
661
|
|
|
418
662
|
.dc-req-status { flex-shrink: 0; }
|
|
419
|
-
.s-ok
|
|
663
|
+
.s-ok { color: var(--dc-green); }
|
|
420
664
|
.s-redir { color: var(--dc-orange); }
|
|
421
|
-
.s-err
|
|
665
|
+
.s-err { color: var(--dc-red); }
|
|
422
666
|
|
|
423
667
|
.dc-req-meta {
|
|
424
668
|
color: var(--dc-text2);
|
|
@@ -439,11 +683,76 @@
|
|
|
439
683
|
.dc-req-detail.open { display: block; }
|
|
440
684
|
|
|
441
685
|
.dc-detail-section { margin-bottom: 10px; }
|
|
442
|
-
|
|
443
|
-
.dc-detail-
|
|
686
|
+
|
|
687
|
+
.dc-detail-title {
|
|
688
|
+
color: var(--dc-accent);
|
|
689
|
+
font-weight: 700;
|
|
690
|
+
margin-bottom: 4px;
|
|
691
|
+
font-size: 10px;
|
|
692
|
+
letter-spacing: 0.08em;
|
|
693
|
+
text-transform: uppercase;
|
|
694
|
+
}
|
|
695
|
+
|
|
696
|
+
.dc-detail-row {
|
|
697
|
+
padding: 2px 0;
|
|
698
|
+
word-break: break-all;
|
|
699
|
+
}
|
|
700
|
+
|
|
444
701
|
.dc-detail-key { color: var(--dc-text2); }
|
|
445
702
|
|
|
446
|
-
|
|
703
|
+
.dc-body-block {
|
|
704
|
+
background: var(--dc-bg1);
|
|
705
|
+
border: 1px solid var(--dc-border);
|
|
706
|
+
border-radius: 5px;
|
|
707
|
+
padding: 7px;
|
|
708
|
+
margin-top: 5px;
|
|
709
|
+
}
|
|
710
|
+
|
|
711
|
+
.dc-body-pre {
|
|
712
|
+
white-space: pre-wrap;
|
|
713
|
+
word-break: break-word;
|
|
714
|
+
max-height: 160px;
|
|
715
|
+
overflow: auto;
|
|
716
|
+
margin: 0;
|
|
717
|
+
font-family: var(--dc-mono);
|
|
718
|
+
font-size: 10px;
|
|
719
|
+
color: var(--dc-green);
|
|
720
|
+
}
|
|
721
|
+
|
|
722
|
+
.dc-body-truncated {
|
|
723
|
+
color: var(--dc-orange);
|
|
724
|
+
font-size: 9px;
|
|
725
|
+
margin-top: 5px;
|
|
726
|
+
}
|
|
727
|
+
|
|
728
|
+
.dc-body-full {
|
|
729
|
+
display: none;
|
|
730
|
+
white-space: pre-wrap;
|
|
731
|
+
word-break: break-word;
|
|
732
|
+
max-height: 400px;
|
|
733
|
+
overflow: auto;
|
|
734
|
+
margin: 6px 0 0;
|
|
735
|
+
font-family: var(--dc-mono);
|
|
736
|
+
font-size: 10px;
|
|
737
|
+
color: var(--dc-green);
|
|
738
|
+
}
|
|
739
|
+
|
|
740
|
+
.dc-body-full.open { display: block; }
|
|
741
|
+
|
|
742
|
+
.dc-body-toggle {
|
|
743
|
+
margin-top: 5px;
|
|
744
|
+
padding: 4px 7px;
|
|
745
|
+
background: var(--dc-bg3);
|
|
746
|
+
border: 1px solid var(--dc-border);
|
|
747
|
+
border-radius: 4px;
|
|
748
|
+
color: var(--dc-text1);
|
|
749
|
+
font-family: var(--dc-mono);
|
|
750
|
+
font-size: 9px;
|
|
751
|
+
cursor: pointer;
|
|
752
|
+
}
|
|
753
|
+
|
|
754
|
+
/* ── STORAGE ─────────────────────────── */
|
|
755
|
+
|
|
447
756
|
.dc-storage-nav {
|
|
448
757
|
display: flex;
|
|
449
758
|
gap: 4px;
|
|
@@ -465,8 +774,16 @@
|
|
|
465
774
|
transition: all 0.15s;
|
|
466
775
|
}
|
|
467
776
|
|
|
468
|
-
.dc-st-btn.active {
|
|
469
|
-
|
|
777
|
+
.dc-st-btn.active {
|
|
778
|
+
background: var(--dc-accent);
|
|
779
|
+
border-color: var(--dc-accent);
|
|
780
|
+
color: #fff;
|
|
781
|
+
}
|
|
782
|
+
|
|
783
|
+
.dc-st-btn:hover:not(.active) {
|
|
784
|
+
border-color: var(--dc-text2);
|
|
785
|
+
color: var(--dc-text1);
|
|
786
|
+
}
|
|
470
787
|
|
|
471
788
|
.dc-storage-actions {
|
|
472
789
|
display: flex;
|
|
@@ -495,10 +812,23 @@
|
|
|
495
812
|
|
|
496
813
|
.dc-db-header:hover { background: var(--dc-border); }
|
|
497
814
|
|
|
498
|
-
.dc-db-name {
|
|
499
|
-
|
|
815
|
+
.dc-db-name {
|
|
816
|
+
color: var(--dc-blue);
|
|
817
|
+
font-size: 12px;
|
|
818
|
+
font-weight: 700;
|
|
819
|
+
}
|
|
820
|
+
|
|
821
|
+
.dc-db-meta {
|
|
822
|
+
color: var(--dc-text2);
|
|
823
|
+
font-size: 10px;
|
|
824
|
+
margin-top: 2px;
|
|
825
|
+
}
|
|
826
|
+
|
|
827
|
+
.dc-db-body {
|
|
828
|
+
display: none;
|
|
829
|
+
padding: 10px;
|
|
830
|
+
}
|
|
500
831
|
|
|
501
|
-
.dc-db-body { display: none; padding: 10px; }
|
|
502
832
|
.dc-db-card.open .dc-db-body { display: block; }
|
|
503
833
|
|
|
504
834
|
.dc-store-item {
|
|
@@ -512,8 +842,18 @@
|
|
|
512
842
|
}
|
|
513
843
|
|
|
514
844
|
.dc-store-item:hover { border-color: var(--dc-border); }
|
|
515
|
-
|
|
516
|
-
.dc-store-
|
|
845
|
+
|
|
846
|
+
.dc-store-name {
|
|
847
|
+
color: var(--dc-text0);
|
|
848
|
+
font-size: 12px;
|
|
849
|
+
font-weight: 600;
|
|
850
|
+
}
|
|
851
|
+
|
|
852
|
+
.dc-store-meta {
|
|
853
|
+
color: var(--dc-text2);
|
|
854
|
+
font-size: 10px;
|
|
855
|
+
margin-top: 2px;
|
|
856
|
+
}
|
|
517
857
|
|
|
518
858
|
.dc-data-viewer {
|
|
519
859
|
display: none;
|
|
@@ -530,8 +870,16 @@
|
|
|
530
870
|
font-size: 11px;
|
|
531
871
|
}
|
|
532
872
|
|
|
533
|
-
.dc-data-key
|
|
534
|
-
|
|
873
|
+
.dc-data-key {
|
|
874
|
+
color: #ffd700;
|
|
875
|
+
font-weight: 600;
|
|
876
|
+
}
|
|
877
|
+
|
|
878
|
+
.dc-data-val {
|
|
879
|
+
color: var(--dc-blue);
|
|
880
|
+
margin-top: 3px;
|
|
881
|
+
word-break: break-all;
|
|
882
|
+
}
|
|
535
883
|
|
|
536
884
|
.dc-kv-row {
|
|
537
885
|
display: flex;
|
|
@@ -542,8 +890,18 @@
|
|
|
542
890
|
font-size: 11px;
|
|
543
891
|
}
|
|
544
892
|
|
|
545
|
-
.dc-kv-key {
|
|
546
|
-
|
|
893
|
+
.dc-kv-key {
|
|
894
|
+
color: #ffd700;
|
|
895
|
+
font-weight: 600;
|
|
896
|
+
min-width: 100px;
|
|
897
|
+
word-break: break-all;
|
|
898
|
+
}
|
|
899
|
+
|
|
900
|
+
.dc-kv-val {
|
|
901
|
+
color: var(--dc-blue);
|
|
902
|
+
flex: 1;
|
|
903
|
+
word-break: break-all;
|
|
904
|
+
}
|
|
547
905
|
|
|
548
906
|
.dc-empty {
|
|
549
907
|
padding: 24px;
|
|
@@ -552,7 +910,8 @@
|
|
|
552
910
|
font-size: 12px;
|
|
553
911
|
}
|
|
554
912
|
|
|
555
|
-
/* ── DOM
|
|
913
|
+
/* ── DOM ─────────────────────────────── */
|
|
914
|
+
|
|
556
915
|
.dc-dom-toolbar {
|
|
557
916
|
display: flex;
|
|
558
917
|
gap: 8px;
|
|
@@ -573,8 +932,16 @@
|
|
|
573
932
|
transition: all 0.15s;
|
|
574
933
|
}
|
|
575
934
|
|
|
576
|
-
.dc-dom-btn:hover {
|
|
577
|
-
|
|
935
|
+
.dc-dom-btn:hover {
|
|
936
|
+
border-color: var(--dc-accent);
|
|
937
|
+
color: var(--dc-accent);
|
|
938
|
+
}
|
|
939
|
+
|
|
940
|
+
.dc-dom-btn.picking {
|
|
941
|
+
background: var(--dc-accent2);
|
|
942
|
+
border-color: var(--dc-accent2);
|
|
943
|
+
color: #fff;
|
|
944
|
+
}
|
|
578
945
|
|
|
579
946
|
.dc-tree { font-size: 12px; }
|
|
580
947
|
|
|
@@ -594,29 +961,51 @@
|
|
|
594
961
|
|
|
595
962
|
.dc-node-label:hover { background: var(--dc-bg3); }
|
|
596
963
|
|
|
597
|
-
.dc-arrow {
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
.dc-children { margin-left: 16px; display: none; }
|
|
604
|
-
.dc-children.open { display: block; }
|
|
964
|
+
.dc-arrow {
|
|
965
|
+
color: var(--dc-text2);
|
|
966
|
+
width: 12px;
|
|
967
|
+
flex-shrink: 0;
|
|
968
|
+
font-size: 9px;
|
|
969
|
+
}
|
|
605
970
|
|
|
606
|
-
.dc-
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
|
|
971
|
+
.dc-tag {
|
|
972
|
+
color: var(--dc-accent2);
|
|
973
|
+
font-weight: 600;
|
|
974
|
+
}
|
|
975
|
+
|
|
976
|
+
.dc-id { color: var(--dc-blue); }
|
|
977
|
+
.dc-cls { color: var(--dc-orange); }
|
|
978
|
+
|
|
979
|
+
.dc-txt-preview {
|
|
980
|
+
color: var(--dc-text2);
|
|
981
|
+
font-size: 10px;
|
|
982
|
+
max-width: 150px;
|
|
983
|
+
overflow: hidden;
|
|
984
|
+
text-overflow: ellipsis;
|
|
985
|
+
}
|
|
986
|
+
|
|
987
|
+
.dc-children {
|
|
988
|
+
margin-left: 16px;
|
|
989
|
+
display: none;
|
|
990
|
+
}
|
|
991
|
+
|
|
992
|
+
.dc-children.open { display: block; }
|
|
993
|
+
|
|
994
|
+
.dc-node-detail {
|
|
995
|
+
background: var(--dc-bg0);
|
|
996
|
+
border: 1px solid var(--dc-border);
|
|
997
|
+
border-radius: 6px;
|
|
998
|
+
padding: 12px;
|
|
999
|
+
margin: 8px 0;
|
|
1000
|
+
font-size: 11px;
|
|
613
1001
|
}
|
|
614
1002
|
|
|
615
1003
|
.dc-attr-row { padding: 3px 0; }
|
|
616
1004
|
.dc-attr-name { color: var(--dc-blue); }
|
|
617
|
-
.dc-attr-val
|
|
1005
|
+
.dc-attr-val { color: var(--dc-green); }
|
|
1006
|
+
|
|
1007
|
+
/* ── SYSTEM ──────────────────────────── */
|
|
618
1008
|
|
|
619
|
-
/* ── SYSTEM TAB ───────────────────────────────── */
|
|
620
1009
|
.dc-sys-grid {
|
|
621
1010
|
display: grid;
|
|
622
1011
|
grid-template-columns: 1fr 1fr;
|
|
@@ -648,7 +1037,8 @@
|
|
|
648
1037
|
|
|
649
1038
|
.dc-sys-full { grid-column: 1 / -1; }
|
|
650
1039
|
|
|
651
|
-
/* ── SETTINGS
|
|
1040
|
+
/* ── SETTINGS ───────────────────────── */
|
|
1041
|
+
|
|
652
1042
|
.dc-settings-body { padding: 10px 12px; }
|
|
653
1043
|
|
|
654
1044
|
.dc-setting-row {
|
|
@@ -662,8 +1052,18 @@
|
|
|
662
1052
|
.dc-setting-row:last-child { border-bottom: none; }
|
|
663
1053
|
|
|
664
1054
|
.dc-setting-info { flex: 1; }
|
|
665
|
-
|
|
666
|
-
.dc-setting-
|
|
1055
|
+
|
|
1056
|
+
.dc-setting-name {
|
|
1057
|
+
color: var(--dc-text0);
|
|
1058
|
+
font-size: 12px;
|
|
1059
|
+
font-weight: 600;
|
|
1060
|
+
}
|
|
1061
|
+
|
|
1062
|
+
.dc-setting-desc {
|
|
1063
|
+
color: var(--dc-text2);
|
|
1064
|
+
font-size: 10px;
|
|
1065
|
+
margin-top: 2px;
|
|
1066
|
+
}
|
|
667
1067
|
|
|
668
1068
|
.dc-toggle {
|
|
669
1069
|
position: relative;
|
|
@@ -672,18 +1072,27 @@
|
|
|
672
1072
|
flex-shrink: 0;
|
|
673
1073
|
}
|
|
674
1074
|
|
|
675
|
-
.dc-toggle input {
|
|
1075
|
+
.dc-toggle input {
|
|
1076
|
+
opacity: 0;
|
|
1077
|
+
width: 0;
|
|
1078
|
+
height: 0;
|
|
1079
|
+
}
|
|
676
1080
|
|
|
677
1081
|
.dc-toggle-track {
|
|
678
1082
|
position: absolute;
|
|
679
|
-
top: 0;
|
|
1083
|
+
top: 0;
|
|
1084
|
+
left: 0;
|
|
1085
|
+
right: 0;
|
|
1086
|
+
bottom: 0;
|
|
680
1087
|
background: var(--dc-border);
|
|
681
1088
|
border-radius: 11px;
|
|
682
1089
|
cursor: pointer;
|
|
683
1090
|
transition: background 0.2s;
|
|
684
1091
|
}
|
|
685
1092
|
|
|
686
|
-
.dc-toggle input:checked + .dc-toggle-track {
|
|
1093
|
+
.dc-toggle input:checked + .dc-toggle-track {
|
|
1094
|
+
background: var(--dc-accent);
|
|
1095
|
+
}
|
|
687
1096
|
|
|
688
1097
|
.dc-toggle-track::after {
|
|
689
1098
|
content: '';
|
|
@@ -692,11 +1101,14 @@
|
|
|
692
1101
|
height: 16px;
|
|
693
1102
|
background: white;
|
|
694
1103
|
border-radius: 50%;
|
|
695
|
-
top: 3px;
|
|
1104
|
+
top: 3px;
|
|
1105
|
+
left: 3px;
|
|
696
1106
|
transition: transform 0.2s;
|
|
697
1107
|
}
|
|
698
1108
|
|
|
699
|
-
.dc-toggle input:checked + .dc-toggle-track::after {
|
|
1109
|
+
.dc-toggle input:checked + .dc-toggle-track::after {
|
|
1110
|
+
transform: translateX(18px);
|
|
1111
|
+
}
|
|
700
1112
|
|
|
701
1113
|
.dc-select {
|
|
702
1114
|
background: var(--dc-bg0);
|
|
@@ -708,7 +1120,8 @@
|
|
|
708
1120
|
outline: none;
|
|
709
1121
|
}
|
|
710
1122
|
|
|
711
|
-
/* ── PICK
|
|
1123
|
+
/* ── PICK ─────────────────────────────── */
|
|
1124
|
+
|
|
712
1125
|
.dc-pick-highlight {
|
|
713
1126
|
outline: 2px dashed var(--dc-accent2) !important;
|
|
714
1127
|
outline-offset: 2px;
|
|
@@ -719,24 +1132,29 @@
|
|
|
719
1132
|
style.textContent = css;
|
|
720
1133
|
document.head.appendChild(style);
|
|
721
1134
|
const html = `
|
|
722
|
-
<button id="dc-fab" title="
|
|
1135
|
+
<button id="dc-fab" title="INSIKT">
|
|
723
1136
|
<span id="dc-fab-icon">⌥</span>
|
|
724
1137
|
<span class="dc-fab-badge" id="dc-error-badge">0</span>
|
|
725
1138
|
</button>
|
|
726
1139
|
|
|
727
1140
|
<div id="dc-panel">
|
|
728
1141
|
<div id="dc-drag"></div>
|
|
1142
|
+
|
|
729
1143
|
<div id="dc-header">
|
|
730
|
-
<span id="dc-title">
|
|
1144
|
+
<span id="dc-title">INSIKT</span>
|
|
731
1145
|
<span class="dc-pulse"></span>
|
|
732
1146
|
<button class="dc-hbtn" id="dc-clear-btn" title="Clear active tab">🗑</button>
|
|
733
|
-
<button class="dc-hbtn" id="dc-copy-btn" title="Copy
|
|
1147
|
+
<button class="dc-hbtn" id="dc-copy-btn" title="Copy active tab">📋</button>
|
|
734
1148
|
<button class="dc-hbtn" id="dc-minimize-btn" title="Minimize">−</button>
|
|
735
1149
|
</div>
|
|
736
1150
|
|
|
737
1151
|
<div id="dc-tabs">
|
|
738
|
-
<button class="dc-tab active" data-tab="console">
|
|
739
|
-
|
|
1152
|
+
<button class="dc-tab active" data-tab="console">
|
|
1153
|
+
Console<span class="dc-tab-count" id="cnt-console" style="display:none"></span>
|
|
1154
|
+
</button>
|
|
1155
|
+
<button class="dc-tab" data-tab="network">
|
|
1156
|
+
Network<span class="dc-tab-count" id="cnt-network" style="display:none"></span>
|
|
1157
|
+
</button>
|
|
740
1158
|
<button class="dc-tab" data-tab="storage">Storage</button>
|
|
741
1159
|
<button class="dc-tab" data-tab="dom">DOM</button>
|
|
742
1160
|
<button class="dc-tab" data-tab="system">System</button>
|
|
@@ -745,15 +1163,28 @@
|
|
|
745
1163
|
|
|
746
1164
|
<div class="dc-panel-content active" id="panel-console">
|
|
747
1165
|
<div class="dc-scroll" id="console-output"></div>
|
|
1166
|
+
|
|
748
1167
|
<div class="dc-repl">
|
|
749
|
-
<input
|
|
1168
|
+
<input
|
|
1169
|
+
class="dc-input"
|
|
1170
|
+
id="repl-input"
|
|
1171
|
+
placeholder="▶ execute javascript…"
|
|
1172
|
+
autocomplete="off"
|
|
1173
|
+
autocorrect="off"
|
|
1174
|
+
autocapitalize="off"
|
|
1175
|
+
spellcheck="false"
|
|
1176
|
+
>
|
|
750
1177
|
<button class="dc-run-btn" id="repl-run">RUN</button>
|
|
751
1178
|
</div>
|
|
752
1179
|
</div>
|
|
753
1180
|
|
|
754
1181
|
<div class="dc-panel-content" id="panel-network">
|
|
755
1182
|
<div class="dc-net-filter">
|
|
756
|
-
<input
|
|
1183
|
+
<input
|
|
1184
|
+
class="dc-filter-input"
|
|
1185
|
+
id="net-filter"
|
|
1186
|
+
placeholder="Filter by URL or method…"
|
|
1187
|
+
>
|
|
757
1188
|
<button class="dc-clear-btn" id="net-clear">Clear</button>
|
|
758
1189
|
</div>
|
|
759
1190
|
<div class="dc-scroll" id="network-output"></div>
|
|
@@ -765,9 +1196,11 @@
|
|
|
765
1196
|
<button class="dc-st-btn" data-storage="localstorage">LocalStorage</button>
|
|
766
1197
|
<button class="dc-st-btn" data-storage="sessionstorage">SessionStorage</button>
|
|
767
1198
|
</div>
|
|
1199
|
+
|
|
768
1200
|
<div class="dc-storage-actions">
|
|
769
1201
|
<button class="dc-clear-btn" id="storage-refresh">↺ Refresh</button>
|
|
770
1202
|
</div>
|
|
1203
|
+
|
|
771
1204
|
<div class="dc-scroll" id="storage-output"></div>
|
|
772
1205
|
</div>
|
|
773
1206
|
|
|
@@ -802,6 +1235,8 @@
|
|
|
802
1235
|
replHistory: [],
|
|
803
1236
|
replHistoryIdx: -1,
|
|
804
1237
|
errorCount: 0,
|
|
1238
|
+
groupDepth: 0,
|
|
1239
|
+
nextLogId: 1,
|
|
805
1240
|
settings: {
|
|
806
1241
|
timestamps: true,
|
|
807
1242
|
autoScroll: true,
|
|
@@ -809,19 +1244,23 @@
|
|
|
809
1244
|
fontSize: 12,
|
|
810
1245
|
monitorNetwork: true,
|
|
811
1246
|
captureErrors: true,
|
|
1247
|
+
persistBuffer: false,
|
|
812
1248
|
theme: "dark"
|
|
813
1249
|
}
|
|
814
1250
|
};
|
|
815
1251
|
function saveSettings() {
|
|
816
1252
|
try {
|
|
817
|
-
localStorage.setItem(
|
|
1253
|
+
localStorage.setItem(SETTINGS_KEY, JSON.stringify(S.settings));
|
|
818
1254
|
} catch (e) {
|
|
819
1255
|
}
|
|
820
1256
|
}
|
|
821
1257
|
function loadSettings() {
|
|
822
1258
|
try {
|
|
823
|
-
const saved = localStorage.getItem(
|
|
824
|
-
if (saved)
|
|
1259
|
+
const saved = localStorage.getItem(SETTINGS_KEY);
|
|
1260
|
+
if (saved) {
|
|
1261
|
+
const parsed = JSON.parse(saved);
|
|
1262
|
+
S.settings = { ...S.settings, ...parsed };
|
|
1263
|
+
}
|
|
825
1264
|
} catch (e) {
|
|
826
1265
|
}
|
|
827
1266
|
}
|
|
@@ -846,20 +1285,7 @@
|
|
|
846
1285
|
return `${String(d.getHours()).padStart(2, "0")}:${String(d.getMinutes()).padStart(2, "0")}:${String(d.getSeconds()).padStart(2, "0")}.${String(d.getMilliseconds()).padStart(3, "0")}`;
|
|
847
1286
|
}
|
|
848
1287
|
function escHtml(s) {
|
|
849
|
-
return String(s).replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">");
|
|
850
|
-
}
|
|
851
|
-
function formatArg(a) {
|
|
852
|
-
if (a === null) return '<span style="color:#aaa">null</span>';
|
|
853
|
-
if (a === void 0) return '<span style="color:#aaa">undefined</span>';
|
|
854
|
-
if (typeof a === "object") {
|
|
855
|
-
try {
|
|
856
|
-
const s = JSON.stringify(a, null, 2);
|
|
857
|
-
return `<pre>${escHtml(s)}</pre>`;
|
|
858
|
-
} catch (e) {
|
|
859
|
-
return String(a);
|
|
860
|
-
}
|
|
861
|
-
}
|
|
862
|
-
return escHtml(String(a));
|
|
1288
|
+
return String(s).replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">").replace(/"/g, """).replace(/'/g, "'");
|
|
863
1289
|
}
|
|
864
1290
|
function truncUrl(url, max = 55) {
|
|
865
1291
|
if (!url || url.length <= max) return url;
|
|
@@ -880,15 +1306,337 @@
|
|
|
880
1306
|
function methodClass(m) {
|
|
881
1307
|
return `m-${["GET", "POST", "PUT", "DELETE", "PATCH"].includes(m) ? m : "UNK"}`;
|
|
882
1308
|
}
|
|
1309
|
+
function updateTabCount(tab, n) {
|
|
1310
|
+
const el2 = document.getElementById(`cnt-${tab}`);
|
|
1311
|
+
if (!el2) return;
|
|
1312
|
+
if (n > 0) {
|
|
1313
|
+
el2.textContent = n > 999 ? "999+" : n;
|
|
1314
|
+
el2.style.display = "inline-flex";
|
|
1315
|
+
} else {
|
|
1316
|
+
el2.style.display = "none";
|
|
1317
|
+
}
|
|
1318
|
+
}
|
|
1319
|
+
const SNAPSHOT_DEPTH = 8;
|
|
1320
|
+
const SNAPSHOT_KEYS = 100;
|
|
1321
|
+
function snapshotValue(value, depth = 0, seen = /* @__PURE__ */ new WeakSet()) {
|
|
1322
|
+
if (value === null) {
|
|
1323
|
+
return { kind: "null" };
|
|
1324
|
+
}
|
|
1325
|
+
if (value === void 0) {
|
|
1326
|
+
return { kind: "undefined" };
|
|
1327
|
+
}
|
|
1328
|
+
const type = typeof value;
|
|
1329
|
+
if (type === "string") {
|
|
1330
|
+
return { kind: "string", value };
|
|
1331
|
+
}
|
|
1332
|
+
if (type === "number") {
|
|
1333
|
+
if (Number.isNaN(value)) return { kind: "number", value: "NaN" };
|
|
1334
|
+
if (value === Infinity) return { kind: "number", value: "Infinity" };
|
|
1335
|
+
if (value === -Infinity) return { kind: "number", value: "-Infinity" };
|
|
1336
|
+
return { kind: "number", value };
|
|
1337
|
+
}
|
|
1338
|
+
if (type === "boolean") {
|
|
1339
|
+
return { kind: "boolean", value };
|
|
1340
|
+
}
|
|
1341
|
+
if (type === "bigint") {
|
|
1342
|
+
return { kind: "bigint", value: value.toString() + "n" };
|
|
1343
|
+
}
|
|
1344
|
+
if (type === "symbol") {
|
|
1345
|
+
return { kind: "symbol", value: String(value) };
|
|
1346
|
+
}
|
|
1347
|
+
if (type === "function") {
|
|
1348
|
+
return {
|
|
1349
|
+
kind: "function",
|
|
1350
|
+
value: value.name ? `[Function ${value.name}]` : "[Function]"
|
|
1351
|
+
};
|
|
1352
|
+
}
|
|
1353
|
+
if (type !== "object") {
|
|
1354
|
+
return { kind: "string", value: String(value) };
|
|
1355
|
+
}
|
|
1356
|
+
if (seen.has(value)) {
|
|
1357
|
+
return { kind: "circular" };
|
|
1358
|
+
}
|
|
1359
|
+
if (depth >= SNAPSHOT_DEPTH) {
|
|
1360
|
+
return {
|
|
1361
|
+
kind: "object",
|
|
1362
|
+
ctor: getConstructorName(value),
|
|
1363
|
+
entries: [],
|
|
1364
|
+
truncated: true
|
|
1365
|
+
};
|
|
1366
|
+
}
|
|
1367
|
+
seen.add(value);
|
|
1368
|
+
if (value instanceof Date) {
|
|
1369
|
+
return {
|
|
1370
|
+
kind: "date",
|
|
1371
|
+
value: isNaN(value.getTime()) ? "Invalid Date" : value.toISOString()
|
|
1372
|
+
};
|
|
1373
|
+
}
|
|
1374
|
+
if (value instanceof RegExp) {
|
|
1375
|
+
return {
|
|
1376
|
+
kind: "regexp",
|
|
1377
|
+
value: String(value)
|
|
1378
|
+
};
|
|
1379
|
+
}
|
|
1380
|
+
if (value instanceof Error) {
|
|
1381
|
+
const result2 = {
|
|
1382
|
+
kind: "error",
|
|
1383
|
+
ctor: value.name || "Error",
|
|
1384
|
+
message: String(value.message || ""),
|
|
1385
|
+
stack: value.stack ? String(value.stack) : "",
|
|
1386
|
+
entries: []
|
|
1387
|
+
};
|
|
1388
|
+
try {
|
|
1389
|
+
Object.keys(value).slice(0, SNAPSHOT_KEYS).forEach((key) => {
|
|
1390
|
+
result2.entries.push({
|
|
1391
|
+
key,
|
|
1392
|
+
value: snapshotValue(value[key], depth + 1, seen)
|
|
1393
|
+
});
|
|
1394
|
+
});
|
|
1395
|
+
} catch (e) {
|
|
1396
|
+
}
|
|
1397
|
+
return result2;
|
|
1398
|
+
}
|
|
1399
|
+
if (Array.isArray(value)) {
|
|
1400
|
+
const result2 = {
|
|
1401
|
+
kind: "array",
|
|
1402
|
+
length: value.length,
|
|
1403
|
+
entries: [],
|
|
1404
|
+
truncated: false
|
|
1405
|
+
};
|
|
1406
|
+
const limit2 = Math.min(value.length, SNAPSHOT_KEYS);
|
|
1407
|
+
for (let i = 0; i < limit2; i++) {
|
|
1408
|
+
try {
|
|
1409
|
+
result2.entries.push({
|
|
1410
|
+
key: String(i),
|
|
1411
|
+
index: true,
|
|
1412
|
+
value: snapshotValue(value[i], depth + 1, seen)
|
|
1413
|
+
});
|
|
1414
|
+
} catch (e) {
|
|
1415
|
+
result2.entries.push({
|
|
1416
|
+
key: String(i),
|
|
1417
|
+
index: true,
|
|
1418
|
+
value: { kind: "string", value: "[Uninspectable]" }
|
|
1419
|
+
});
|
|
1420
|
+
}
|
|
1421
|
+
}
|
|
1422
|
+
if (value.length > limit2) result2.truncated = true;
|
|
1423
|
+
seen.delete(value);
|
|
1424
|
+
return result2;
|
|
1425
|
+
}
|
|
1426
|
+
const result = {
|
|
1427
|
+
kind: "object",
|
|
1428
|
+
ctor: getConstructorName(value),
|
|
1429
|
+
entries: [],
|
|
1430
|
+
truncated: false
|
|
1431
|
+
};
|
|
1432
|
+
let keys = [];
|
|
1433
|
+
try {
|
|
1434
|
+
keys = Object.keys(value);
|
|
1435
|
+
} catch (e) {
|
|
1436
|
+
}
|
|
1437
|
+
const limit = Math.min(keys.length, SNAPSHOT_KEYS);
|
|
1438
|
+
for (let i = 0; i < limit; i++) {
|
|
1439
|
+
const key = keys[i];
|
|
1440
|
+
try {
|
|
1441
|
+
result.entries.push({
|
|
1442
|
+
key,
|
|
1443
|
+
value: snapshotValue(value[key], depth + 1, seen)
|
|
1444
|
+
});
|
|
1445
|
+
} catch (e) {
|
|
1446
|
+
result.entries.push({
|
|
1447
|
+
key,
|
|
1448
|
+
value: { kind: "string", value: "[Uninspectable]" }
|
|
1449
|
+
});
|
|
1450
|
+
}
|
|
1451
|
+
}
|
|
1452
|
+
if (keys.length > limit) result.truncated = true;
|
|
1453
|
+
seen.delete(value);
|
|
1454
|
+
return result;
|
|
1455
|
+
}
|
|
1456
|
+
function getConstructorName(value) {
|
|
1457
|
+
try {
|
|
1458
|
+
if (value && value.constructor && value.constructor.name) {
|
|
1459
|
+
return value.constructor.name;
|
|
1460
|
+
}
|
|
1461
|
+
} catch (e) {
|
|
1462
|
+
}
|
|
1463
|
+
return "Object";
|
|
1464
|
+
}
|
|
1465
|
+
function snapshotArgs(args) {
|
|
1466
|
+
return args.map((a) => snapshotValue(a));
|
|
1467
|
+
}
|
|
1468
|
+
function renderValue(value, options = {}) {
|
|
1469
|
+
const node = document.createElement("span");
|
|
1470
|
+
node.className = "dc-value";
|
|
1471
|
+
if (!value || typeof value.kind !== "string") {
|
|
1472
|
+
node.textContent = String(value);
|
|
1473
|
+
return node;
|
|
1474
|
+
}
|
|
1475
|
+
switch (value.kind) {
|
|
1476
|
+
case "null":
|
|
1477
|
+
node.classList.add("dc-primitive-null");
|
|
1478
|
+
node.textContent = "null";
|
|
1479
|
+
return node;
|
|
1480
|
+
case "undefined":
|
|
1481
|
+
node.classList.add("dc-primitive-undefined");
|
|
1482
|
+
node.textContent = "undefined";
|
|
1483
|
+
return node;
|
|
1484
|
+
case "string":
|
|
1485
|
+
node.classList.add("dc-primitive-string");
|
|
1486
|
+
node.textContent = `"${value.value}"`;
|
|
1487
|
+
return node;
|
|
1488
|
+
case "number":
|
|
1489
|
+
node.classList.add("dc-primitive-number");
|
|
1490
|
+
node.textContent = String(value.value);
|
|
1491
|
+
return node;
|
|
1492
|
+
case "boolean":
|
|
1493
|
+
node.classList.add("dc-primitive-boolean");
|
|
1494
|
+
node.textContent = String(value.value);
|
|
1495
|
+
return node;
|
|
1496
|
+
case "bigint":
|
|
1497
|
+
node.classList.add("dc-primitive-bigint");
|
|
1498
|
+
node.textContent = String(value.value);
|
|
1499
|
+
return node;
|
|
1500
|
+
case "symbol":
|
|
1501
|
+
node.classList.add("dc-primitive-symbol");
|
|
1502
|
+
node.textContent = String(value.value);
|
|
1503
|
+
return node;
|
|
1504
|
+
case "function":
|
|
1505
|
+
node.classList.add("dc-primitive-function");
|
|
1506
|
+
node.textContent = String(value.value);
|
|
1507
|
+
return node;
|
|
1508
|
+
case "date":
|
|
1509
|
+
node.classList.add("dc-primitive-string");
|
|
1510
|
+
node.textContent = `Date("${value.value}")`;
|
|
1511
|
+
return node;
|
|
1512
|
+
case "regexp":
|
|
1513
|
+
node.classList.add("dc-primitive-string");
|
|
1514
|
+
node.textContent = value.value;
|
|
1515
|
+
return node;
|
|
1516
|
+
case "circular":
|
|
1517
|
+
node.classList.add("dc-primitive-null");
|
|
1518
|
+
node.textContent = "[Circular]";
|
|
1519
|
+
return node;
|
|
1520
|
+
case "error":
|
|
1521
|
+
return renderExpandableValue(value, {
|
|
1522
|
+
summary: `${value.ctor || "Error"}: ${value.message || ""}`
|
|
1523
|
+
});
|
|
1524
|
+
case "array":
|
|
1525
|
+
return renderExpandableValue(value, {
|
|
1526
|
+
summary: `[${value.length != null ? value.length + " items" : "…"}]`
|
|
1527
|
+
});
|
|
1528
|
+
case "object":
|
|
1529
|
+
return renderExpandableValue(value, {
|
|
1530
|
+
summary: `{${value.ctor && value.ctor !== "Object" ? value.ctor + " " : ""}…}`
|
|
1531
|
+
});
|
|
1532
|
+
default:
|
|
1533
|
+
node.textContent = "[Unknown]";
|
|
1534
|
+
return node;
|
|
1535
|
+
}
|
|
1536
|
+
}
|
|
1537
|
+
function renderExpandableValue(value, options = {}) {
|
|
1538
|
+
const wrap = document.createElement("span");
|
|
1539
|
+
wrap.className = "dc-object-node";
|
|
1540
|
+
const toggle = document.createElement("span");
|
|
1541
|
+
toggle.className = "dc-object-toggle";
|
|
1542
|
+
const arrow = document.createElement("span");
|
|
1543
|
+
arrow.className = "dc-object-arrow";
|
|
1544
|
+
arrow.textContent = "▶";
|
|
1545
|
+
const summary = document.createElement("span");
|
|
1546
|
+
summary.className = "dc-object-summary";
|
|
1547
|
+
summary.textContent = options.summary || "{…}";
|
|
1548
|
+
toggle.appendChild(arrow);
|
|
1549
|
+
toggle.appendChild(summary);
|
|
1550
|
+
const children = document.createElement("div");
|
|
1551
|
+
children.className = "dc-object-children";
|
|
1552
|
+
const entries = Array.isArray(value.entries) ? value.entries : [];
|
|
1553
|
+
entries.forEach((entry) => {
|
|
1554
|
+
const row = document.createElement("div");
|
|
1555
|
+
row.className = "dc-object-row";
|
|
1556
|
+
const key = document.createElement("span");
|
|
1557
|
+
key.className = entry.index ? "dc-object-key-index" : "dc-object-key";
|
|
1558
|
+
key.textContent = entry.index ? `[${entry.key}] ` : `${entry.key}: `;
|
|
1559
|
+
row.appendChild(key);
|
|
1560
|
+
row.appendChild(renderValue(entry.value, {
|
|
1561
|
+
depth: (options.depth || 0) + 1
|
|
1562
|
+
}));
|
|
1563
|
+
children.appendChild(row);
|
|
1564
|
+
});
|
|
1565
|
+
if (value.truncated) {
|
|
1566
|
+
const more = document.createElement("div");
|
|
1567
|
+
more.className = "dc-object-more";
|
|
1568
|
+
more.textContent = "… more";
|
|
1569
|
+
children.appendChild(more);
|
|
1570
|
+
}
|
|
1571
|
+
if (value.kind === "error" && value.stack) {
|
|
1572
|
+
const stack = document.createElement("div");
|
|
1573
|
+
stack.className = "dc-object-more";
|
|
1574
|
+
stack.style.whiteSpace = "pre-wrap";
|
|
1575
|
+
stack.style.marginTop = "4px";
|
|
1576
|
+
stack.textContent = value.stack;
|
|
1577
|
+
children.appendChild(stack);
|
|
1578
|
+
}
|
|
1579
|
+
toggle.addEventListener("click", (e) => {
|
|
1580
|
+
e.stopPropagation();
|
|
1581
|
+
const open = children.classList.toggle("open");
|
|
1582
|
+
arrow.textContent = open ? "▼" : "▶";
|
|
1583
|
+
});
|
|
1584
|
+
wrap.appendChild(toggle);
|
|
1585
|
+
if (entries.length || value.truncated || value.stack) {
|
|
1586
|
+
wrap.appendChild(children);
|
|
1587
|
+
}
|
|
1588
|
+
return wrap;
|
|
1589
|
+
}
|
|
1590
|
+
function renderArgsInto(container, args) {
|
|
1591
|
+
if (!args || !args.length) {
|
|
1592
|
+
container.textContent = "";
|
|
1593
|
+
return;
|
|
1594
|
+
}
|
|
1595
|
+
args.forEach((arg, index) => {
|
|
1596
|
+
if (index > 0) {
|
|
1597
|
+
container.appendChild(document.createTextNode(" "));
|
|
1598
|
+
}
|
|
1599
|
+
container.appendChild(renderValue(arg));
|
|
1600
|
+
});
|
|
1601
|
+
}
|
|
883
1602
|
const _orig = {};
|
|
1603
|
+
["log", "warn", "error", "info", "table", "group", "groupCollapsed", "groupEnd"].forEach((level) => {
|
|
1604
|
+
if (typeof console[level] === "function") {
|
|
1605
|
+
_orig[level] = console[level].bind(console);
|
|
1606
|
+
}
|
|
1607
|
+
});
|
|
884
1608
|
["log", "warn", "error", "info"].forEach((level) => {
|
|
885
|
-
_orig[level]
|
|
1609
|
+
if (!_orig[level]) return;
|
|
886
1610
|
console[level] = (...args) => {
|
|
887
1611
|
_orig[level](...args);
|
|
888
1612
|
addLog(level, args);
|
|
889
1613
|
};
|
|
890
1614
|
});
|
|
891
|
-
|
|
1615
|
+
if (_orig.table) {
|
|
1616
|
+
console.table = (...args) => {
|
|
1617
|
+
_orig.table(...args);
|
|
1618
|
+
addTableLog(args);
|
|
1619
|
+
};
|
|
1620
|
+
}
|
|
1621
|
+
if (_orig.group) {
|
|
1622
|
+
console.group = (...args) => {
|
|
1623
|
+
_orig.group(...args);
|
|
1624
|
+
addGroupLog(false, args);
|
|
1625
|
+
};
|
|
1626
|
+
}
|
|
1627
|
+
if (_orig.groupCollapsed) {
|
|
1628
|
+
console.groupCollapsed = (...args) => {
|
|
1629
|
+
_orig.groupCollapsed(...args);
|
|
1630
|
+
addGroupLog(true, args);
|
|
1631
|
+
};
|
|
1632
|
+
}
|
|
1633
|
+
if (_orig.groupEnd) {
|
|
1634
|
+
console.groupEnd = (...args) => {
|
|
1635
|
+
_orig.groupEnd(...args);
|
|
1636
|
+
S.groupDepth = Math.max(0, S.groupDepth - 1);
|
|
1637
|
+
};
|
|
1638
|
+
}
|
|
1639
|
+
function addLog(type, args, options = {}) {
|
|
892
1640
|
if (type === "error") {
|
|
893
1641
|
S.errorCount++;
|
|
894
1642
|
const b = el.badge();
|
|
@@ -897,139 +1645,763 @@
|
|
|
897
1645
|
b.style.display = "flex";
|
|
898
1646
|
}
|
|
899
1647
|
}
|
|
900
|
-
|
|
901
|
-
|
|
1648
|
+
const entry = {
|
|
1649
|
+
id: S.nextLogId++,
|
|
1650
|
+
type,
|
|
1651
|
+
args: snapshotArgs(args),
|
|
1652
|
+
ts: ts(),
|
|
1653
|
+
groupDepth: options.groupDepth != null ? options.groupDepth : S.groupDepth,
|
|
1654
|
+
restored: false
|
|
1655
|
+
};
|
|
1656
|
+
S.logs.push(entry);
|
|
1657
|
+
trimLogs();
|
|
1658
|
+
persistBuffer();
|
|
1659
|
+
updateTabCount("console", S.logs.length);
|
|
1660
|
+
if (S.activeTab === "console") {
|
|
1661
|
+
renderConsole();
|
|
1662
|
+
}
|
|
1663
|
+
}
|
|
1664
|
+
function addTableLog(args) {
|
|
1665
|
+
const source = args.length > 0 ? args[0] : void 0;
|
|
1666
|
+
const entry = {
|
|
1667
|
+
id: S.nextLogId++,
|
|
1668
|
+
type: "table",
|
|
1669
|
+
args: snapshotArgs(args),
|
|
1670
|
+
table: buildTableSnapshot(source),
|
|
1671
|
+
ts: ts(),
|
|
1672
|
+
groupDepth: S.groupDepth,
|
|
1673
|
+
restored: false
|
|
1674
|
+
};
|
|
1675
|
+
S.logs.push(entry);
|
|
1676
|
+
trimLogs();
|
|
1677
|
+
persistBuffer();
|
|
1678
|
+
updateTabCount("console", S.logs.length);
|
|
1679
|
+
if (S.activeTab === "console") {
|
|
1680
|
+
renderConsole();
|
|
1681
|
+
}
|
|
1682
|
+
}
|
|
1683
|
+
function addGroupLog(collapsed, args) {
|
|
1684
|
+
const depth = S.groupDepth;
|
|
1685
|
+
const entry = {
|
|
1686
|
+
id: S.nextLogId++,
|
|
1687
|
+
type: "group",
|
|
1688
|
+
args: snapshotArgs(args),
|
|
1689
|
+
ts: ts(),
|
|
1690
|
+
groupDepth: depth,
|
|
1691
|
+
collapsed: !!collapsed,
|
|
1692
|
+
restored: false
|
|
1693
|
+
};
|
|
1694
|
+
S.logs.push(entry);
|
|
1695
|
+
S.groupDepth++;
|
|
1696
|
+
trimLogs();
|
|
1697
|
+
persistBuffer();
|
|
902
1698
|
updateTabCount("console", S.logs.length);
|
|
903
|
-
if (S.activeTab === "console")
|
|
1699
|
+
if (S.activeTab === "console") {
|
|
1700
|
+
renderConsole();
|
|
1701
|
+
}
|
|
1702
|
+
}
|
|
1703
|
+
function buildTableSnapshot(source) {
|
|
1704
|
+
if (!Array.isArray(source)) {
|
|
1705
|
+
return {
|
|
1706
|
+
tabular: false,
|
|
1707
|
+
value: snapshotValue(source)
|
|
1708
|
+
};
|
|
1709
|
+
}
|
|
1710
|
+
const rows = source.slice(0, SNAPSHOT_KEYS).map((row, index) => {
|
|
1711
|
+
const cells = {};
|
|
1712
|
+
if (row && typeof row === "object" && !Array.isArray(row)) {
|
|
1713
|
+
Object.keys(row).slice(0, SNAPSHOT_KEYS).forEach((key) => {
|
|
1714
|
+
cells[key] = snapshotValue(row[key]);
|
|
1715
|
+
});
|
|
1716
|
+
} else {
|
|
1717
|
+
cells.value = snapshotValue(row);
|
|
1718
|
+
}
|
|
1719
|
+
return {
|
|
1720
|
+
index,
|
|
1721
|
+
cells
|
|
1722
|
+
};
|
|
1723
|
+
});
|
|
1724
|
+
return {
|
|
1725
|
+
tabular: true,
|
|
1726
|
+
rows,
|
|
1727
|
+
truncated: source.length > rows.length
|
|
1728
|
+
};
|
|
1729
|
+
}
|
|
1730
|
+
function trimLogs() {
|
|
1731
|
+
const max = Math.max(1, Number(S.settings.maxEntries) || 500);
|
|
1732
|
+
while (S.logs.length > max) {
|
|
1733
|
+
S.logs.shift();
|
|
1734
|
+
}
|
|
904
1735
|
}
|
|
905
1736
|
function renderConsole() {
|
|
906
1737
|
const o = el.consOut();
|
|
907
1738
|
if (!o) return;
|
|
1739
|
+
o.innerHTML = "";
|
|
1740
|
+
if (!S.logs.length) {
|
|
1741
|
+
o.innerHTML = '<div class="dc-empty">No console entries yet</div>';
|
|
1742
|
+
return;
|
|
1743
|
+
}
|
|
908
1744
|
const frag = document.createDocumentFragment();
|
|
909
|
-
|
|
910
|
-
|
|
911
|
-
|
|
912
|
-
|
|
913
|
-
|
|
914
|
-
|
|
915
|
-
|
|
916
|
-
|
|
1745
|
+
let previousRestored = null;
|
|
1746
|
+
let skipUntil = -1;
|
|
1747
|
+
S.logs.forEach((log, index) => {
|
|
1748
|
+
if (!log.restored && previousRestored === true) {
|
|
1749
|
+
frag.appendChild(createReloadSeparator());
|
|
1750
|
+
}
|
|
1751
|
+
previousRestored = !!log.restored;
|
|
1752
|
+
if (index < skipUntil) return;
|
|
1753
|
+
const entry = createConsoleEntry(log, index);
|
|
1754
|
+
if (entry) {
|
|
1755
|
+
frag.appendChild(entry);
|
|
1756
|
+
if (log.type === "group" && entry.dataset.groupEnd) {
|
|
1757
|
+
skipUntil = parseInt(entry.dataset.groupEnd, 10);
|
|
1758
|
+
}
|
|
1759
|
+
}
|
|
917
1760
|
});
|
|
918
|
-
o.innerHTML = "";
|
|
919
1761
|
o.appendChild(frag);
|
|
920
|
-
if (S.settings.autoScroll)
|
|
1762
|
+
if (S.settings.autoScroll) {
|
|
1763
|
+
o.scrollTop = o.scrollHeight;
|
|
1764
|
+
}
|
|
921
1765
|
}
|
|
922
|
-
|
|
923
|
-
|
|
924
|
-
|
|
1766
|
+
function createReloadSeparator() {
|
|
1767
|
+
const separator = document.createElement("div");
|
|
1768
|
+
separator.className = "dc-reload-separator";
|
|
1769
|
+
separator.textContent = "reloaded";
|
|
1770
|
+
return separator;
|
|
1771
|
+
}
|
|
1772
|
+
function createConsoleEntry(log, index) {
|
|
1773
|
+
if (log.type === "group") {
|
|
1774
|
+
return createGroupEntry(log, index);
|
|
1775
|
+
}
|
|
1776
|
+
if (log.type === "table") {
|
|
1777
|
+
return createTableEntry(log);
|
|
1778
|
+
}
|
|
1779
|
+
const d = document.createElement("div");
|
|
1780
|
+
d.className = `dc-entry dc-entry-${log.type}`;
|
|
1781
|
+
if (log.groupDepth > 0) {
|
|
1782
|
+
d.classList.add("dc-grouped");
|
|
1783
|
+
}
|
|
1784
|
+
d.style.fontSize = S.settings.fontSize + "px";
|
|
1785
|
+
if (S.settings.timestamps) {
|
|
1786
|
+
const timestamp = document.createElement("span");
|
|
1787
|
+
timestamp.className = "dc-ts";
|
|
1788
|
+
timestamp.textContent = log.ts;
|
|
1789
|
+
d.appendChild(timestamp);
|
|
1790
|
+
}
|
|
1791
|
+
const body = document.createElement("span");
|
|
1792
|
+
body.className = "dc-entry-body";
|
|
1793
|
+
renderArgsInto(body, log.args);
|
|
1794
|
+
d.appendChild(body);
|
|
1795
|
+
return d;
|
|
1796
|
+
}
|
|
1797
|
+
function createGroupEntry(log, index) {
|
|
1798
|
+
const d = document.createElement("div");
|
|
1799
|
+
d.className = "dc-entry dc-entry-group";
|
|
1800
|
+
d.style.fontSize = S.settings.fontSize + "px";
|
|
1801
|
+
const arrow = document.createElement("span");
|
|
1802
|
+
arrow.className = "dc-group-arrow";
|
|
1803
|
+
arrow.textContent = "▶";
|
|
1804
|
+
const label = document.createElement("span");
|
|
1805
|
+
label.className = "dc-entry-body";
|
|
1806
|
+
renderArgsInto(label, log.args);
|
|
1807
|
+
if (S.settings.timestamps) {
|
|
1808
|
+
const timestamp = document.createElement("span");
|
|
1809
|
+
timestamp.className = "dc-ts";
|
|
1810
|
+
timestamp.textContent = log.ts;
|
|
1811
|
+
d.appendChild(timestamp);
|
|
1812
|
+
}
|
|
1813
|
+
d.appendChild(arrow);
|
|
1814
|
+
d.appendChild(label);
|
|
1815
|
+
const children = document.createElement("div");
|
|
1816
|
+
children.className = "dc-group-children";
|
|
1817
|
+
const end = findGroupEnd(index, log.groupDepth);
|
|
1818
|
+
if (end > index + 1) {
|
|
1819
|
+
const childFrag = document.createDocumentFragment();
|
|
1820
|
+
for (let i = index + 1; i < end; i++) {
|
|
1821
|
+
const child = createConsoleEntry(S.logs[i], i);
|
|
1822
|
+
if (child) {
|
|
1823
|
+
childFrag.appendChild(child);
|
|
1824
|
+
}
|
|
1825
|
+
}
|
|
1826
|
+
children.appendChild(childFrag);
|
|
1827
|
+
if (log.collapsed) {
|
|
1828
|
+
children.classList.add("collapsed");
|
|
1829
|
+
} else {
|
|
1830
|
+
arrow.classList.add("open");
|
|
1831
|
+
}
|
|
1832
|
+
d.addEventListener("click", (e) => {
|
|
1833
|
+
e.stopPropagation();
|
|
1834
|
+
const collapsed = children.classList.toggle("collapsed");
|
|
1835
|
+
arrow.classList.toggle("open", !collapsed);
|
|
1836
|
+
});
|
|
1837
|
+
d.dataset.groupEnd = String(end);
|
|
1838
|
+
d.appendChild(children);
|
|
1839
|
+
}
|
|
1840
|
+
return d;
|
|
1841
|
+
}
|
|
1842
|
+
function findGroupEnd(index, depth) {
|
|
1843
|
+
for (let i = index + 1; i < S.logs.length; i++) {
|
|
1844
|
+
const candidate = S.logs[i];
|
|
1845
|
+
if (candidate.type === "group" && candidate.groupDepth <= depth) {
|
|
1846
|
+
return i;
|
|
1847
|
+
}
|
|
1848
|
+
if (candidate.groupDepth < depth) {
|
|
1849
|
+
return i;
|
|
1850
|
+
}
|
|
1851
|
+
}
|
|
1852
|
+
return S.logs.length;
|
|
1853
|
+
}
|
|
1854
|
+
function createTableEntry(log) {
|
|
1855
|
+
const d = document.createElement("div");
|
|
1856
|
+
d.className = "dc-entry dc-entry-table";
|
|
1857
|
+
if (log.groupDepth > 0) {
|
|
1858
|
+
d.classList.add("dc-grouped");
|
|
1859
|
+
}
|
|
1860
|
+
d.style.fontSize = S.settings.fontSize + "px";
|
|
1861
|
+
if (S.settings.timestamps) {
|
|
1862
|
+
const timestamp = document.createElement("span");
|
|
1863
|
+
timestamp.className = "dc-ts";
|
|
1864
|
+
timestamp.textContent = log.ts;
|
|
1865
|
+
d.appendChild(timestamp);
|
|
1866
|
+
}
|
|
1867
|
+
const body = document.createElement("div");
|
|
1868
|
+
body.className = "dc-entry-body";
|
|
1869
|
+
const tableData = log.table;
|
|
1870
|
+
if (!tableData || !tableData.tabular) {
|
|
1871
|
+
renderArgsInto(body, log.args);
|
|
1872
|
+
d.appendChild(body);
|
|
1873
|
+
return d;
|
|
1874
|
+
}
|
|
1875
|
+
const wrap = document.createElement("div");
|
|
1876
|
+
wrap.className = "dc-table-wrap";
|
|
1877
|
+
const table = document.createElement("table");
|
|
1878
|
+
table.className = "dc-console-table";
|
|
1879
|
+
const columns = /* @__PURE__ */ new Set();
|
|
1880
|
+
tableData.rows.forEach((row) => {
|
|
1881
|
+
Object.keys(row.cells).forEach((key) => columns.add(key));
|
|
1882
|
+
});
|
|
1883
|
+
const columnList = [...columns];
|
|
1884
|
+
const thead = document.createElement("thead");
|
|
1885
|
+
const headRow = document.createElement("tr");
|
|
1886
|
+
const indexHead = document.createElement("th");
|
|
1887
|
+
indexHead.textContent = "(index)";
|
|
1888
|
+
headRow.appendChild(indexHead);
|
|
1889
|
+
columnList.forEach((column) => {
|
|
1890
|
+
const th = document.createElement("th");
|
|
1891
|
+
th.textContent = column;
|
|
1892
|
+
headRow.appendChild(th);
|
|
1893
|
+
});
|
|
1894
|
+
thead.appendChild(headRow);
|
|
1895
|
+
table.appendChild(thead);
|
|
1896
|
+
const tbody = document.createElement("tbody");
|
|
1897
|
+
tableData.rows.forEach((row) => {
|
|
1898
|
+
const tr = document.createElement("tr");
|
|
1899
|
+
const indexCell = document.createElement("td");
|
|
1900
|
+
indexCell.textContent = String(row.index);
|
|
1901
|
+
tr.appendChild(indexCell);
|
|
1902
|
+
columnList.forEach((column) => {
|
|
1903
|
+
const td = document.createElement("td");
|
|
1904
|
+
if (row.cells[column]) {
|
|
1905
|
+
td.appendChild(renderValue(row.cells[column]));
|
|
1906
|
+
} else {
|
|
1907
|
+
td.textContent = "—";
|
|
1908
|
+
}
|
|
1909
|
+
tr.appendChild(td);
|
|
1910
|
+
});
|
|
1911
|
+
tbody.appendChild(tr);
|
|
1912
|
+
});
|
|
1913
|
+
table.appendChild(tbody);
|
|
1914
|
+
wrap.appendChild(table);
|
|
1915
|
+
body.appendChild(wrap);
|
|
1916
|
+
if (tableData.truncated) {
|
|
1917
|
+
const note = document.createElement("div");
|
|
1918
|
+
note.className = "dc-object-more";
|
|
1919
|
+
note.textContent = "… more rows";
|
|
1920
|
+
body.appendChild(note);
|
|
1921
|
+
}
|
|
1922
|
+
d.appendChild(body);
|
|
1923
|
+
return d;
|
|
1924
|
+
}
|
|
1925
|
+
let _origOnError = window.onerror;
|
|
1926
|
+
function installErrorCapture() {
|
|
1927
|
+
if (!S.settings.captureErrors) return;
|
|
1928
|
+
_origOnError = window.onerror;
|
|
1929
|
+
window.onerror = function(msg, src, line, col, error) {
|
|
1930
|
+
addLog("error", [
|
|
1931
|
+
error || `${msg} @ ${src}:${line}:${col}`
|
|
1932
|
+
]);
|
|
1933
|
+
if (typeof _origOnError === "function") {
|
|
1934
|
+
try {
|
|
1935
|
+
return _origOnError.apply(this, arguments);
|
|
1936
|
+
} catch (e) {
|
|
1937
|
+
}
|
|
1938
|
+
}
|
|
925
1939
|
return false;
|
|
926
1940
|
};
|
|
927
|
-
window.addEventListener("unhandledrejection",
|
|
928
|
-
|
|
929
|
-
|
|
1941
|
+
window.addEventListener("unhandledrejection", onUnhandledRejection);
|
|
1942
|
+
}
|
|
1943
|
+
function onUnhandledRejection(e) {
|
|
1944
|
+
addLog("error", [
|
|
1945
|
+
e.reason instanceof Error ? e.reason : `Unhandled Promise Rejection: ${String(e.reason)}`
|
|
1946
|
+
]);
|
|
930
1947
|
}
|
|
1948
|
+
installErrorCapture();
|
|
931
1949
|
const _origFetch = window.fetch;
|
|
932
|
-
|
|
933
|
-
|
|
934
|
-
|
|
935
|
-
|
|
936
|
-
|
|
937
|
-
|
|
938
|
-
|
|
1950
|
+
function isBinaryContentType(contentType) {
|
|
1951
|
+
if (!contentType) return false;
|
|
1952
|
+
const type = contentType.toLowerCase();
|
|
1953
|
+
return type.includes("application/octet-stream") || type.includes("image/") || type.includes("audio/") || type.includes("video/") || type.includes("application/pdf") || type.includes("application/zip") || type.includes("application/gzip") || type.includes("application/wasm");
|
|
1954
|
+
}
|
|
1955
|
+
function shouldCaptureTextBody(contentType) {
|
|
1956
|
+
if (!contentType) return true;
|
|
1957
|
+
return !isBinaryContentType(contentType);
|
|
1958
|
+
}
|
|
1959
|
+
async function captureRequestBody(input, init) {
|
|
939
1960
|
try {
|
|
940
|
-
|
|
941
|
-
|
|
942
|
-
|
|
943
|
-
|
|
1961
|
+
if (init && init.body != null) {
|
|
1962
|
+
return serializeRequestBody(init.body);
|
|
1963
|
+
}
|
|
1964
|
+
if (input instanceof Request) {
|
|
1965
|
+
const clone = input.clone();
|
|
1966
|
+
if (clone.bodyUsed || !shouldCaptureTextBody(clone.headers.get("content-type"))) {
|
|
1967
|
+
return null;
|
|
1968
|
+
}
|
|
1969
|
+
return await clone.text();
|
|
1970
|
+
}
|
|
1971
|
+
} catch (e) {
|
|
1972
|
+
}
|
|
1973
|
+
return null;
|
|
1974
|
+
}
|
|
1975
|
+
function serializeRequestBody(body) {
|
|
1976
|
+
if (body == null) return null;
|
|
1977
|
+
if (typeof body === "string") {
|
|
1978
|
+
return body;
|
|
1979
|
+
}
|
|
1980
|
+
if (body instanceof URLSearchParams) {
|
|
1981
|
+
return body.toString();
|
|
1982
|
+
}
|
|
1983
|
+
if (body instanceof FormData) {
|
|
1984
|
+
const result = {};
|
|
944
1985
|
try {
|
|
945
|
-
|
|
946
|
-
|
|
1986
|
+
body.forEach((value, key) => {
|
|
1987
|
+
if (value instanceof File) {
|
|
1988
|
+
result[key] = `[File ${value.name}, ${value.size} bytes]`;
|
|
1989
|
+
} else {
|
|
1990
|
+
result[key] = String(value);
|
|
1991
|
+
}
|
|
947
1992
|
});
|
|
948
1993
|
} catch (e) {
|
|
1994
|
+
return "[FormData]";
|
|
949
1995
|
}
|
|
950
|
-
|
|
951
|
-
|
|
1996
|
+
return JSON.stringify(result, null, 2);
|
|
1997
|
+
}
|
|
1998
|
+
if (body instanceof Blob) {
|
|
1999
|
+
return isBinaryContentType(body.type) ? null : `[Blob ${body.type || "unknown"}, ${body.size} bytes]`;
|
|
2000
|
+
}
|
|
2001
|
+
if (body instanceof ArrayBuffer || ArrayBuffer.isView(body)) {
|
|
2002
|
+
return null;
|
|
2003
|
+
}
|
|
2004
|
+
try {
|
|
2005
|
+
return JSON.stringify(body, null, 2);
|
|
952
2006
|
} catch (e) {
|
|
953
|
-
|
|
954
|
-
req.duration = Date.now() - startTime;
|
|
955
|
-
addNetReq(req);
|
|
956
|
-
throw e;
|
|
2007
|
+
return String(body);
|
|
957
2008
|
}
|
|
958
|
-
}
|
|
2009
|
+
}
|
|
2010
|
+
async function captureResponseBody(response) {
|
|
2011
|
+
try {
|
|
2012
|
+
const contentType = response.headers.get("content-type") || "";
|
|
2013
|
+
if (!shouldCaptureTextBody(contentType)) {
|
|
2014
|
+
return null;
|
|
2015
|
+
}
|
|
2016
|
+
const clone = response.clone();
|
|
2017
|
+
if (clone.bodyUsed) return null;
|
|
2018
|
+
return await clone.text();
|
|
2019
|
+
} catch (e) {
|
|
2020
|
+
return null;
|
|
2021
|
+
}
|
|
2022
|
+
}
|
|
2023
|
+
if (_origFetch) {
|
|
2024
|
+
window.fetch = async (...args) => {
|
|
2025
|
+
if (!S.settings.monitorNetwork) {
|
|
2026
|
+
return _origFetch.apply(window, args);
|
|
2027
|
+
}
|
|
2028
|
+
const startTime = Date.now();
|
|
2029
|
+
let method = "GET";
|
|
2030
|
+
let url = "";
|
|
2031
|
+
try {
|
|
2032
|
+
url = args[0] instanceof Request ? args[0].url : String(args[0]);
|
|
2033
|
+
if (args[1] && args[1].method) {
|
|
2034
|
+
method = String(args[1].method).toUpperCase();
|
|
2035
|
+
}
|
|
2036
|
+
if (args[0] instanceof Request) {
|
|
2037
|
+
method = args[0].method.toUpperCase();
|
|
2038
|
+
}
|
|
2039
|
+
} catch (e) {
|
|
2040
|
+
url = String(args[0]);
|
|
2041
|
+
}
|
|
2042
|
+
const req = {
|
|
2043
|
+
method,
|
|
2044
|
+
url,
|
|
2045
|
+
ts: ts(),
|
|
2046
|
+
startTime,
|
|
2047
|
+
status: null,
|
|
2048
|
+
statusText: "",
|
|
2049
|
+
duration: null,
|
|
2050
|
+
headers: {},
|
|
2051
|
+
requestHeaders: {},
|
|
2052
|
+
requestBody: null,
|
|
2053
|
+
responseBody: null,
|
|
2054
|
+
error: null
|
|
2055
|
+
};
|
|
2056
|
+
try {
|
|
2057
|
+
const request = args[0] instanceof Request ? args[0] : new Request(url, args[1]);
|
|
2058
|
+
request.headers.forEach((v, k) => {
|
|
2059
|
+
req.requestHeaders[k] = v;
|
|
2060
|
+
});
|
|
2061
|
+
} catch (e) {
|
|
2062
|
+
}
|
|
2063
|
+
req.requestBody = await captureRequestBody(args[0], args[1]);
|
|
2064
|
+
try {
|
|
2065
|
+
const res = await _origFetch.apply(window, args);
|
|
2066
|
+
req.status = res.status;
|
|
2067
|
+
req.statusText = res.statusText;
|
|
2068
|
+
req.duration = Date.now() - startTime;
|
|
2069
|
+
try {
|
|
2070
|
+
res.headers.forEach((v, k) => {
|
|
2071
|
+
req.headers[k] = v;
|
|
2072
|
+
});
|
|
2073
|
+
} catch (e) {
|
|
2074
|
+
}
|
|
2075
|
+
addNetReq(req);
|
|
2076
|
+
captureResponseBody(res).then((body) => {
|
|
2077
|
+
if (body == null) return;
|
|
2078
|
+
req.responseBody = body;
|
|
2079
|
+
if (S.activeTab === "network") {
|
|
2080
|
+
renderNetwork();
|
|
2081
|
+
}
|
|
2082
|
+
persistBuffer();
|
|
2083
|
+
}).catch(() => {
|
|
2084
|
+
});
|
|
2085
|
+
return res;
|
|
2086
|
+
} catch (e) {
|
|
2087
|
+
req.error = e && e.message ? e.message : String(e);
|
|
2088
|
+
req.duration = Date.now() - startTime;
|
|
2089
|
+
addNetReq(req);
|
|
2090
|
+
throw e;
|
|
2091
|
+
}
|
|
2092
|
+
};
|
|
2093
|
+
}
|
|
959
2094
|
const _origOpen = XMLHttpRequest.prototype.open;
|
|
960
2095
|
const _origSend = XMLHttpRequest.prototype.send;
|
|
961
2096
|
XMLHttpRequest.prototype.open = function(method, url) {
|
|
962
|
-
|
|
2097
|
+
if (!S.settings.monitorNetwork) {
|
|
2098
|
+
return _origOpen.apply(this, arguments);
|
|
2099
|
+
}
|
|
2100
|
+
this.__dcReq = {
|
|
2101
|
+
method: String(method).toUpperCase(),
|
|
2102
|
+
url: String(url),
|
|
2103
|
+
ts: ts(),
|
|
2104
|
+
startTime: 0,
|
|
2105
|
+
requestBody: null,
|
|
2106
|
+
responseBody: null,
|
|
2107
|
+
requestHeaders: {}
|
|
2108
|
+
};
|
|
963
2109
|
return _origOpen.apply(this, arguments);
|
|
964
2110
|
};
|
|
965
|
-
XMLHttpRequest.prototype.
|
|
2111
|
+
const _origSetRequestHeader = XMLHttpRequest.prototype.setRequestHeader;
|
|
2112
|
+
XMLHttpRequest.prototype.setRequestHeader = function(name, value) {
|
|
966
2113
|
if (this.__dcReq) {
|
|
967
|
-
|
|
968
|
-
req.startTime = Date.now();
|
|
969
|
-
this.addEventListener("loadend", () => {
|
|
970
|
-
req.status = this.status;
|
|
971
|
-
req.statusText = this.statusText;
|
|
972
|
-
req.duration = Date.now() - req.startTime;
|
|
973
|
-
req.headers = {};
|
|
974
|
-
const raw = this.getAllResponseHeaders();
|
|
975
|
-
if (raw) raw.split("\r\n").filter(Boolean).forEach((line) => {
|
|
976
|
-
const i = line.indexOf(": ");
|
|
977
|
-
if (i > 0) req.headers[line.slice(0, i)] = line.slice(i + 2);
|
|
978
|
-
});
|
|
979
|
-
req.error = this.status === 0 ? "Request failed" : null;
|
|
980
|
-
addNetReq(req);
|
|
981
|
-
});
|
|
2114
|
+
this.__dcReq.requestHeaders[name] = String(value);
|
|
982
2115
|
}
|
|
2116
|
+
return _origSetRequestHeader.apply(this, arguments);
|
|
2117
|
+
};
|
|
2118
|
+
XMLHttpRequest.prototype.send = function(body) {
|
|
2119
|
+
if (!S.settings.monitorNetwork || !this.__dcReq) {
|
|
2120
|
+
return _origSend.apply(this, arguments);
|
|
2121
|
+
}
|
|
2122
|
+
const req = this.__dcReq;
|
|
2123
|
+
req.startTime = Date.now();
|
|
2124
|
+
req.requestBody = serializeRequestBody(body);
|
|
2125
|
+
this.addEventListener("loadend", () => {
|
|
2126
|
+
req.status = this.status;
|
|
2127
|
+
req.statusText = this.statusText;
|
|
2128
|
+
req.duration = Date.now() - req.startTime;
|
|
2129
|
+
req.headers = {};
|
|
2130
|
+
try {
|
|
2131
|
+
const raw = this.getAllResponseHeaders();
|
|
2132
|
+
if (raw) {
|
|
2133
|
+
raw.split("\r\n").filter(Boolean).forEach((line) => {
|
|
2134
|
+
const i = line.indexOf(": ");
|
|
2135
|
+
if (i > 0) {
|
|
2136
|
+
req.headers[line.slice(0, i)] = line.slice(i + 2);
|
|
2137
|
+
}
|
|
2138
|
+
});
|
|
2139
|
+
}
|
|
2140
|
+
} catch (e) {
|
|
2141
|
+
}
|
|
2142
|
+
req.error = this.status === 0 ? "Request failed" : null;
|
|
2143
|
+
try {
|
|
2144
|
+
const responseType = this.responseType || "";
|
|
2145
|
+
if (responseType === "" || responseType === "text") {
|
|
2146
|
+
const contentType = req.headers["content-type"] || "";
|
|
2147
|
+
if (shouldCaptureTextBody(contentType)) {
|
|
2148
|
+
req.responseBody = this.responseText || null;
|
|
2149
|
+
}
|
|
2150
|
+
}
|
|
2151
|
+
} catch (e) {
|
|
2152
|
+
}
|
|
2153
|
+
addNetReq(req);
|
|
2154
|
+
});
|
|
983
2155
|
return _origSend.apply(this, arguments);
|
|
984
2156
|
};
|
|
985
2157
|
function addNetReq(req) {
|
|
986
2158
|
S.network.unshift(req);
|
|
987
|
-
if (S.network.length > S.settings.maxEntries)
|
|
2159
|
+
if (S.network.length > S.settings.maxEntries) {
|
|
2160
|
+
S.network.pop();
|
|
2161
|
+
}
|
|
2162
|
+
persistBuffer();
|
|
988
2163
|
updateTabCount("network", S.network.length);
|
|
989
|
-
if (S.activeTab === "network")
|
|
2164
|
+
if (S.activeTab === "network") {
|
|
2165
|
+
renderNetwork();
|
|
2166
|
+
}
|
|
990
2167
|
}
|
|
991
2168
|
function renderNetwork(filter) {
|
|
992
2169
|
const o = el.netOut();
|
|
993
2170
|
if (!o) return;
|
|
994
2171
|
filter = filter !== void 0 ? filter : el.netFlt() ? el.netFlt().value : "";
|
|
995
|
-
const
|
|
996
|
-
|
|
997
|
-
|
|
998
|
-
|
|
999
|
-
|
|
1000
|
-
|
|
1001
|
-
|
|
1002
|
-
return
|
|
1003
|
-
|
|
1004
|
-
|
|
1005
|
-
|
|
1006
|
-
|
|
1007
|
-
|
|
1008
|
-
|
|
1009
|
-
|
|
1010
|
-
|
|
1011
|
-
|
|
1012
|
-
|
|
1013
|
-
|
|
1014
|
-
|
|
1015
|
-
|
|
1016
|
-
|
|
1017
|
-
|
|
1018
|
-
|
|
1019
|
-
|
|
1020
|
-
|
|
1021
|
-
|
|
1022
|
-
|
|
1023
|
-
|
|
1024
|
-
|
|
1025
|
-
|
|
1026
|
-
const
|
|
1027
|
-
|
|
1028
|
-
|
|
1029
|
-
|
|
1030
|
-
detail.
|
|
1031
|
-
|
|
1032
|
-
|
|
2172
|
+
const needle = filter.trim().toLowerCase();
|
|
2173
|
+
const filtered = needle ? S.network.filter(
|
|
2174
|
+
(r) => String(r.url).toLowerCase().includes(needle) || String(r.method).toLowerCase().includes(needle)
|
|
2175
|
+
) : S.network;
|
|
2176
|
+
o.innerHTML = "";
|
|
2177
|
+
if (!filtered.length) {
|
|
2178
|
+
o.innerHTML = '<div class="dc-empty">No requests captured yet</div>';
|
|
2179
|
+
return;
|
|
2180
|
+
}
|
|
2181
|
+
filtered.forEach((req) => {
|
|
2182
|
+
o.appendChild(createNetworkEntry(req));
|
|
2183
|
+
});
|
|
2184
|
+
}
|
|
2185
|
+
function createNetworkEntry(req) {
|
|
2186
|
+
const card = document.createElement("div");
|
|
2187
|
+
card.className = "dc-req";
|
|
2188
|
+
const top = document.createElement("div");
|
|
2189
|
+
top.className = "dc-req-top";
|
|
2190
|
+
const method = document.createElement("span");
|
|
2191
|
+
method.className = `dc-method ${methodClass(req.method)}`;
|
|
2192
|
+
method.textContent = req.method;
|
|
2193
|
+
const url = document.createElement("span");
|
|
2194
|
+
url.className = "dc-req-url";
|
|
2195
|
+
url.title = req.url;
|
|
2196
|
+
url.textContent = truncUrl(req.url);
|
|
2197
|
+
const status = document.createElement("span");
|
|
2198
|
+
status.className = `dc-req-status ${req.error ? "s-err" : statusClass(req.status)}`;
|
|
2199
|
+
status.textContent = req.status ? String(req.status) : req.error ? "ERR" : "…";
|
|
2200
|
+
top.appendChild(method);
|
|
2201
|
+
top.appendChild(url);
|
|
2202
|
+
top.appendChild(status);
|
|
2203
|
+
const meta = document.createElement("div");
|
|
2204
|
+
meta.className = "dc-req-meta";
|
|
2205
|
+
const dur = req.duration != null ? `${req.duration}ms · ` : "";
|
|
2206
|
+
meta.textContent = `${dur}${req.ts}` + (req.error ? ` · ${req.error}` : "");
|
|
2207
|
+
const detail = document.createElement("div");
|
|
2208
|
+
detail.className = "dc-req-detail";
|
|
2209
|
+
buildNetworkDetail(detail, req);
|
|
2210
|
+
card.appendChild(top);
|
|
2211
|
+
card.appendChild(meta);
|
|
2212
|
+
card.appendChild(detail);
|
|
2213
|
+
card.addEventListener("click", (e) => {
|
|
2214
|
+
if (e.target.closest(".dc-body-toggle")) return;
|
|
2215
|
+
const open = detail.classList.toggle("open");
|
|
2216
|
+
card.classList.toggle("expanded", open);
|
|
2217
|
+
});
|
|
2218
|
+
return card;
|
|
2219
|
+
}
|
|
2220
|
+
function buildNetworkDetail(detail, req) {
|
|
2221
|
+
addDetailSection(detail, "General", [
|
|
2222
|
+
["URL", req.url],
|
|
2223
|
+
["Method", req.method],
|
|
2224
|
+
["Status", `${req.status || req.error || "–"} ${req.statusText || ""}`],
|
|
2225
|
+
["Duration", req.duration != null ? `${req.duration}ms` : "–"]
|
|
2226
|
+
]);
|
|
2227
|
+
addHeaderSection(
|
|
2228
|
+
detail,
|
|
2229
|
+
"Request Headers",
|
|
2230
|
+
req.requestHeaders
|
|
2231
|
+
);
|
|
2232
|
+
addBodySection(
|
|
2233
|
+
detail,
|
|
2234
|
+
"Request Body",
|
|
2235
|
+
req.requestBody
|
|
2236
|
+
);
|
|
2237
|
+
addHeaderSection(
|
|
2238
|
+
detail,
|
|
2239
|
+
"Response Headers",
|
|
2240
|
+
req.headers
|
|
2241
|
+
);
|
|
2242
|
+
addBodySection(
|
|
2243
|
+
detail,
|
|
2244
|
+
"Response Body",
|
|
2245
|
+
req.responseBody
|
|
2246
|
+
);
|
|
2247
|
+
}
|
|
2248
|
+
function addDetailSection(parent, title, rows) {
|
|
2249
|
+
const section = document.createElement("div");
|
|
2250
|
+
section.className = "dc-detail-section";
|
|
2251
|
+
const heading = document.createElement("div");
|
|
2252
|
+
heading.className = "dc-detail-title";
|
|
2253
|
+
heading.textContent = title;
|
|
2254
|
+
section.appendChild(heading);
|
|
2255
|
+
rows.forEach(([key, value]) => {
|
|
2256
|
+
const row = document.createElement("div");
|
|
2257
|
+
row.className = "dc-detail-row";
|
|
2258
|
+
const keyEl = document.createElement("span");
|
|
2259
|
+
keyEl.className = "dc-detail-key";
|
|
2260
|
+
keyEl.textContent = `${key}: `;
|
|
2261
|
+
row.appendChild(keyEl);
|
|
2262
|
+
row.appendChild(document.createTextNode(String(value ?? "–")));
|
|
2263
|
+
section.appendChild(row);
|
|
2264
|
+
});
|
|
2265
|
+
parent.appendChild(section);
|
|
2266
|
+
}
|
|
2267
|
+
function addHeaderSection(parent, title, headers) {
|
|
2268
|
+
const section = document.createElement("div");
|
|
2269
|
+
section.className = "dc-detail-section";
|
|
2270
|
+
const heading = document.createElement("div");
|
|
2271
|
+
heading.className = "dc-detail-title";
|
|
2272
|
+
heading.textContent = title;
|
|
2273
|
+
section.appendChild(heading);
|
|
2274
|
+
const entries = headers ? Object.entries(headers) : [];
|
|
2275
|
+
if (!entries.length) {
|
|
2276
|
+
const empty = document.createElement("div");
|
|
2277
|
+
empty.className = "dc-detail-row";
|
|
2278
|
+
empty.style.color = "var(--dc-text2)";
|
|
2279
|
+
empty.textContent = "none";
|
|
2280
|
+
section.appendChild(empty);
|
|
2281
|
+
} else {
|
|
2282
|
+
entries.forEach(([key, value]) => {
|
|
2283
|
+
const row = document.createElement("div");
|
|
2284
|
+
row.className = "dc-detail-row";
|
|
2285
|
+
const keyEl = document.createElement("span");
|
|
2286
|
+
keyEl.className = "dc-detail-key";
|
|
2287
|
+
keyEl.textContent = `${key}: `;
|
|
2288
|
+
row.appendChild(keyEl);
|
|
2289
|
+
row.appendChild(document.createTextNode(String(value)));
|
|
2290
|
+
section.appendChild(row);
|
|
2291
|
+
});
|
|
2292
|
+
}
|
|
2293
|
+
parent.appendChild(section);
|
|
2294
|
+
}
|
|
2295
|
+
function addBodySection(parent, title, body) {
|
|
2296
|
+
if (body == null || body === "") return;
|
|
2297
|
+
const section = document.createElement("div");
|
|
2298
|
+
section.className = "dc-detail-section";
|
|
2299
|
+
const heading = document.createElement("div");
|
|
2300
|
+
heading.className = "dc-detail-title";
|
|
2301
|
+
heading.textContent = title;
|
|
2302
|
+
section.appendChild(heading);
|
|
2303
|
+
const block = document.createElement("div");
|
|
2304
|
+
block.className = "dc-body-block";
|
|
2305
|
+
const text = String(body);
|
|
2306
|
+
if (text.length <= BODY_DISPLAY_LIMIT) {
|
|
2307
|
+
const pre = document.createElement("pre");
|
|
2308
|
+
pre.className = "dc-body-pre";
|
|
2309
|
+
pre.textContent = formatBodyForDisplay(text);
|
|
2310
|
+
block.appendChild(pre);
|
|
2311
|
+
} else {
|
|
2312
|
+
const preview = document.createElement("pre");
|
|
2313
|
+
preview.className = "dc-body-pre";
|
|
2314
|
+
preview.textContent = formatBodyForDisplay(text.slice(0, BODY_DISPLAY_LIMIT)) + "\n…";
|
|
2315
|
+
const full = document.createElement("pre");
|
|
2316
|
+
full.className = "dc-body-full";
|
|
2317
|
+
full.textContent = formatBodyForDisplay(text);
|
|
2318
|
+
const note = document.createElement("div");
|
|
2319
|
+
note.className = "dc-body-truncated";
|
|
2320
|
+
note.textContent = `Showing first 10 KB of ${formatBytes(text.length)}.`;
|
|
2321
|
+
const toggle = document.createElement("button");
|
|
2322
|
+
toggle.className = "dc-body-toggle";
|
|
2323
|
+
toggle.textContent = "Show full";
|
|
2324
|
+
toggle.addEventListener("click", (e) => {
|
|
2325
|
+
e.stopPropagation();
|
|
2326
|
+
const open = full.classList.toggle("open");
|
|
2327
|
+
toggle.textContent = open ? "Hide full" : "Show full";
|
|
2328
|
+
});
|
|
2329
|
+
block.appendChild(preview);
|
|
2330
|
+
block.appendChild(note);
|
|
2331
|
+
block.appendChild(toggle);
|
|
2332
|
+
block.appendChild(full);
|
|
2333
|
+
}
|
|
2334
|
+
section.appendChild(block);
|
|
2335
|
+
parent.appendChild(section);
|
|
2336
|
+
}
|
|
2337
|
+
function formatBodyForDisplay(text) {
|
|
2338
|
+
const trimmed = text.trim();
|
|
2339
|
+
if (trimmed.startsWith("{") && trimmed.endsWith("}") || trimmed.startsWith("[") && trimmed.endsWith("]")) {
|
|
2340
|
+
try {
|
|
2341
|
+
return JSON.stringify(JSON.parse(trimmed), null, 2);
|
|
2342
|
+
} catch (e) {
|
|
2343
|
+
}
|
|
2344
|
+
}
|
|
2345
|
+
return text;
|
|
2346
|
+
}
|
|
2347
|
+
function formatBytes(bytes) {
|
|
2348
|
+
if (bytes < 1024) return `${bytes} B`;
|
|
2349
|
+
if (bytes < 1024 * 1024) return `${(bytes / 1024).toFixed(1)} KB`;
|
|
2350
|
+
return `${(bytes / 1024 / 1024).toFixed(1)} MB`;
|
|
2351
|
+
}
|
|
2352
|
+
function persistBuffer() {
|
|
2353
|
+
if (!S.settings.persistBuffer) return;
|
|
2354
|
+
try {
|
|
2355
|
+
const payload = {
|
|
2356
|
+
version: VERSION,
|
|
2357
|
+
savedAt: Date.now(),
|
|
2358
|
+
logs: S.logs.slice(-S.settings.maxEntries),
|
|
2359
|
+
network: S.network.slice(0, S.settings.maxEntries)
|
|
2360
|
+
};
|
|
2361
|
+
sessionStorage.setItem(
|
|
2362
|
+
BUFFER_KEY,
|
|
2363
|
+
JSON.stringify(payload)
|
|
2364
|
+
);
|
|
2365
|
+
} catch (e) {
|
|
2366
|
+
}
|
|
2367
|
+
}
|
|
2368
|
+
function restoreBuffer() {
|
|
2369
|
+
if (!S.settings.persistBuffer) return;
|
|
2370
|
+
try {
|
|
2371
|
+
const raw = sessionStorage.getItem(BUFFER_KEY);
|
|
2372
|
+
if (!raw) return;
|
|
2373
|
+
const payload = JSON.parse(raw);
|
|
2374
|
+
if (!payload || typeof payload !== "object") return;
|
|
2375
|
+
if (Array.isArray(payload.logs)) {
|
|
2376
|
+
S.logs = payload.logs.map((log) => ({
|
|
2377
|
+
...log,
|
|
2378
|
+
restored: true
|
|
2379
|
+
}));
|
|
2380
|
+
}
|
|
2381
|
+
if (Array.isArray(payload.network)) {
|
|
2382
|
+
S.network = payload.network;
|
|
2383
|
+
}
|
|
2384
|
+
S.logs.forEach((log) => {
|
|
2385
|
+
if (log.id >= S.nextLogId) {
|
|
2386
|
+
S.nextLogId = log.id + 1;
|
|
2387
|
+
}
|
|
2388
|
+
});
|
|
2389
|
+
updateTabCount("console", S.logs.length);
|
|
2390
|
+
updateTabCount("network", S.network.length);
|
|
2391
|
+
} catch (e) {
|
|
2392
|
+
try {
|
|
2393
|
+
sessionStorage.removeItem(BUFFER_KEY);
|
|
2394
|
+
} catch (err) {
|
|
2395
|
+
}
|
|
2396
|
+
}
|
|
2397
|
+
}
|
|
2398
|
+
function clearPersistentBuffer() {
|
|
2399
|
+
try {
|
|
2400
|
+
sessionStorage.removeItem(BUFFER_KEY);
|
|
2401
|
+
} catch (e) {
|
|
2402
|
+
}
|
|
2403
|
+
}
|
|
2404
|
+
restoreBuffer();
|
|
1033
2405
|
async function loadStorage() {
|
|
1034
2406
|
S.dbs = [];
|
|
1035
2407
|
if (!window.indexedDB) return;
|
|
@@ -1053,7 +2425,11 @@
|
|
|
1053
2425
|
req.onerror = () => rej(req.error);
|
|
1054
2426
|
req.onsuccess = () => {
|
|
1055
2427
|
const db = req.result;
|
|
1056
|
-
const info = {
|
|
2428
|
+
const info = {
|
|
2429
|
+
name: db.name,
|
|
2430
|
+
version: db.version,
|
|
2431
|
+
stores: []
|
|
2432
|
+
};
|
|
1057
2433
|
const storeNames = [...db.objectStoreNames];
|
|
1058
2434
|
let pending = storeNames.length;
|
|
1059
2435
|
if (!pending) {
|
|
@@ -1070,7 +2446,12 @@
|
|
|
1070
2446
|
res(info);
|
|
1071
2447
|
}
|
|
1072
2448
|
}).catch(() => {
|
|
1073
|
-
info.stores.push({
|
|
2449
|
+
info.stores.push({
|
|
2450
|
+
name: storeName,
|
|
2451
|
+
count: 0,
|
|
2452
|
+
keyPath: null,
|
|
2453
|
+
data: []
|
|
2454
|
+
});
|
|
1074
2455
|
if (--pending === 0) {
|
|
1075
2456
|
db.close();
|
|
1076
2457
|
S.dbs.push(info);
|
|
@@ -1087,7 +2468,12 @@
|
|
|
1087
2468
|
const store = tx.objectStore(storeName);
|
|
1088
2469
|
const cntReq = store.count();
|
|
1089
2470
|
cntReq.onsuccess = () => {
|
|
1090
|
-
const info = {
|
|
2471
|
+
const info = {
|
|
2472
|
+
name: storeName,
|
|
2473
|
+
count: cntReq.result,
|
|
2474
|
+
keyPath: store.keyPath,
|
|
2475
|
+
data: []
|
|
2476
|
+
};
|
|
1091
2477
|
const getReq = store.getAll(void 0, 20);
|
|
1092
2478
|
getReq.onsuccess = () => {
|
|
1093
2479
|
info.data = getReq.result;
|
|
@@ -1095,7 +2481,12 @@
|
|
|
1095
2481
|
};
|
|
1096
2482
|
getReq.onerror = () => res(info);
|
|
1097
2483
|
};
|
|
1098
|
-
cntReq.onerror = () => res({
|
|
2484
|
+
cntReq.onerror = () => res({
|
|
2485
|
+
name: storeName,
|
|
2486
|
+
count: 0,
|
|
2487
|
+
keyPath: null,
|
|
2488
|
+
data: []
|
|
2489
|
+
});
|
|
1099
2490
|
});
|
|
1100
2491
|
}
|
|
1101
2492
|
function renderStorage() {
|
|
@@ -1118,29 +2509,46 @@
|
|
|
1118
2509
|
o.innerHTML = '<div class="dc-empty">No IndexedDB databases found</div>';
|
|
1119
2510
|
return;
|
|
1120
2511
|
}
|
|
1121
|
-
o.innerHTML = S.dbs.map((db, di) =>
|
|
2512
|
+
o.innerHTML = S.dbs.map((db, di) => `
|
|
2513
|
+
<div class="dc-db-card" id="db-card-${di}">
|
|
1122
2514
|
<div class="dc-db-header" onclick="window.__dcToggleDb(${di})">
|
|
1123
2515
|
<div>
|
|
1124
2516
|
<div class="dc-db-name">${escHtml(db.name)}</div>
|
|
1125
|
-
<div class="dc-db-meta">
|
|
2517
|
+
<div class="dc-db-meta">
|
|
2518
|
+
v${db.version} ·
|
|
2519
|
+
${db.stores.length}
|
|
2520
|
+
store${db.stores.length !== 1 ? "s" : ""}
|
|
2521
|
+
</div>
|
|
1126
2522
|
</div>
|
|
1127
2523
|
<span style="color:var(--dc-text2);font-size:11px">▼</span>
|
|
1128
2524
|
</div>
|
|
2525
|
+
|
|
1129
2526
|
<div class="dc-db-body">
|
|
1130
2527
|
${db.stores.map((st, si) => `
|
|
1131
|
-
|
|
1132
|
-
|
|
1133
|
-
|
|
1134
|
-
|
|
1135
|
-
|
|
1136
|
-
|
|
1137
|
-
|
|
1138
|
-
|
|
1139
|
-
|
|
2528
|
+
<div class="dc-store-item" onclick="window.__dcToggleStore(${di},${si})">
|
|
2529
|
+
<div class="dc-store-name">${escHtml(st.name)}</div>
|
|
2530
|
+
<div class="dc-store-meta">
|
|
2531
|
+
${st.count} records ·
|
|
2532
|
+
keyPath: ${st.keyPath || "none"}
|
|
2533
|
+
</div>
|
|
2534
|
+
|
|
2535
|
+
<div class="dc-data-viewer" id="store-${di}-${si}">
|
|
2536
|
+
${st.data.length ? st.data.slice(0, 20).map((item) => `
|
|
2537
|
+
<div class="dc-data-row">
|
|
2538
|
+
<div class="dc-data-key">
|
|
2539
|
+
· ${escHtml(getKey(item, st.keyPath))}
|
|
2540
|
+
</div>
|
|
2541
|
+
<div class="dc-data-val">
|
|
2542
|
+
${escHtml(fmtVal(item))}
|
|
2543
|
+
</div>
|
|
2544
|
+
</div>
|
|
2545
|
+
`).join("") : '<div style="color:var(--dc-text2);font-size:11px;padding:8px">Empty store</div>'}
|
|
2546
|
+
</div>
|
|
1140
2547
|
</div>
|
|
1141
|
-
|
|
2548
|
+
`).join("")}
|
|
1142
2549
|
</div>
|
|
1143
|
-
</div
|
|
2550
|
+
</div>
|
|
2551
|
+
`).join("");
|
|
1144
2552
|
}
|
|
1145
2553
|
function getKey(obj, keyPath) {
|
|
1146
2554
|
if (!keyPath) return "—";
|
|
@@ -1148,35 +2556,27 @@
|
|
|
1148
2556
|
}
|
|
1149
2557
|
function fmtVal(v) {
|
|
1150
2558
|
if (typeof v === "object" && v !== null) {
|
|
1151
|
-
|
|
1152
|
-
|
|
2559
|
+
try {
|
|
2560
|
+
const s2 = JSON.stringify(v, null, 2);
|
|
2561
|
+
return s2.length > 300 ? s2.slice(0, 300) + "…" : s2;
|
|
2562
|
+
} catch (e) {
|
|
2563
|
+
return "[Unserializable]";
|
|
2564
|
+
}
|
|
1153
2565
|
}
|
|
1154
2566
|
const s = String(v);
|
|
1155
2567
|
return s.length > 200 ? s.slice(0, 200) + "…" : s;
|
|
1156
2568
|
}
|
|
1157
|
-
function renderKV(o, storage, name) {
|
|
1158
|
-
const items = [];
|
|
1159
|
-
for (let i = 0; i < storage.length; i++) {
|
|
1160
|
-
const k = storage.key(i);
|
|
1161
|
-
items.push({ k, v: storage.getItem(k) });
|
|
1162
|
-
}
|
|
1163
|
-
if (!items.length) {
|
|
1164
|
-
o.innerHTML = `<div class="dc-empty">No ${name} items</div>`;
|
|
1165
|
-
return;
|
|
1166
|
-
}
|
|
1167
|
-
o.innerHTML = `<div style="padding:4px 0">` + items.map(({ k, v }) => `
|
|
1168
|
-
<div class="dc-kv-row">
|
|
1169
|
-
<span class="dc-kv-key">${escHtml(k)}</span>
|
|
1170
|
-
<span class="dc-kv-val">${escHtml(fmtVal(v))}</span>
|
|
1171
|
-
</div>`).join("") + `</div>`;
|
|
1172
|
-
}
|
|
1173
2569
|
window.__dcToggleDb = function(di) {
|
|
1174
2570
|
const card = document.getElementById(`db-card-${di}`);
|
|
1175
|
-
if (card)
|
|
2571
|
+
if (card) {
|
|
2572
|
+
card.classList.toggle("open");
|
|
2573
|
+
}
|
|
1176
2574
|
};
|
|
1177
2575
|
window.__dcToggleStore = function(di, si) {
|
|
1178
2576
|
const viewer = document.getElementById(`store-${di}-${si}`);
|
|
1179
|
-
if (viewer)
|
|
2577
|
+
if (viewer) {
|
|
2578
|
+
viewer.classList.toggle("open");
|
|
2579
|
+
}
|
|
1180
2580
|
};
|
|
1181
2581
|
function renderDomTree() {
|
|
1182
2582
|
const o = el.domOut();
|
|
@@ -1218,7 +2618,9 @@
|
|
|
1218
2618
|
close.className = "dc-tag";
|
|
1219
2619
|
close.textContent = ">";
|
|
1220
2620
|
label.appendChild(close);
|
|
1221
|
-
const txtContent = nodeEl.childNodes.length ? [...nodeEl.childNodes].find(
|
|
2621
|
+
const txtContent = nodeEl.childNodes.length ? [...nodeEl.childNodes].find(
|
|
2622
|
+
(n) => n.nodeType === 3 && n.textContent.trim()
|
|
2623
|
+
) : null;
|
|
1222
2624
|
if (txtContent) {
|
|
1223
2625
|
const preview = document.createElement("span");
|
|
1224
2626
|
preview.className = "dc-txt-preview";
|
|
@@ -1230,7 +2632,9 @@
|
|
|
1230
2632
|
if (hasChildren) {
|
|
1231
2633
|
const childDiv = wrap.querySelector(":scope > .dc-children");
|
|
1232
2634
|
const isOpen = childDiv && childDiv.classList.contains("open");
|
|
1233
|
-
if (childDiv)
|
|
2635
|
+
if (childDiv) {
|
|
2636
|
+
childDiv.classList.toggle("open", !isOpen);
|
|
2637
|
+
}
|
|
1234
2638
|
arrow.textContent = !isOpen ? "▼" : "▶";
|
|
1235
2639
|
}
|
|
1236
2640
|
showNodeDetail(nodeEl);
|
|
@@ -1239,7 +2643,9 @@
|
|
|
1239
2643
|
if (hasChildren) {
|
|
1240
2644
|
const childDiv = document.createElement("div");
|
|
1241
2645
|
childDiv.className = "dc-children";
|
|
1242
|
-
children.forEach((child) =>
|
|
2646
|
+
children.forEach((child) => {
|
|
2647
|
+
childDiv.appendChild(buildNode(child));
|
|
2648
|
+
});
|
|
1243
2649
|
wrap.appendChild(childDiv);
|
|
1244
2650
|
}
|
|
1245
2651
|
return wrap;
|
|
@@ -1253,46 +2659,109 @@
|
|
|
1253
2659
|
const tag = `<${targetEl.tagName.toLowerCase()}>`;
|
|
1254
2660
|
const attrs = [...targetEl.attributes];
|
|
1255
2661
|
const styles = window.getComputedStyle(targetEl);
|
|
1256
|
-
d.innerHTML =
|
|
1257
|
-
|
|
1258
|
-
|
|
1259
|
-
|
|
1260
|
-
|
|
1261
|
-
|
|
2662
|
+
d.innerHTML = `
|
|
2663
|
+
<div style="color:var(--dc-accent2);font-size:12px;font-weight:700;margin-bottom:8px">
|
|
2664
|
+
${escHtml(tag)}
|
|
2665
|
+
</div>
|
|
2666
|
+
|
|
2667
|
+
${attrs.length ? `
|
|
2668
|
+
<div class="dc-detail-title">Attributes</div>
|
|
2669
|
+
${attrs.map((a) => `
|
|
2670
|
+
<div class="dc-attr-row">
|
|
2671
|
+
<span class="dc-attr-name">${escHtml(a.name)}</span>=
|
|
2672
|
+
<span class="dc-attr-val">"${escHtml(a.value)}"</span>
|
|
2673
|
+
</div>
|
|
2674
|
+
`).join("")}
|
|
2675
|
+
` : ""}
|
|
2676
|
+
|
|
2677
|
+
<div class="dc-detail-title" style="margin-top:8px">
|
|
2678
|
+
Geometry
|
|
2679
|
+
</div>
|
|
2680
|
+
|
|
2681
|
+
<div class="dc-attr-row">
|
|
2682
|
+
<span class="dc-attr-name">size: </span>
|
|
2683
|
+
<span class="dc-attr-val">
|
|
2684
|
+
${Math.round(targetEl.offsetWidth)}×${Math.round(targetEl.offsetHeight)}
|
|
2685
|
+
</span>
|
|
2686
|
+
</div>
|
|
2687
|
+
|
|
2688
|
+
<div class="dc-attr-row">
|
|
2689
|
+
<span class="dc-attr-name">display: </span>
|
|
2690
|
+
<span class="dc-attr-val">${styles.display}</span>
|
|
2691
|
+
</div>
|
|
2692
|
+
|
|
2693
|
+
<div class="dc-attr-row">
|
|
2694
|
+
<span class="dc-attr-name">position: </span>
|
|
2695
|
+
<span class="dc-attr-val">${styles.position}</span>
|
|
2696
|
+
</div>
|
|
2697
|
+
`;
|
|
1262
2698
|
el.domOut().prepend(d);
|
|
1263
2699
|
}
|
|
1264
2700
|
let _pickHandler = null;
|
|
2701
|
+
let _pickHoverHandler = null;
|
|
1265
2702
|
let _pickedEl = null;
|
|
1266
2703
|
function startPicking() {
|
|
1267
2704
|
S.isPicking = true;
|
|
1268
|
-
document.getElementById("dom-pick-btn")
|
|
2705
|
+
const button = document.getElementById("dom-pick-btn");
|
|
2706
|
+
if (button) button.classList.add("picking");
|
|
1269
2707
|
_pickHandler = (e) => {
|
|
1270
|
-
if (e.target.closest("#dc-panel") || e.target.closest("#dc-fab"))
|
|
2708
|
+
if (e.target.closest("#dc-panel") || e.target.closest("#dc-fab")) {
|
|
2709
|
+
return;
|
|
2710
|
+
}
|
|
1271
2711
|
e.preventDefault();
|
|
1272
2712
|
e.stopPropagation();
|
|
1273
|
-
if (_pickedEl)
|
|
2713
|
+
if (_pickedEl) {
|
|
2714
|
+
_pickedEl.classList.remove("dc-pick-highlight");
|
|
2715
|
+
}
|
|
1274
2716
|
_pickedEl = e.target;
|
|
1275
2717
|
_pickedEl.classList.add("dc-pick-highlight");
|
|
1276
2718
|
showNodeDetail(_pickedEl);
|
|
1277
2719
|
stopPicking();
|
|
1278
2720
|
};
|
|
1279
|
-
|
|
1280
|
-
document.addEventListener("mouseover", (e) => {
|
|
2721
|
+
_pickHoverHandler = (e) => {
|
|
1281
2722
|
if (!S.isPicking) return;
|
|
1282
|
-
if (e.target.closest("#dc-panel") || e.target.closest("#dc-fab"))
|
|
1283
|
-
|
|
2723
|
+
if (e.target.closest("#dc-panel") || e.target.closest("#dc-fab")) {
|
|
2724
|
+
return;
|
|
2725
|
+
}
|
|
2726
|
+
if (_pickedEl) {
|
|
2727
|
+
_pickedEl.classList.remove("dc-pick-highlight");
|
|
2728
|
+
}
|
|
1284
2729
|
_pickedEl = e.target;
|
|
1285
2730
|
_pickedEl.classList.add("dc-pick-highlight");
|
|
1286
|
-
}
|
|
2731
|
+
};
|
|
2732
|
+
document.addEventListener(
|
|
2733
|
+
"click",
|
|
2734
|
+
_pickHandler,
|
|
2735
|
+
true
|
|
2736
|
+
);
|
|
2737
|
+
document.addEventListener(
|
|
2738
|
+
"mouseover",
|
|
2739
|
+
_pickHoverHandler,
|
|
2740
|
+
true
|
|
2741
|
+
);
|
|
1287
2742
|
}
|
|
1288
2743
|
function stopPicking() {
|
|
1289
2744
|
S.isPicking = false;
|
|
1290
|
-
const
|
|
1291
|
-
if (
|
|
2745
|
+
const button = document.getElementById("dom-pick-btn");
|
|
2746
|
+
if (button) {
|
|
2747
|
+
button.classList.remove("picking");
|
|
2748
|
+
}
|
|
1292
2749
|
if (_pickHandler) {
|
|
1293
|
-
document.removeEventListener(
|
|
2750
|
+
document.removeEventListener(
|
|
2751
|
+
"click",
|
|
2752
|
+
_pickHandler,
|
|
2753
|
+
true
|
|
2754
|
+
);
|
|
1294
2755
|
_pickHandler = null;
|
|
1295
2756
|
}
|
|
2757
|
+
if (_pickHoverHandler) {
|
|
2758
|
+
document.removeEventListener(
|
|
2759
|
+
"mouseover",
|
|
2760
|
+
_pickHoverHandler,
|
|
2761
|
+
true
|
|
2762
|
+
);
|
|
2763
|
+
_pickHoverHandler = null;
|
|
2764
|
+
}
|
|
1296
2765
|
}
|
|
1297
2766
|
function renderSystem() {
|
|
1298
2767
|
const o = el.sysOut();
|
|
@@ -1311,126 +2780,161 @@
|
|
|
1311
2780
|
["HW Concurrency", nav.hardwareConcurrency || "—"]
|
|
1312
2781
|
];
|
|
1313
2782
|
if (conn) {
|
|
1314
|
-
cards.push([
|
|
1315
|
-
|
|
2783
|
+
cards.push([
|
|
2784
|
+
"Connection",
|
|
2785
|
+
`${conn.effectiveType || "—"} · ${conn.downlink || "—"} Mbps`
|
|
2786
|
+
]);
|
|
2787
|
+
cards.push([
|
|
2788
|
+
"RTT",
|
|
2789
|
+
conn.rtt != null ? `${conn.rtt}ms` : "—"
|
|
2790
|
+
]);
|
|
1316
2791
|
}
|
|
1317
2792
|
if (mem) {
|
|
1318
2793
|
const mb = (v) => (v / 1048576).toFixed(1) + " MB";
|
|
1319
|
-
cards.push([
|
|
1320
|
-
|
|
2794
|
+
cards.push([
|
|
2795
|
+
"Heap Used",
|
|
2796
|
+
mb(mem.usedJSHeapSize)
|
|
2797
|
+
]);
|
|
2798
|
+
cards.push([
|
|
2799
|
+
"Heap Limit",
|
|
2800
|
+
mb(mem.jsHeapSizeLimit)
|
|
2801
|
+
]);
|
|
1321
2802
|
}
|
|
1322
2803
|
if (perf) {
|
|
1323
2804
|
const nav2 = perf.getEntriesByType && perf.getEntriesByType("navigation")[0];
|
|
1324
2805
|
if (nav2) {
|
|
1325
|
-
cards.push([
|
|
1326
|
-
|
|
2806
|
+
cards.push([
|
|
2807
|
+
"Page Load",
|
|
2808
|
+
`${Math.round(nav2.loadEventEnd)}ms`
|
|
2809
|
+
]);
|
|
2810
|
+
cards.push([
|
|
2811
|
+
"DOM Ready",
|
|
2812
|
+
`${Math.round(nav2.domContentLoadedEventEnd)}ms`
|
|
2813
|
+
]);
|
|
1327
2814
|
}
|
|
1328
2815
|
}
|
|
1329
|
-
o.innerHTML = cards.map(
|
|
1330
|
-
|
|
1331
|
-
|
|
2816
|
+
o.innerHTML = cards.map(([label, val]) => `
|
|
2817
|
+
<div class="dc-sys-card">
|
|
2818
|
+
<div class="dc-sys-label">${escHtml(label)}</div>
|
|
2819
|
+
<div class="dc-sys-val">${escHtml(String(val))}</div>
|
|
2820
|
+
</div>
|
|
2821
|
+
`).join("") + `
|
|
2822
|
+
<div class="dc-sys-card dc-sys-full">
|
|
2823
|
+
<div class="dc-sys-label">User Agent</div>
|
|
2824
|
+
<div
|
|
2825
|
+
class="dc-sys-val"
|
|
2826
|
+
style="word-break:break-all;font-size:10px"
|
|
2827
|
+
>
|
|
2828
|
+
${escHtml(nav.userAgent)}
|
|
2829
|
+
</div>
|
|
2830
|
+
</div>
|
|
2831
|
+
`;
|
|
2832
|
+
}
|
|
2833
|
+
function makeToggle(id, name, desc, checked) {
|
|
2834
|
+
return `
|
|
2835
|
+
<div class="dc-setting-row">
|
|
2836
|
+
<div class="dc-setting-info">
|
|
2837
|
+
<div class="dc-setting-name">${name}</div>
|
|
2838
|
+
<div class="dc-setting-desc">${desc}</div>
|
|
2839
|
+
</div>
|
|
2840
|
+
<label class="dc-toggle">
|
|
2841
|
+
<input type="checkbox" id="${id}" ${checked ? "checked" : ""}>
|
|
2842
|
+
<span class="dc-toggle-track"></span>
|
|
2843
|
+
</label>
|
|
2844
|
+
</div>`;
|
|
2845
|
+
}
|
|
2846
|
+
function makeSelect(id, name, desc, options, current) {
|
|
2847
|
+
return `
|
|
2848
|
+
<div class="dc-setting-row">
|
|
2849
|
+
<div class="dc-setting-info">
|
|
2850
|
+
<div class="dc-setting-name">${name}</div>
|
|
2851
|
+
<div class="dc-setting-desc">${desc}</div>
|
|
2852
|
+
</div>
|
|
2853
|
+
<select class="dc-select" id="${id}">
|
|
2854
|
+
${options.map((v) => `<option value="${v}" ${current === v ? "selected" : ""}>${v}</option>`).join("")}
|
|
2855
|
+
</select>
|
|
2856
|
+
</div>`;
|
|
1332
2857
|
}
|
|
1333
2858
|
function renderSettings() {
|
|
1334
2859
|
const o = el.settOut();
|
|
1335
2860
|
if (!o) return;
|
|
1336
|
-
|
|
1337
|
-
|
|
1338
|
-
|
|
1339
|
-
|
|
1340
|
-
|
|
1341
|
-
|
|
1342
|
-
|
|
1343
|
-
|
|
1344
|
-
<div class="dc-setting-row">
|
|
1345
|
-
<div class="dc-setting-info">
|
|
1346
|
-
<div class="dc-setting-name">Auto-scroll</div>
|
|
1347
|
-
<div class="dc-setting-desc">Scroll to latest entry automatically</div>
|
|
1348
|
-
</div>
|
|
1349
|
-
<label class="dc-toggle"><input type="checkbox" id="s-as" ${S.settings.autoScroll ? "checked" : ""}><span class="dc-toggle-track"></span></label>
|
|
1350
|
-
</div>
|
|
1351
|
-
<div class="dc-setting-row">
|
|
1352
|
-
<div class="dc-setting-info">
|
|
1353
|
-
<div class="dc-setting-name">Capture Global Errors</div>
|
|
1354
|
-
<div class="dc-setting-desc">window.onerror + unhandledrejection</div>
|
|
1355
|
-
</div>
|
|
1356
|
-
<label class="dc-toggle"><input type="checkbox" id="s-ce" ${S.settings.captureErrors ? "checked" : ""}><span class="dc-toggle-track"></span></label>
|
|
1357
|
-
</div>
|
|
1358
|
-
<div class="dc-setting-row">
|
|
1359
|
-
<div class="dc-setting-info">
|
|
1360
|
-
<div class="dc-setting-name">Monitor Network</div>
|
|
1361
|
-
<div class="dc-setting-desc">Intercept fetch + XHR requests</div>
|
|
1362
|
-
</div>
|
|
1363
|
-
<label class="dc-toggle"><input type="checkbox" id="s-mn" ${S.settings.monitorNetwork ? "checked" : ""}><span class="dc-toggle-track"></span></label>
|
|
1364
|
-
</div>
|
|
1365
|
-
<div class="dc-setting-row">
|
|
1366
|
-
<div class="dc-setting-info">
|
|
1367
|
-
<div class="dc-setting-name">Font Size</div>
|
|
1368
|
-
<div class="dc-setting-desc">Console output font size (px)</div>
|
|
1369
|
-
</div>
|
|
1370
|
-
<select class="dc-select" id="s-fs">
|
|
1371
|
-
${[10, 11, 12, 13, 14].map((s) => `<option value="${s}" ${S.settings.fontSize === s ? "selected" : ""}>${s}px</option>`).join("")}
|
|
1372
|
-
</select>
|
|
1373
|
-
</div>
|
|
1374
|
-
<div class="dc-setting-row">
|
|
1375
|
-
<div class="dc-setting-info">
|
|
1376
|
-
<div class="dc-setting-name">Max Log Entries</div>
|
|
1377
|
-
<div class="dc-setting-desc">Older entries are discarded</div>
|
|
1378
|
-
</div>
|
|
1379
|
-
<select class="dc-select" id="s-me">
|
|
1380
|
-
${[100, 250, 500, 1e3, 2e3].map((s) => `<option value="${s}" ${S.settings.maxEntries === s ? "selected" : ""}>${s}</option>`).join("")}
|
|
1381
|
-
</select>
|
|
1382
|
-
</div>
|
|
1383
|
-
<div class="dc-setting-row" style="border:none">
|
|
1384
|
-
<div class="dc-setting-info">
|
|
1385
|
-
<div class="dc-setting-name" style="color:var(--dc-red)">Clear All Data</div>
|
|
1386
|
-
<div class="dc-setting-desc">Wipe logs and network history</div>
|
|
1387
|
-
</div>
|
|
1388
|
-
<button class="dc-clear-btn" onclick="window.__dcClearAll()">Clear</button>
|
|
1389
|
-
</div>`;
|
|
2861
|
+
const ss = S.settings;
|
|
2862
|
+
o.innerHTML = makeToggle("s-ts", "Timestamps", "Show time prefix on each log entry", ss.timestamps) + makeToggle("s-as", "Auto-scroll", "Scroll to latest entry automatically", ss.autoScroll) + makeToggle("s-ce", "Capture Global Errors", "window.onerror + unhandledrejection", ss.captureErrors) + makeToggle("s-mn", "Monitor Network", "Intercept fetch + XHR requests", ss.monitorNetwork) + makeToggle("s-pb", "Persist Across Reload", "Keep console and network history in sessionStorage", ss.persistBuffer) + makeSelect("s-fs", "Font Size", "Console output font size (px)", [10, 11, 12, 13, 14], ss.fontSize) + makeSelect("s-me", "Max Log Entries", "Older entries are discarded", [100, 250, 500, 1e3, 2e3], ss.maxEntries) + `<div class="dc-setting-row" style="border:none">
|
|
2863
|
+
<div class="dc-setting-info">
|
|
2864
|
+
<div class="dc-setting-name" style="color:var(--dc-red)">Clear All Data</div>
|
|
2865
|
+
<div class="dc-setting-desc">Wipe logs, network history and persistent buffer</div>
|
|
2866
|
+
</div>
|
|
2867
|
+
<button class="dc-clear-btn" id="dc-settings-clear">Clear</button>
|
|
2868
|
+
</div>`;
|
|
1390
2869
|
document.getElementById("s-ts").onchange = (e) => {
|
|
1391
|
-
|
|
2870
|
+
ss.timestamps = e.target.checked;
|
|
1392
2871
|
saveSettings();
|
|
1393
2872
|
renderConsole();
|
|
1394
2873
|
};
|
|
1395
2874
|
document.getElementById("s-as").onchange = (e) => {
|
|
1396
|
-
|
|
2875
|
+
ss.autoScroll = e.target.checked;
|
|
1397
2876
|
saveSettings();
|
|
1398
2877
|
};
|
|
1399
2878
|
document.getElementById("s-ce").onchange = (e) => {
|
|
1400
|
-
|
|
2879
|
+
ss.captureErrors = e.target.checked;
|
|
1401
2880
|
saveSettings();
|
|
1402
2881
|
};
|
|
1403
2882
|
document.getElementById("s-mn").onchange = (e) => {
|
|
1404
|
-
|
|
2883
|
+
ss.monitorNetwork = e.target.checked;
|
|
2884
|
+
saveSettings();
|
|
2885
|
+
};
|
|
2886
|
+
document.getElementById("s-pb").onchange = (e) => {
|
|
2887
|
+
ss.persistBuffer = e.target.checked;
|
|
1405
2888
|
saveSettings();
|
|
2889
|
+
ss.persistBuffer ? persistBuffer() : clearPersistentBuffer();
|
|
1406
2890
|
};
|
|
1407
2891
|
document.getElementById("s-fs").onchange = (e) => {
|
|
1408
|
-
|
|
2892
|
+
ss.fontSize = parseInt(e.target.value, 10);
|
|
1409
2893
|
saveSettings();
|
|
1410
2894
|
if (S.activeTab === "console") renderConsole();
|
|
1411
2895
|
};
|
|
1412
2896
|
document.getElementById("s-me").onchange = (e) => {
|
|
1413
|
-
|
|
2897
|
+
ss.maxEntries = parseInt(e.target.value, 10);
|
|
2898
|
+
trimLogs();
|
|
2899
|
+
if (S.network.length > ss.maxEntries) S.network = S.network.slice(0, ss.maxEntries);
|
|
1414
2900
|
saveSettings();
|
|
2901
|
+
persistBuffer();
|
|
2902
|
+
updateTabCount("console", S.logs.length);
|
|
2903
|
+
updateTabCount("network", S.network.length);
|
|
2904
|
+
renderConsole();
|
|
1415
2905
|
};
|
|
2906
|
+
document.getElementById("dc-settings-clear").addEventListener("click", window.__dcClearAll);
|
|
1416
2907
|
}
|
|
1417
2908
|
window.__dcClearAll = function() {
|
|
1418
2909
|
S.logs = [];
|
|
1419
2910
|
S.network = [];
|
|
1420
2911
|
S.errorCount = 0;
|
|
2912
|
+
S.groupDepth = 0;
|
|
2913
|
+
clearPersistentBuffer();
|
|
1421
2914
|
const b = el.badge();
|
|
1422
2915
|
if (b) {
|
|
1423
2916
|
b.style.display = "none";
|
|
2917
|
+
b.textContent = "0";
|
|
1424
2918
|
}
|
|
1425
2919
|
updateTabCount("console", 0);
|
|
1426
2920
|
updateTabCount("network", 0);
|
|
1427
|
-
|
|
1428
|
-
|
|
2921
|
+
renderConsole();
|
|
2922
|
+
renderNetwork();
|
|
1429
2923
|
};
|
|
1430
2924
|
function switchTab(name) {
|
|
1431
2925
|
S.activeTab = name;
|
|
1432
|
-
document.querySelectorAll(".dc-tab").forEach(
|
|
1433
|
-
|
|
2926
|
+
document.querySelectorAll(".dc-tab").forEach(
|
|
2927
|
+
(b) => b.classList.toggle(
|
|
2928
|
+
"active",
|
|
2929
|
+
b.dataset.tab === name
|
|
2930
|
+
)
|
|
2931
|
+
);
|
|
2932
|
+
document.querySelectorAll(".dc-panel-content").forEach(
|
|
2933
|
+
(p) => p.classList.toggle(
|
|
2934
|
+
"active",
|
|
2935
|
+
p.id === `panel-${name}`
|
|
2936
|
+
)
|
|
2937
|
+
);
|
|
1434
2938
|
switch (name) {
|
|
1435
2939
|
case "console":
|
|
1436
2940
|
renderConsole();
|
|
@@ -1452,15 +2956,12 @@
|
|
|
1452
2956
|
break;
|
|
1453
2957
|
}
|
|
1454
2958
|
}
|
|
1455
|
-
function updateTabCount(tab, n) {
|
|
1456
|
-
const el2 = document.getElementById(`cnt-${tab}`);
|
|
1457
|
-
if (!el2) return;
|
|
1458
|
-
if (n > 0) {
|
|
1459
|
-
el2.textContent = n > 999 ? "999+" : n;
|
|
1460
|
-
el2.style.display = "inline-flex";
|
|
1461
|
-
} else el2.style.display = "none";
|
|
1462
|
-
}
|
|
1463
2959
|
let _panelOpen = false;
|
|
2960
|
+
function updateFab() {
|
|
2961
|
+
const fab = el.fab();
|
|
2962
|
+
if (!fab) return;
|
|
2963
|
+
fab.innerHTML = `${_panelOpen ? "✕" : "⌥"}<span class="dc-fab-badge" id="dc-error-badge" style="display:${S.errorCount > 0 ? "flex" : "none"}">${S.errorCount}</span>`;
|
|
2964
|
+
}
|
|
1464
2965
|
function togglePanel() {
|
|
1465
2966
|
_panelOpen = !_panelOpen;
|
|
1466
2967
|
const panel = el.panel();
|
|
@@ -1473,19 +2974,19 @@
|
|
|
1473
2974
|
} else {
|
|
1474
2975
|
panel.classList.remove("visible");
|
|
1475
2976
|
setTimeout(() => {
|
|
1476
|
-
|
|
2977
|
+
if (!_panelOpen) {
|
|
2978
|
+
panel.style.display = "none";
|
|
2979
|
+
}
|
|
1477
2980
|
}, 260);
|
|
1478
2981
|
}
|
|
1479
|
-
|
|
1480
|
-
el.fab().innerHTML = `✕<span class="dc-fab-badge" id="dc-error-badge" style="display:${S.errorCount > 0 ? "flex" : "none"}">${S.errorCount}</span>`;
|
|
1481
|
-
} else {
|
|
1482
|
-
el.fab().innerHTML = `⌥<span class="dc-fab-badge" id="dc-error-badge" style="display:${S.errorCount > 0 ? "flex" : "none"}">${S.errorCount}</span>`;
|
|
1483
|
-
}
|
|
2982
|
+
updateFab();
|
|
1484
2983
|
}
|
|
1485
2984
|
(function initDrag() {
|
|
1486
2985
|
const handle = document.getElementById("dc-drag");
|
|
1487
2986
|
const panel = document.getElementById("dc-panel");
|
|
1488
|
-
let dragging = false
|
|
2987
|
+
let dragging = false;
|
|
2988
|
+
let startY = 0;
|
|
2989
|
+
let startH = 0;
|
|
1489
2990
|
function onStart(e) {
|
|
1490
2991
|
dragging = true;
|
|
1491
2992
|
startY = e.clientY || e.touches && e.touches[0].clientY;
|
|
@@ -1495,19 +2996,45 @@
|
|
|
1495
2996
|
function onMove(e) {
|
|
1496
2997
|
if (!dragging) return;
|
|
1497
2998
|
const y = e.clientY || e.touches && e.touches[0].clientY;
|
|
1498
|
-
const newH = Math.max(
|
|
2999
|
+
const newH = Math.max(
|
|
3000
|
+
120,
|
|
3001
|
+
Math.min(
|
|
3002
|
+
window.innerHeight * 0.85,
|
|
3003
|
+
startH + (startY - y)
|
|
3004
|
+
)
|
|
3005
|
+
);
|
|
1499
3006
|
panel.style.height = newH + "px";
|
|
1500
3007
|
}
|
|
1501
3008
|
function onEnd() {
|
|
1502
3009
|
dragging = false;
|
|
1503
3010
|
document.body.style.userSelect = "";
|
|
1504
3011
|
}
|
|
1505
|
-
handle.addEventListener(
|
|
1506
|
-
|
|
1507
|
-
|
|
1508
|
-
|
|
1509
|
-
|
|
1510
|
-
|
|
3012
|
+
handle.addEventListener(
|
|
3013
|
+
"mousedown",
|
|
3014
|
+
onStart
|
|
3015
|
+
);
|
|
3016
|
+
handle.addEventListener(
|
|
3017
|
+
"touchstart",
|
|
3018
|
+
onStart,
|
|
3019
|
+
{ passive: true }
|
|
3020
|
+
);
|
|
3021
|
+
document.addEventListener(
|
|
3022
|
+
"mousemove",
|
|
3023
|
+
onMove
|
|
3024
|
+
);
|
|
3025
|
+
document.addEventListener(
|
|
3026
|
+
"touchmove",
|
|
3027
|
+
onMove,
|
|
3028
|
+
{ passive: true }
|
|
3029
|
+
);
|
|
3030
|
+
document.addEventListener(
|
|
3031
|
+
"mouseup",
|
|
3032
|
+
onEnd
|
|
3033
|
+
);
|
|
3034
|
+
document.addEventListener(
|
|
3035
|
+
"touchend",
|
|
3036
|
+
onEnd
|
|
3037
|
+
);
|
|
1511
3038
|
})();
|
|
1512
3039
|
function initRepl() {
|
|
1513
3040
|
const input = el.replIn();
|
|
@@ -1516,12 +3043,23 @@
|
|
|
1516
3043
|
const code = input.value.trim();
|
|
1517
3044
|
if (!code) return;
|
|
1518
3045
|
S.replHistory.unshift(code);
|
|
1519
|
-
if (S.replHistory.length > 50)
|
|
3046
|
+
if (S.replHistory.length > 50) {
|
|
3047
|
+
S.replHistory.pop();
|
|
3048
|
+
}
|
|
1520
3049
|
S.replHistoryIdx = -1;
|
|
1521
3050
|
const entry = document.createElement("div");
|
|
1522
3051
|
entry.className = "dc-entry dc-entry-cmd";
|
|
1523
3052
|
entry.style.fontSize = S.settings.fontSize + "px";
|
|
1524
|
-
|
|
3053
|
+
if (S.settings.timestamps) {
|
|
3054
|
+
const timestamp = document.createElement("span");
|
|
3055
|
+
timestamp.className = "dc-ts";
|
|
3056
|
+
timestamp.textContent = ts();
|
|
3057
|
+
entry.appendChild(timestamp);
|
|
3058
|
+
}
|
|
3059
|
+
const body = document.createElement("span");
|
|
3060
|
+
body.className = "dc-entry-body";
|
|
3061
|
+
body.textContent = `▶ ${code}`;
|
|
3062
|
+
entry.appendChild(body);
|
|
1525
3063
|
el.consOut().appendChild(entry);
|
|
1526
3064
|
try {
|
|
1527
3065
|
const result = (0, eval)(code);
|
|
@@ -1529,18 +3067,42 @@
|
|
|
1529
3067
|
const resEntry = document.createElement("div");
|
|
1530
3068
|
resEntry.className = "dc-entry dc-entry-log";
|
|
1531
3069
|
resEntry.style.fontSize = S.settings.fontSize + "px";
|
|
1532
|
-
|
|
3070
|
+
if (S.settings.timestamps) {
|
|
3071
|
+
const timestamp = document.createElement("span");
|
|
3072
|
+
timestamp.className = "dc-ts";
|
|
3073
|
+
timestamp.textContent = ts();
|
|
3074
|
+
resEntry.appendChild(timestamp);
|
|
3075
|
+
}
|
|
3076
|
+
const resultBody = document.createElement("span");
|
|
3077
|
+
resultBody.className = "dc-entry-body";
|
|
3078
|
+
resultBody.appendChild(
|
|
3079
|
+
renderValue(snapshotValue(result))
|
|
3080
|
+
);
|
|
3081
|
+
resEntry.appendChild(resultBody);
|
|
1533
3082
|
el.consOut().appendChild(resEntry);
|
|
1534
3083
|
}
|
|
1535
3084
|
} catch (err) {
|
|
1536
3085
|
const errEntry = document.createElement("div");
|
|
1537
3086
|
errEntry.className = "dc-entry dc-entry-error";
|
|
1538
3087
|
errEntry.style.fontSize = S.settings.fontSize + "px";
|
|
1539
|
-
|
|
3088
|
+
if (S.settings.timestamps) {
|
|
3089
|
+
const timestamp = document.createElement("span");
|
|
3090
|
+
timestamp.className = "dc-ts";
|
|
3091
|
+
timestamp.textContent = ts();
|
|
3092
|
+
errEntry.appendChild(timestamp);
|
|
3093
|
+
}
|
|
3094
|
+
const body2 = document.createElement("span");
|
|
3095
|
+
body2.className = "dc-entry-body";
|
|
3096
|
+
body2.appendChild(
|
|
3097
|
+
renderValue(snapshotValue(err))
|
|
3098
|
+
);
|
|
3099
|
+
errEntry.appendChild(body2);
|
|
1540
3100
|
el.consOut().appendChild(errEntry);
|
|
1541
3101
|
}
|
|
1542
3102
|
input.value = "";
|
|
1543
|
-
if (S.settings.autoScroll)
|
|
3103
|
+
if (S.settings.autoScroll) {
|
|
3104
|
+
el.consOut().scrollTop = el.consOut().scrollHeight;
|
|
3105
|
+
}
|
|
1544
3106
|
switchTab("console");
|
|
1545
3107
|
}
|
|
1546
3108
|
input.addEventListener("keydown", (e) => {
|
|
@@ -1550,100 +3112,241 @@
|
|
|
1550
3112
|
}
|
|
1551
3113
|
if (e.key === "ArrowUp") {
|
|
1552
3114
|
e.preventDefault();
|
|
1553
|
-
S.replHistoryIdx = Math.min(
|
|
3115
|
+
S.replHistoryIdx = Math.min(
|
|
3116
|
+
S.replHistoryIdx + 1,
|
|
3117
|
+
S.replHistory.length - 1
|
|
3118
|
+
);
|
|
1554
3119
|
input.value = S.replHistory[S.replHistoryIdx] || "";
|
|
1555
3120
|
}
|
|
1556
3121
|
if (e.key === "ArrowDown") {
|
|
1557
3122
|
e.preventDefault();
|
|
1558
|
-
S.replHistoryIdx = Math.max(
|
|
3123
|
+
S.replHistoryIdx = Math.max(
|
|
3124
|
+
S.replHistoryIdx - 1,
|
|
3125
|
+
-1
|
|
3126
|
+
);
|
|
1559
3127
|
input.value = S.replHistoryIdx >= 0 ? S.replHistory[S.replHistoryIdx] : "";
|
|
1560
3128
|
}
|
|
1561
3129
|
});
|
|
1562
3130
|
const runBtn = document.getElementById("repl-run");
|
|
1563
|
-
if (runBtn)
|
|
3131
|
+
if (runBtn) {
|
|
3132
|
+
runBtn.addEventListener(
|
|
3133
|
+
"click",
|
|
3134
|
+
execute
|
|
3135
|
+
);
|
|
3136
|
+
}
|
|
1564
3137
|
}
|
|
1565
|
-
document.getElementById("dc-fab").addEventListener(
|
|
1566
|
-
|
|
3138
|
+
document.getElementById("dc-fab").addEventListener(
|
|
3139
|
+
"click",
|
|
3140
|
+
togglePanel
|
|
3141
|
+
);
|
|
3142
|
+
document.getElementById("dc-minimize-btn").addEventListener(
|
|
3143
|
+
"click",
|
|
3144
|
+
togglePanel
|
|
3145
|
+
);
|
|
1567
3146
|
document.querySelectorAll(".dc-tab").forEach((btn) => {
|
|
1568
|
-
btn.addEventListener(
|
|
3147
|
+
btn.addEventListener(
|
|
3148
|
+
"click",
|
|
3149
|
+
() => switchTab(btn.dataset.tab)
|
|
3150
|
+
);
|
|
1569
3151
|
});
|
|
1570
|
-
document.getElementById("dc-clear-btn").addEventListener(
|
|
1571
|
-
|
|
1572
|
-
|
|
1573
|
-
|
|
1574
|
-
|
|
1575
|
-
|
|
1576
|
-
|
|
1577
|
-
|
|
1578
|
-
|
|
1579
|
-
|
|
1580
|
-
|
|
1581
|
-
|
|
3152
|
+
document.getElementById("dc-clear-btn").addEventListener(
|
|
3153
|
+
"click",
|
|
3154
|
+
() => {
|
|
3155
|
+
switch (S.activeTab) {
|
|
3156
|
+
case "console":
|
|
3157
|
+
S.logs = [];
|
|
3158
|
+
S.groupDepth = 0;
|
|
3159
|
+
clearPersistentBuffer();
|
|
3160
|
+
updateTabCount("console", 0);
|
|
3161
|
+
renderConsole();
|
|
3162
|
+
break;
|
|
3163
|
+
case "network":
|
|
3164
|
+
S.network = [];
|
|
3165
|
+
clearPersistentBuffer();
|
|
3166
|
+
updateTabCount("network", 0);
|
|
3167
|
+
renderNetwork();
|
|
3168
|
+
break;
|
|
3169
|
+
}
|
|
1582
3170
|
}
|
|
1583
|
-
|
|
1584
|
-
document.getElementById("dc-copy-btn").addEventListener(
|
|
1585
|
-
|
|
1586
|
-
|
|
1587
|
-
text =
|
|
1588
|
-
|
|
1589
|
-
|
|
3171
|
+
);
|
|
3172
|
+
document.getElementById("dc-copy-btn").addEventListener(
|
|
3173
|
+
"click",
|
|
3174
|
+
() => {
|
|
3175
|
+
let text = "";
|
|
3176
|
+
if (S.activeTab === "console") {
|
|
3177
|
+
text = S.logs.map(
|
|
3178
|
+
(l) => `[${l.ts}] [${String(l.type).toUpperCase()}] ${formatLogForCopy(l)}`
|
|
3179
|
+
).join("\n");
|
|
3180
|
+
} else if (S.activeTab === "network") {
|
|
3181
|
+
text = S.network.map(
|
|
3182
|
+
(r) => `[${r.ts}] ${r.method} ${r.url} → ${r.status || "ERR"} (${r.duration}ms)` + (r.requestBody ? `
|
|
3183
|
+
Request: ${r.requestBody}` : "") + (r.responseBody ? `
|
|
3184
|
+
Response: ${r.responseBody}` : "")
|
|
3185
|
+
).join("\n\n");
|
|
3186
|
+
}
|
|
3187
|
+
if (!text) return;
|
|
3188
|
+
if (navigator.clipboard && navigator.clipboard.writeText) {
|
|
3189
|
+
navigator.clipboard.writeText(text).catch(() => {
|
|
3190
|
+
});
|
|
3191
|
+
}
|
|
1590
3192
|
}
|
|
1591
|
-
|
|
1592
|
-
|
|
1593
|
-
|
|
1594
|
-
|
|
1595
|
-
|
|
3193
|
+
);
|
|
3194
|
+
function formatLogForCopy(log) {
|
|
3195
|
+
if (log.type === "table" && log.table) {
|
|
3196
|
+
try {
|
|
3197
|
+
return JSON.stringify(log.table, null, 2);
|
|
3198
|
+
} catch (e) {
|
|
3199
|
+
}
|
|
1596
3200
|
}
|
|
1597
|
-
|
|
1598
|
-
|
|
1599
|
-
|
|
1600
|
-
|
|
1601
|
-
|
|
1602
|
-
|
|
1603
|
-
|
|
3201
|
+
return (log.args || []).map(snapshotToText).join(" ");
|
|
3202
|
+
}
|
|
3203
|
+
function snapshotToText(value) {
|
|
3204
|
+
if (!value) return "";
|
|
3205
|
+
switch (value.kind) {
|
|
3206
|
+
case "string":
|
|
3207
|
+
return `"${value.value}"`;
|
|
3208
|
+
case "null":
|
|
3209
|
+
case "undefined":
|
|
3210
|
+
case "number":
|
|
3211
|
+
case "boolean":
|
|
3212
|
+
case "bigint":
|
|
3213
|
+
case "symbol":
|
|
3214
|
+
case "function":
|
|
3215
|
+
return String(value.value ?? value.kind);
|
|
3216
|
+
case "date":
|
|
3217
|
+
case "regexp":
|
|
3218
|
+
case "circular":
|
|
3219
|
+
return String(value.value || `[${value.kind}]`);
|
|
3220
|
+
case "error":
|
|
3221
|
+
return `${value.ctor}: ${value.message}`;
|
|
3222
|
+
case "array":
|
|
3223
|
+
case "object":
|
|
3224
|
+
try {
|
|
3225
|
+
return JSON.stringify(value, null, 2);
|
|
3226
|
+
} catch (e) {
|
|
3227
|
+
return "[Object]";
|
|
3228
|
+
}
|
|
3229
|
+
default:
|
|
3230
|
+
return "[Unknown]";
|
|
3231
|
+
}
|
|
3232
|
+
}
|
|
3233
|
+
el.netFlt().addEventListener(
|
|
3234
|
+
"input",
|
|
3235
|
+
(e) => renderNetwork(e.target.value)
|
|
3236
|
+
);
|
|
3237
|
+
document.getElementById("net-clear").addEventListener(
|
|
3238
|
+
"click",
|
|
3239
|
+
() => {
|
|
3240
|
+
S.network = [];
|
|
3241
|
+
clearPersistentBuffer();
|
|
3242
|
+
updateTabCount("network", 0);
|
|
3243
|
+
renderNetwork();
|
|
3244
|
+
}
|
|
3245
|
+
);
|
|
1604
3246
|
document.querySelectorAll(".dc-st-btn").forEach((btn) => {
|
|
1605
|
-
btn.addEventListener(
|
|
1606
|
-
|
|
1607
|
-
|
|
1608
|
-
|
|
1609
|
-
|
|
1610
|
-
|
|
1611
|
-
|
|
1612
|
-
|
|
1613
|
-
|
|
1614
|
-
|
|
1615
|
-
|
|
1616
|
-
|
|
1617
|
-
|
|
1618
|
-
document.querySelectorAll(".dc-arrow").forEach((a) => {
|
|
1619
|
-
if (a.textContent === "▼") a.textContent = "▶";
|
|
1620
|
-
});
|
|
3247
|
+
btn.addEventListener(
|
|
3248
|
+
"click",
|
|
3249
|
+
() => {
|
|
3250
|
+
S.activeStorage = btn.dataset.storage;
|
|
3251
|
+
document.querySelectorAll(".dc-st-btn").forEach(
|
|
3252
|
+
(b) => b.classList.toggle(
|
|
3253
|
+
"active",
|
|
3254
|
+
b === btn
|
|
3255
|
+
)
|
|
3256
|
+
);
|
|
3257
|
+
renderStorage();
|
|
3258
|
+
}
|
|
3259
|
+
);
|
|
1621
3260
|
});
|
|
3261
|
+
document.getElementById("storage-refresh").addEventListener(
|
|
3262
|
+
"click",
|
|
3263
|
+
loadStorage
|
|
3264
|
+
);
|
|
3265
|
+
document.getElementById("dom-refresh-btn").addEventListener(
|
|
3266
|
+
"click",
|
|
3267
|
+
renderDomTree
|
|
3268
|
+
);
|
|
3269
|
+
document.getElementById("dom-pick-btn").addEventListener(
|
|
3270
|
+
"click",
|
|
3271
|
+
() => {
|
|
3272
|
+
S.isPicking ? stopPicking() : startPicking();
|
|
3273
|
+
}
|
|
3274
|
+
);
|
|
3275
|
+
document.getElementById("dom-collapse-btn").addEventListener(
|
|
3276
|
+
"click",
|
|
3277
|
+
() => {
|
|
3278
|
+
document.querySelectorAll(".dc-children.open").forEach(
|
|
3279
|
+
(c) => c.classList.remove("open")
|
|
3280
|
+
);
|
|
3281
|
+
document.querySelectorAll(".dc-arrow").forEach((a) => {
|
|
3282
|
+
if (a.textContent === "▼") {
|
|
3283
|
+
a.textContent = "▶";
|
|
3284
|
+
}
|
|
3285
|
+
});
|
|
3286
|
+
}
|
|
3287
|
+
);
|
|
1622
3288
|
let _lastUrl = location.href;
|
|
1623
3289
|
setInterval(() => {
|
|
1624
3290
|
if (location.href !== _lastUrl) {
|
|
1625
3291
|
_lastUrl = location.href;
|
|
1626
|
-
addLog(
|
|
3292
|
+
addLog(
|
|
3293
|
+
"info",
|
|
3294
|
+
["🔄 SPA navigation detected:", location.href]
|
|
3295
|
+
);
|
|
1627
3296
|
}
|
|
1628
3297
|
}, 1e3);
|
|
1629
3298
|
initRepl();
|
|
1630
3299
|
renderConsole();
|
|
1631
|
-
|
|
3300
|
+
if (!S.logs.length) {
|
|
3301
|
+
addLog(
|
|
3302
|
+
"log",
|
|
3303
|
+
[`✅ INSIKT v${VERSION} loaded — click ⌥ to open`]
|
|
3304
|
+
);
|
|
3305
|
+
} else {
|
|
3306
|
+
S.logs.forEach((log) => {
|
|
3307
|
+
log.restored = true;
|
|
3308
|
+
});
|
|
3309
|
+
addLog(
|
|
3310
|
+
"info",
|
|
3311
|
+
[`🔄 INSIKT v${VERSION} resumed after reload`]
|
|
3312
|
+
);
|
|
3313
|
+
}
|
|
1632
3314
|
window.insikt = {
|
|
3315
|
+
version: VERSION,
|
|
1633
3316
|
toggle: togglePanel,
|
|
1634
3317
|
clear: window.__dcClearAll,
|
|
1635
3318
|
init: () => {
|
|
1636
3319
|
},
|
|
1637
3320
|
destroy: () => {
|
|
1638
|
-
const fab = el.fab()
|
|
3321
|
+
const fab = el.fab();
|
|
3322
|
+
const panel = el.panel();
|
|
1639
3323
|
if (fab) fab.remove();
|
|
1640
3324
|
if (panel) panel.remove();
|
|
1641
|
-
["log", "warn", "error", "info"].forEach((
|
|
1642
|
-
if (_orig[
|
|
3325
|
+
["log", "warn", "error", "info", "table", "group", "groupCollapsed", "groupEnd"].forEach((level) => {
|
|
3326
|
+
if (_orig[level]) {
|
|
3327
|
+
console[level] = _orig[level];
|
|
3328
|
+
}
|
|
1643
3329
|
});
|
|
1644
|
-
|
|
3330
|
+
if (_origFetch) {
|
|
3331
|
+
window.fetch = _origFetch;
|
|
3332
|
+
}
|
|
1645
3333
|
XMLHttpRequest.prototype.open = _origOpen;
|
|
1646
3334
|
XMLHttpRequest.prototype.send = _origSend;
|
|
3335
|
+
XMLHttpRequest.prototype.setRequestHeader = _origSetRequestHeader;
|
|
3336
|
+
window.onerror = _origOnError;
|
|
3337
|
+
window.removeEventListener(
|
|
3338
|
+
"unhandledrejection",
|
|
3339
|
+
onUnhandledRejection
|
|
3340
|
+
);
|
|
3341
|
+
stopPicking();
|
|
3342
|
+
if (style && style.parentNode) {
|
|
3343
|
+
style.parentNode.removeChild(style);
|
|
3344
|
+
}
|
|
3345
|
+
delete window.__dcToggleReq;
|
|
3346
|
+
delete window.__dcToggleDb;
|
|
3347
|
+
delete window.__dcToggleStore;
|
|
3348
|
+
delete window.__dcClearAll;
|
|
3349
|
+
delete window.insikt;
|
|
1647
3350
|
}
|
|
1648
3351
|
};
|
|
1649
3352
|
})();
|