figrecipe 0.5.0__py3-none-any.whl → 0.7.4__py3-none-any.whl
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.
- figrecipe/__init__.py +220 -819
- figrecipe/_api/__init__.py +48 -0
- figrecipe/_api/_extract.py +108 -0
- figrecipe/_api/_notebook.py +61 -0
- figrecipe/_api/_panel.py +46 -0
- figrecipe/_api/_save.py +191 -0
- figrecipe/_api/_seaborn_proxy.py +34 -0
- figrecipe/_api/_style_manager.py +153 -0
- figrecipe/_api/_subplots.py +333 -0
- figrecipe/_api/_validate.py +82 -0
- figrecipe/_dev/__init__.py +29 -0
- figrecipe/_dev/_plotters.py +76 -0
- figrecipe/_dev/_run_demos.py +56 -0
- figrecipe/_dev/demo_plotters/__init__.py +64 -0
- figrecipe/_dev/demo_plotters/_categories.py +81 -0
- figrecipe/_dev/demo_plotters/_figure_creators.py +119 -0
- figrecipe/_dev/demo_plotters/_helpers.py +31 -0
- figrecipe/_dev/demo_plotters/_registry.py +50 -0
- figrecipe/_dev/demo_plotters/bar_categorical/__init__.py +4 -0
- figrecipe/_dev/demo_plotters/bar_categorical/plot_bar.py +25 -0
- figrecipe/_dev/demo_plotters/bar_categorical/plot_barh.py +25 -0
- figrecipe/_dev/demo_plotters/contour_surface/__init__.py +4 -0
- figrecipe/_dev/demo_plotters/contour_surface/plot_contour.py +30 -0
- figrecipe/_dev/demo_plotters/contour_surface/plot_contourf.py +29 -0
- figrecipe/_dev/demo_plotters/contour_surface/plot_tricontour.py +28 -0
- figrecipe/_dev/demo_plotters/contour_surface/plot_tricontourf.py +28 -0
- figrecipe/_dev/demo_plotters/contour_surface/plot_tripcolor.py +29 -0
- figrecipe/_dev/demo_plotters/contour_surface/plot_triplot.py +25 -0
- figrecipe/_dev/demo_plotters/distribution/__init__.py +4 -0
- figrecipe/_dev/demo_plotters/distribution/plot_boxplot.py +24 -0
- figrecipe/_dev/demo_plotters/distribution/plot_ecdf.py +24 -0
- figrecipe/_dev/demo_plotters/distribution/plot_hist.py +24 -0
- figrecipe/_dev/demo_plotters/distribution/plot_hist2d.py +25 -0
- figrecipe/_dev/demo_plotters/distribution/plot_violinplot.py +25 -0
- figrecipe/_dev/demo_plotters/image_matrix/__init__.py +4 -0
- figrecipe/_dev/demo_plotters/image_matrix/plot_hexbin.py +25 -0
- figrecipe/_dev/demo_plotters/image_matrix/plot_imshow.py +23 -0
- figrecipe/_dev/demo_plotters/image_matrix/plot_matshow.py +23 -0
- figrecipe/_dev/demo_plotters/image_matrix/plot_pcolor.py +29 -0
- figrecipe/_dev/demo_plotters/image_matrix/plot_pcolormesh.py +29 -0
- figrecipe/_dev/demo_plotters/image_matrix/plot_spy.py +29 -0
- figrecipe/_dev/demo_plotters/line_curve/__init__.py +4 -0
- figrecipe/_dev/demo_plotters/line_curve/plot_errorbar.py +28 -0
- figrecipe/_dev/demo_plotters/line_curve/plot_fill.py +29 -0
- figrecipe/_dev/demo_plotters/line_curve/plot_fill_between.py +30 -0
- figrecipe/_dev/demo_plotters/line_curve/plot_fill_betweenx.py +28 -0
- figrecipe/_dev/demo_plotters/line_curve/plot_plot.py +28 -0
- figrecipe/_dev/demo_plotters/line_curve/plot_stackplot.py +29 -0
- figrecipe/_dev/demo_plotters/line_curve/plot_stairs.py +27 -0
- figrecipe/_dev/demo_plotters/line_curve/plot_step.py +27 -0
- figrecipe/_dev/demo_plotters/scatter_points/__init__.py +4 -0
- figrecipe/_dev/demo_plotters/scatter_points/plot_scatter.py +24 -0
- figrecipe/_dev/demo_plotters/special/__init__.py +4 -0
- figrecipe/_dev/demo_plotters/special/plot_eventplot.py +25 -0
- figrecipe/_dev/demo_plotters/special/plot_loglog.py +27 -0
- figrecipe/_dev/demo_plotters/special/plot_pie.py +27 -0
- figrecipe/_dev/demo_plotters/special/plot_semilogx.py +27 -0
- figrecipe/_dev/demo_plotters/special/plot_semilogy.py +27 -0
- figrecipe/_dev/demo_plotters/special/plot_stem.py +27 -0
- figrecipe/_dev/demo_plotters/spectral_signal/__init__.py +4 -0
- figrecipe/_dev/demo_plotters/spectral_signal/plot_acorr.py +24 -0
- figrecipe/_dev/demo_plotters/spectral_signal/plot_angle_spectrum.py +28 -0
- figrecipe/_dev/demo_plotters/spectral_signal/plot_cohere.py +29 -0
- figrecipe/_dev/demo_plotters/spectral_signal/plot_csd.py +29 -0
- figrecipe/_dev/demo_plotters/spectral_signal/plot_magnitude_spectrum.py +28 -0
- figrecipe/_dev/demo_plotters/spectral_signal/plot_phase_spectrum.py +28 -0
- figrecipe/_dev/demo_plotters/spectral_signal/plot_psd.py +29 -0
- figrecipe/_dev/demo_plotters/spectral_signal/plot_specgram.py +30 -0
- figrecipe/_dev/demo_plotters/spectral_signal/plot_xcorr.py +25 -0
- figrecipe/_dev/demo_plotters/vector_flow/__init__.py +4 -0
- figrecipe/_dev/demo_plotters/vector_flow/plot_barbs.py +30 -0
- figrecipe/_dev/demo_plotters/vector_flow/plot_quiver.py +30 -0
- figrecipe/_dev/demo_plotters/vector_flow/plot_streamplot.py +30 -0
- figrecipe/_editor/__init__.py +278 -0
- figrecipe/_editor/_bbox/__init__.py +43 -0
- figrecipe/_editor/_bbox/_collections.py +177 -0
- figrecipe/_editor/_bbox/_elements.py +159 -0
- figrecipe/_editor/_bbox/_extract.py +256 -0
- figrecipe/_editor/_bbox/_extract_axes.py +370 -0
- figrecipe/_editor/_bbox/_extract_text.py +342 -0
- figrecipe/_editor/_bbox/_lines.py +173 -0
- figrecipe/_editor/_bbox/_transforms.py +146 -0
- figrecipe/_editor/_flask_app.py +258 -0
- figrecipe/_editor/_helpers.py +242 -0
- figrecipe/_editor/_hitmap/__init__.py +76 -0
- figrecipe/_editor/_hitmap/_artists/__init__.py +21 -0
- figrecipe/_editor/_hitmap/_artists/_collections.py +345 -0
- figrecipe/_editor/_hitmap/_artists/_images.py +68 -0
- figrecipe/_editor/_hitmap/_artists/_lines.py +107 -0
- figrecipe/_editor/_hitmap/_artists/_patches.py +163 -0
- figrecipe/_editor/_hitmap/_artists/_text.py +190 -0
- figrecipe/_editor/_hitmap/_colors.py +181 -0
- figrecipe/_editor/_hitmap/_detect.py +137 -0
- figrecipe/_editor/_hitmap/_restore.py +154 -0
- figrecipe/_editor/_hitmap_main.py +182 -0
- figrecipe/_editor/_overrides.py +318 -0
- figrecipe/_editor/_preferences.py +135 -0
- figrecipe/_editor/_render_overrides.py +480 -0
- figrecipe/_editor/_renderer.py +199 -0
- figrecipe/_editor/_routes_axis.py +453 -0
- figrecipe/_editor/_routes_core.py +284 -0
- figrecipe/_editor/_routes_element.py +317 -0
- figrecipe/_editor/_routes_style.py +223 -0
- figrecipe/_editor/_templates/__init__.py +152 -0
- figrecipe/_editor/_templates/_html.py +502 -0
- figrecipe/_editor/_templates/_scripts/__init__.py +120 -0
- figrecipe/_editor/_templates/_scripts/_api.py +228 -0
- figrecipe/_editor/_templates/_scripts/_colors.py +485 -0
- figrecipe/_editor/_templates/_scripts/_core.py +436 -0
- figrecipe/_editor/_templates/_scripts/_debug_snapshot.py +186 -0
- figrecipe/_editor/_templates/_scripts/_element_editor.py +310 -0
- figrecipe/_editor/_templates/_scripts/_files.py +195 -0
- figrecipe/_editor/_templates/_scripts/_hitmap.py +509 -0
- figrecipe/_editor/_templates/_scripts/_inspector.py +315 -0
- figrecipe/_editor/_templates/_scripts/_labels.py +464 -0
- figrecipe/_editor/_templates/_scripts/_legend_drag.py +265 -0
- figrecipe/_editor/_templates/_scripts/_modals.py +226 -0
- figrecipe/_editor/_templates/_scripts/_overlays.py +292 -0
- figrecipe/_editor/_templates/_scripts/_panel_drag.py +334 -0
- figrecipe/_editor/_templates/_scripts/_panel_position.py +279 -0
- figrecipe/_editor/_templates/_scripts/_selection.py +237 -0
- figrecipe/_editor/_templates/_scripts/_tabs.py +89 -0
- figrecipe/_editor/_templates/_scripts/_view_mode.py +107 -0
- figrecipe/_editor/_templates/_scripts/_zoom.py +179 -0
- figrecipe/_editor/_templates/_styles/__init__.py +69 -0
- figrecipe/_editor/_templates/_styles/_base.py +64 -0
- figrecipe/_editor/_templates/_styles/_buttons.py +206 -0
- figrecipe/_editor/_templates/_styles/_color_input.py +123 -0
- figrecipe/_editor/_templates/_styles/_controls.py +265 -0
- figrecipe/_editor/_templates/_styles/_dynamic_props.py +144 -0
- figrecipe/_editor/_templates/_styles/_forms.py +126 -0
- figrecipe/_editor/_templates/_styles/_hitmap.py +184 -0
- figrecipe/_editor/_templates/_styles/_inspector.py +90 -0
- figrecipe/_editor/_templates/_styles/_labels.py +118 -0
- figrecipe/_editor/_templates/_styles/_modals.py +98 -0
- figrecipe/_editor/_templates/_styles/_overlays.py +130 -0
- figrecipe/_editor/_templates/_styles/_preview.py +225 -0
- figrecipe/_editor/_templates/_styles/_selection.py +73 -0
- figrecipe/_params/_DECORATION_METHODS.py +33 -0
- figrecipe/_params/_PLOTTING_METHODS.py +58 -0
- figrecipe/_params/__init__.py +9 -0
- figrecipe/_recorder.py +92 -110
- figrecipe/_recorder_utils.py +124 -0
- figrecipe/_reproducer/__init__.py +18 -0
- figrecipe/_reproducer/_core.py +498 -0
- figrecipe/_reproducer/_custom_plots.py +279 -0
- figrecipe/_reproducer/_seaborn.py +100 -0
- figrecipe/_reproducer/_violin.py +186 -0
- figrecipe/_seaborn.py +14 -9
- figrecipe/_serializer.py +2 -2
- figrecipe/_signatures/README.md +68 -0
- figrecipe/_signatures/__init__.py +12 -2
- figrecipe/_signatures/_kwargs.py +273 -0
- figrecipe/_signatures/_loader.py +114 -57
- figrecipe/_signatures/_parsing.py +147 -0
- figrecipe/_utils/__init__.py +6 -4
- figrecipe/_utils/_crop.py +10 -4
- figrecipe/_utils/_image_diff.py +37 -33
- figrecipe/_utils/_numpy_io.py +0 -1
- figrecipe/_utils/_units.py +11 -3
- figrecipe/_validator.py +12 -3
- figrecipe/_wrappers/_axes.py +193 -170
- figrecipe/_wrappers/_axes_helpers.py +136 -0
- figrecipe/_wrappers/_axes_plots.py +418 -0
- figrecipe/_wrappers/_axes_seaborn.py +157 -0
- figrecipe/_wrappers/_figure.py +277 -18
- figrecipe/_wrappers/_panel_labels.py +127 -0
- figrecipe/_wrappers/_plot_helpers.py +143 -0
- figrecipe/_wrappers/_violin_helpers.py +180 -0
- figrecipe/plt.py +0 -1
- figrecipe/pyplot.py +2 -1
- figrecipe/styles/__init__.py +12 -11
- figrecipe/styles/_dotdict.py +72 -0
- figrecipe/styles/_finalize.py +134 -0
- figrecipe/styles/_fonts.py +77 -0
- figrecipe/styles/_kwargs_converter.py +178 -0
- figrecipe/styles/_plot_styles.py +209 -0
- figrecipe/styles/_style_applier.py +60 -202
- figrecipe/styles/_style_loader.py +73 -121
- figrecipe/styles/_themes.py +151 -0
- figrecipe/styles/presets/MATPLOTLIB.yaml +95 -0
- figrecipe/styles/presets/SCITEX.yaml +181 -0
- figrecipe-0.7.4.dist-info/METADATA +429 -0
- figrecipe-0.7.4.dist-info/RECORD +188 -0
- figrecipe/_reproducer.py +0 -358
- figrecipe-0.5.0.dist-info/METADATA +0 -336
- figrecipe-0.5.0.dist-info/RECORD +0 -26
- {figrecipe-0.5.0.dist-info → figrecipe-0.7.4.dist-info}/WHEEL +0 -0
- {figrecipe-0.5.0.dist-info → figrecipe-0.7.4.dist-info}/licenses/LICENSE +0 -0
|
@@ -0,0 +1,315 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
# -*- coding: utf-8 -*-
|
|
3
|
+
"""Element inspector and debug capture JavaScript."""
|
|
4
|
+
|
|
5
|
+
SCRIPTS_INSPECTOR = """
|
|
6
|
+
// ==================== ELEMENT INSPECTOR ====================
|
|
7
|
+
// Visual debugging tool for DOM elements (Alt+I to toggle)
|
|
8
|
+
let elementInspectorActive = false;
|
|
9
|
+
let elementInspectorOverlay = null;
|
|
10
|
+
const inspectorColors = [
|
|
11
|
+
'#FF6B6B', '#4ECDC4', '#45B7D1', '#96CEB4', '#FFEAA7',
|
|
12
|
+
'#DDA0DD', '#98D8C8', '#F7DC6F', '#BB8FCE', '#85C1E9'
|
|
13
|
+
];
|
|
14
|
+
|
|
15
|
+
function toggleElementInspector() {
|
|
16
|
+
if (elementInspectorActive) {
|
|
17
|
+
deactivateElementInspector();
|
|
18
|
+
} else {
|
|
19
|
+
activateElementInspector();
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
function activateElementInspector() {
|
|
24
|
+
console.log('[ElementInspector] Activating...');
|
|
25
|
+
elementInspectorActive = true;
|
|
26
|
+
|
|
27
|
+
// Create overlay container
|
|
28
|
+
elementInspectorOverlay = document.createElement('div');
|
|
29
|
+
elementInspectorOverlay.id = 'element-inspector-overlay';
|
|
30
|
+
elementInspectorOverlay.className = 'element-inspector-overlay';
|
|
31
|
+
document.body.appendChild(elementInspectorOverlay);
|
|
32
|
+
|
|
33
|
+
// Scan and visualize elements
|
|
34
|
+
scanInspectorElements();
|
|
35
|
+
|
|
36
|
+
console.log('[ElementInspector] Active - Press Alt+I to deactivate');
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
function deactivateElementInspector() {
|
|
40
|
+
console.log('[ElementInspector] Deactivating...');
|
|
41
|
+
elementInspectorActive = false;
|
|
42
|
+
|
|
43
|
+
if (elementInspectorOverlay) {
|
|
44
|
+
elementInspectorOverlay.remove();
|
|
45
|
+
elementInspectorOverlay = null;
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
function scanInspectorElements() {
|
|
50
|
+
if (!elementInspectorOverlay) return;
|
|
51
|
+
|
|
52
|
+
// Clear existing overlays
|
|
53
|
+
elementInspectorOverlay.innerHTML = '';
|
|
54
|
+
|
|
55
|
+
// Get all visible elements
|
|
56
|
+
const allElements = document.querySelectorAll('*');
|
|
57
|
+
let colorIndex = 0;
|
|
58
|
+
|
|
59
|
+
allElements.forEach(element => {
|
|
60
|
+
// Skip non-visible, overlay, and script/style elements
|
|
61
|
+
if (element.tagName === 'SCRIPT' || element.tagName === 'STYLE' ||
|
|
62
|
+
element.tagName === 'HEAD' || element.tagName === 'META' ||
|
|
63
|
+
element.tagName === 'LINK' || element.tagName === 'TITLE' ||
|
|
64
|
+
element.id === 'element-inspector-overlay' ||
|
|
65
|
+
element.closest('#element-inspector-overlay')) {
|
|
66
|
+
return;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
const rect = element.getBoundingClientRect();
|
|
70
|
+
|
|
71
|
+
// Skip invisible or zero-size elements
|
|
72
|
+
if (rect.width < 5 || rect.height < 5 ||
|
|
73
|
+
rect.bottom < 0 || rect.right < 0 ||
|
|
74
|
+
rect.top > window.innerHeight || rect.left > window.innerWidth) {
|
|
75
|
+
return;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
// Create element box
|
|
79
|
+
const box = document.createElement('div');
|
|
80
|
+
box.className = 'element-inspector-box';
|
|
81
|
+
const color = inspectorColors[colorIndex % inspectorColors.length];
|
|
82
|
+
box.style.cssText = `
|
|
83
|
+
left: ${rect.left + window.scrollX}px;
|
|
84
|
+
top: ${rect.top + window.scrollY}px;
|
|
85
|
+
width: ${rect.width}px;
|
|
86
|
+
height: ${rect.height}px;
|
|
87
|
+
border-color: ${color};
|
|
88
|
+
`;
|
|
89
|
+
|
|
90
|
+
// Create label
|
|
91
|
+
const label = document.createElement('div');
|
|
92
|
+
label.className = 'element-inspector-label';
|
|
93
|
+
label.style.backgroundColor = color;
|
|
94
|
+
|
|
95
|
+
// Build element identifier
|
|
96
|
+
let identifier = element.tagName.toLowerCase();
|
|
97
|
+
if (element.id) identifier += '#' + element.id;
|
|
98
|
+
if (element.className && typeof element.className === 'string') {
|
|
99
|
+
const classes = element.className.split(' ').filter(c => c && !c.startsWith('element-inspector')).slice(0, 2);
|
|
100
|
+
if (classes.length) identifier += '.' + classes.join('.');
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
label.textContent = identifier;
|
|
104
|
+
box.appendChild(label);
|
|
105
|
+
|
|
106
|
+
// Add click handler to show element info
|
|
107
|
+
box.addEventListener('click', (e) => {
|
|
108
|
+
e.stopPropagation();
|
|
109
|
+
showInspectorElementInfo(element, color);
|
|
110
|
+
});
|
|
111
|
+
|
|
112
|
+
// Right-click to copy element path
|
|
113
|
+
box.addEventListener('contextmenu', (e) => {
|
|
114
|
+
e.preventDefault();
|
|
115
|
+
e.stopPropagation();
|
|
116
|
+
copyInspectorElementPath(element);
|
|
117
|
+
});
|
|
118
|
+
|
|
119
|
+
elementInspectorOverlay.appendChild(box);
|
|
120
|
+
colorIndex++;
|
|
121
|
+
});
|
|
122
|
+
|
|
123
|
+
console.log('[ElementInspector] Scanned ' + colorIndex + ' elements');
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
function showInspectorElementInfo(element, color) {
|
|
127
|
+
// Log element info to console
|
|
128
|
+
console.group('%cElement Info', 'color: ' + color + '; font-weight: bold;');
|
|
129
|
+
console.log('Tag:', element.tagName);
|
|
130
|
+
console.log('ID:', element.id || '(none)');
|
|
131
|
+
console.log('Classes:', element.className || '(none)');
|
|
132
|
+
console.log('Size:', element.offsetWidth + 'x' + element.offsetHeight);
|
|
133
|
+
console.log('Position:', element.getBoundingClientRect());
|
|
134
|
+
console.log('Element:', element);
|
|
135
|
+
console.groupEnd();
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
function copyInspectorElementPath(element) {
|
|
139
|
+
// Build CSS selector path
|
|
140
|
+
const path = [];
|
|
141
|
+
let current = element;
|
|
142
|
+
|
|
143
|
+
while (current && current !== document.body) {
|
|
144
|
+
let selector = current.tagName.toLowerCase();
|
|
145
|
+
if (current.id) {
|
|
146
|
+
selector = '#' + current.id;
|
|
147
|
+
path.unshift(selector);
|
|
148
|
+
break;
|
|
149
|
+
} else if (current.className && typeof current.className === 'string') {
|
|
150
|
+
const classes = current.className.split(' ').filter(c => c).slice(0, 2);
|
|
151
|
+
if (classes.length) selector += '.' + classes.join('.');
|
|
152
|
+
}
|
|
153
|
+
path.unshift(selector);
|
|
154
|
+
current = current.parentElement;
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
const selectorPath = path.join(' > ');
|
|
158
|
+
navigator.clipboard.writeText(selectorPath).then(() => {
|
|
159
|
+
console.log('[ElementInspector] Copied selector:', selectorPath);
|
|
160
|
+
showToast('Copied: ' + selectorPath, 'success');
|
|
161
|
+
});
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
// Shutter effect for screenshot feedback
|
|
165
|
+
function showShutterEffect() {
|
|
166
|
+
const shutter = document.createElement('div');
|
|
167
|
+
shutter.style.cssText = `
|
|
168
|
+
position: fixed;
|
|
169
|
+
top: 0;
|
|
170
|
+
left: 0;
|
|
171
|
+
width: 100vw;
|
|
172
|
+
height: 100vh;
|
|
173
|
+
background: white;
|
|
174
|
+
opacity: 0.8;
|
|
175
|
+
z-index: 99999;
|
|
176
|
+
pointer-events: none;
|
|
177
|
+
animation: shutterFlash 0.3s ease-out forwards;
|
|
178
|
+
`;
|
|
179
|
+
|
|
180
|
+
// Add keyframes if not exists
|
|
181
|
+
if (!document.getElementById('shutter-keyframes')) {
|
|
182
|
+
const style = document.createElement('style');
|
|
183
|
+
style.id = 'shutter-keyframes';
|
|
184
|
+
style.textContent = `
|
|
185
|
+
@keyframes shutterFlash {
|
|
186
|
+
0% { opacity: 0.8; }
|
|
187
|
+
100% { opacity: 0; }
|
|
188
|
+
}
|
|
189
|
+
`;
|
|
190
|
+
document.head.appendChild(style);
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
document.body.appendChild(shutter);
|
|
194
|
+
setTimeout(() => shutter.remove(), 300);
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
// Capture debug info: full-page screenshot first, then console logs after delay
|
|
198
|
+
async function captureDebugInfo() {
|
|
199
|
+
const timestamp = new Date().toISOString().replace(/[:.]/g, '-');
|
|
200
|
+
|
|
201
|
+
// Show shutter effect
|
|
202
|
+
showShutterEffect();
|
|
203
|
+
|
|
204
|
+
// Step 1: Capture full page screenshot using html2canvas, fallback to figure only
|
|
205
|
+
try {
|
|
206
|
+
let blob = null;
|
|
207
|
+
|
|
208
|
+
// Try html2canvas for full page capture
|
|
209
|
+
if (typeof html2canvas !== 'undefined') {
|
|
210
|
+
try {
|
|
211
|
+
console.log('[DebugCapture] Attempting full-page capture with html2canvas...');
|
|
212
|
+
const canvas = await html2canvas(document.body, {
|
|
213
|
+
useCORS: true,
|
|
214
|
+
allowTaint: true,
|
|
215
|
+
logging: false,
|
|
216
|
+
backgroundColor: document.documentElement.getAttribute('data-theme') === 'dark' ? '#1e1e1e' : '#ffffff',
|
|
217
|
+
ignoreElements: (element) => {
|
|
218
|
+
// Skip script and noscript elements
|
|
219
|
+
return element.tagName === 'SCRIPT' || element.tagName === 'NOSCRIPT';
|
|
220
|
+
}
|
|
221
|
+
});
|
|
222
|
+
blob = await new Promise(resolve => canvas.toBlob(resolve, 'image/png'));
|
|
223
|
+
console.log('[DebugCapture] Full-page capture successful');
|
|
224
|
+
} catch (html2canvasErr) {
|
|
225
|
+
console.warn('[DebugCapture] html2canvas failed, falling back to figure only:', html2canvasErr.message);
|
|
226
|
+
}
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
// Fallback: copy just the figure image
|
|
230
|
+
if (!blob) {
|
|
231
|
+
const img = document.getElementById('preview-image');
|
|
232
|
+
if (img && img.src) {
|
|
233
|
+
const response = await fetch(img.src);
|
|
234
|
+
blob = await response.blob();
|
|
235
|
+
console.log('[DebugCapture] Fallback: copied figure image only');
|
|
236
|
+
}
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
if (blob) {
|
|
240
|
+
await navigator.clipboard.write([
|
|
241
|
+
new ClipboardItem({ [blob.type]: blob })
|
|
242
|
+
]);
|
|
243
|
+
showToast('Screenshot copied! Paste now. Text in 2s...', 'success');
|
|
244
|
+
console.log('[DebugCapture] Image copied to clipboard');
|
|
245
|
+
} else {
|
|
246
|
+
showToast('No image captured, copying text only...', 'warning');
|
|
247
|
+
}
|
|
248
|
+
} catch (err) {
|
|
249
|
+
console.error('[DebugCapture] Image copy failed:', err);
|
|
250
|
+
showToast('Image copy failed, copying text...', 'warning');
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
// Step 2: Wait 2 seconds, then copy debug text
|
|
254
|
+
setTimeout(async () => {
|
|
255
|
+
let debugInfo = `=== Debug Capture: ${timestamp} ===\\n\\n`;
|
|
256
|
+
|
|
257
|
+
// Collect console logs
|
|
258
|
+
debugInfo += '=== Console Logs ===\\n';
|
|
259
|
+
if (window.consoleLogs && window.consoleLogs.length > 0) {
|
|
260
|
+
window.consoleLogs.forEach(log => {
|
|
261
|
+
debugInfo += `[${log.type}] ${log.message}\\n`;
|
|
262
|
+
});
|
|
263
|
+
} else {
|
|
264
|
+
debugInfo += '(No logs captured)\\n';
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
// Add current state info
|
|
268
|
+
debugInfo += '\\n=== Current State ===\\n';
|
|
269
|
+
debugInfo += `URL: ${window.location.href}\\n`;
|
|
270
|
+
debugInfo += `Selected Element: ${selectedElement ? selectedElement.key : 'None'}\\n`;
|
|
271
|
+
debugInfo += `Zoom Level: ${Math.round(zoomLevel * 100)}%\\n`;
|
|
272
|
+
debugInfo += `Theme: ${document.documentElement.getAttribute('data-theme') || 'light'}\\n`;
|
|
273
|
+
|
|
274
|
+
try {
|
|
275
|
+
await navigator.clipboard.writeText(debugInfo);
|
|
276
|
+
showToast('Debug text copied! Paste now.', 'success');
|
|
277
|
+
console.log('[DebugCapture] Text copied:', debugInfo);
|
|
278
|
+
} catch (err) {
|
|
279
|
+
console.error('[DebugCapture] Text copy failed:', err);
|
|
280
|
+
showToast('Text copy failed: ' + err.message, 'error');
|
|
281
|
+
}
|
|
282
|
+
}, 2000);
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
// Console log interceptor (captures logs for debug export)
|
|
286
|
+
window.consoleLogs = [];
|
|
287
|
+
const originalConsole = {
|
|
288
|
+
log: console.log,
|
|
289
|
+
warn: console.warn,
|
|
290
|
+
error: console.error
|
|
291
|
+
};
|
|
292
|
+
|
|
293
|
+
console.log = function(...args) {
|
|
294
|
+
window.consoleLogs.push({ type: 'LOG', message: args.join(' '), time: new Date() });
|
|
295
|
+
if (window.consoleLogs.length > 100) window.consoleLogs.shift();
|
|
296
|
+
originalConsole.log.apply(console, args);
|
|
297
|
+
};
|
|
298
|
+
|
|
299
|
+
console.warn = function(...args) {
|
|
300
|
+
window.consoleLogs.push({ type: 'WARN', message: args.join(' '), time: new Date() });
|
|
301
|
+
if (window.consoleLogs.length > 100) window.consoleLogs.shift();
|
|
302
|
+
originalConsole.warn.apply(console, args);
|
|
303
|
+
};
|
|
304
|
+
|
|
305
|
+
console.error = function(...args) {
|
|
306
|
+
window.consoleLogs.push({ type: 'ERROR', message: args.join(' '), time: new Date() });
|
|
307
|
+
if (window.consoleLogs.length > 100) window.consoleLogs.shift();
|
|
308
|
+
originalConsole.error.apply(console, args);
|
|
309
|
+
};
|
|
310
|
+
|
|
311
|
+
console.log('[ElementInspector] Loaded - Press Alt+I to toggle');
|
|
312
|
+
console.log('[DebugCapture] Loaded - Press Alt+Shift+I for screenshot + logs');
|
|
313
|
+
"""
|
|
314
|
+
|
|
315
|
+
__all__ = ["SCRIPTS_INSPECTOR"]
|