]>
jfr.im git - dlqueue.git/blob - venv/lib/python3.11/site-packages/werkzeug/debug/shared/debugger.js
5 // if we are in console mode, show the console.
6 if (CONSOLE_MODE
&& EVALEX
) {
7 createInteractiveConsole();
10 const frames
= document
.querySelectorAll("div.traceback div.frame");
12 addConsoleIconToFrames(frames
);
14 addEventListenersToElements(document
.querySelectorAll("div.detail"), "click", () =>
15 document
.querySelector("div.traceback").scrollIntoView(false)
17 addToggleFrameTraceback(frames
);
18 addToggleTraceTypesOnClick(document
.querySelectorAll("h2.traceback"));
19 addInfoPrompt(document
.querySelectorAll("span.nojavascript"));
23 function addToggleFrameTraceback(frames
) {
24 frames
.forEach((frame
) => {
25 frame
.addEventListener("click", () => {
26 frame
.getElementsByTagName("pre")[0].parentElement
.classList
.toggle("expanded");
32 function wrapPlainTraceback() {
33 const plainTraceback
= document
.querySelector("div.plain textarea");
34 const wrapper
= document
.createElement("pre");
35 const textNode
= document
.createTextNode(plainTraceback
.textContent
);
36 wrapper
.appendChild(textNode
);
37 plainTraceback
.replaceWith(wrapper
);
40 function initPinBox() {
41 document
.querySelector(".pin-prompt form").addEventListener(
44 event
.preventDefault();
45 const pin
= encodeURIComponent(this.pin
.value
);
46 const encodedSecret
= encodeURIComponent(SECRET
);
51 `${document.location.pathname}?__debugger__=yes&cmd=pinauth&pin=${pin}&s=${encodedSecret}`
53 .then((res
) => res
.json())
54 .then(({auth
, exhausted
}) => {
56 EVALEX_TRUSTED
= true;
57 fadeOut(document
.getElementsByClassName("pin-prompt")[0]);
62 ? "too many attempts. Restart server to retry."
69 alert("Error: Could not verify PIN. Network error?");
72 .finally(() => (btn
.disabled
= false));
78 function promptForPin() {
79 if (!EVALEX_TRUSTED
) {
80 const encodedSecret
= encodeURIComponent(SECRET
);
82 `${document.location.pathname}?__debugger__=yes&cmd=printpin&s=${encodedSecret}`
84 const pinPrompt
= document
.getElementsByClassName("pin-prompt")[0];
86 document
.querySelector('.pin-prompt input[name="pin"]').focus();
91 * Helper function for shell initialization
93 function openShell(consoleNode
, target
, frameID
) {
96 slideToggle(consoleNode
);
100 const history
= [""];
101 const consoleElement
= createConsole();
102 const output
= createConsoleOutput();
103 const form
= createConsoleInputForm();
104 const command
= createConsoleInput();
106 target
.parentNode
.appendChild(consoleElement
);
107 consoleElement
.append(output
);
108 consoleElement
.append(form
);
109 form
.append(command
);
111 slideToggle(consoleElement
);
113 form
.addEventListener("submit", (e
) => {
114 handleConsoleSubmit(e
, command
, frameID
).then((consoleOutput
) => {
115 output
.append(consoleOutput
);
117 consoleElement
.scrollTo(0, consoleElement
.scrollHeight
);
118 const old
= history
.pop();
119 history
.push(command
.value
);
120 if (typeof old
!== "undefined") {
123 historyPos
= history
.length
- 1;
128 command
.addEventListener("keydown", (e
) => {
129 if (e
.key
=== "l" && e
.ctrlKey
) {
130 output
.innerText
= "--- screen cleared ---";
131 } else if (e
.key
=== "ArrowUp" || e
.key
=== "ArrowDown") {
132 // Handle up arrow and down arrow.
133 if (e
.key
=== "ArrowUp" && historyPos
> 0) {
136 } else if (e
.key
=== "ArrowDown" && historyPos
< history
.length
- 1) {
139 command
.value
= history
[historyPos
];
144 return consoleElement
;
147 function addEventListenersToElements(elements
, event
, listener
) {
148 elements
.forEach((el
) => el
.addEventListener(event
, listener
));
154 function addInfoPrompt(elements
) {
155 for (let i
= 0; i
< elements
.length
; i
++) {
156 elements
[i
].innerHTML
=
157 "<p>To switch between the interactive traceback and the plaintext " +
158 'one, you can click on the "Traceback" headline. From the text ' +
159 "traceback you can also create a paste of it. " +
162 : "For code execution mouse-over the frame you want to debug and " +
163 "click on the console icon on the right side." +
164 "<p>You can execute arbitrary Python code in the stack frames and " +
165 "there are some extra helpers available for introspection:" +
166 "<ul><li><code>dump()</code> shows all variables in the frame" +
167 "<li><code>dump(obj)</code> dumps all that's known about the object</ul>");
168 elements
[i
].classList
.remove("nojavascript");
172 function addConsoleIconToFrames(frames
) {
173 for (let i
= 0; i
< frames
.length
; i
++) {
174 let consoleNode
= null;
175 const target
= frames
[i
];
176 const frameID
= frames
[i
].id
.substring(6);
178 for (let j
= 0; j
< target
.getElementsByTagName("pre").length
; j
++) {
179 const img
= createIconForConsole();
180 img
.addEventListener("click", (e
) => {
182 consoleNode
= openShell(consoleNode
, target
, frameID
);
185 target
.getElementsByTagName("pre")[j
].append(img
);
190 function slideToggle(target
) {
191 target
.classList
.toggle("active");
195 * toggle traceback types on click.
197 function addToggleTraceTypesOnClick(elements
) {
198 for (let i
= 0; i
< elements
.length
; i
++) {
199 elements
[i
].addEventListener("click", () => {
200 document
.querySelector("div.traceback").classList
.toggle("hidden");
201 document
.querySelector("div.plain").classList
.toggle("hidden");
203 elements
[i
].style
.cursor
= "pointer";
204 document
.querySelector("div.plain").classList
.toggle("hidden");
208 function createConsole() {
209 const consoleNode
= document
.createElement("pre");
210 consoleNode
.classList
.add("console");
211 consoleNode
.classList
.add("active");
215 function createConsoleOutput() {
216 const output
= document
.createElement("div");
217 output
.classList
.add("output");
218 output
.innerHTML
= "[console ready]";
222 function createConsoleInputForm() {
223 const form
= document
.createElement("form");
224 form
.innerHTML
= ">>> ";
228 function createConsoleInput() {
229 const command
= document
.createElement("input");
230 command
.type
= "text";
231 command
.setAttribute("autocomplete", "off");
232 command
.setAttribute("spellcheck", false);
233 command
.setAttribute("autocapitalize", "off");
234 command
.setAttribute("autocorrect", "off");
238 function createIconForConsole() {
239 const img
= document
.createElement("img");
240 img
.setAttribute("src", "?__debugger__=yes&cmd=resource&f=console.png");
241 img
.setAttribute("title", "Open an interactive python shell in this frame");
245 function createExpansionButtonForConsole() {
246 const expansionButton
= document
.createElement("a");
247 expansionButton
.setAttribute("href", "#");
248 expansionButton
.setAttribute("class", "toggle");
249 expansionButton
.innerHTML
= " ";
250 return expansionButton
;
253 function createInteractiveConsole() {
254 const target
= document
.querySelector("div.console div.inner");
255 while (target
.firstChild
) {
256 target
.removeChild(target
.firstChild
);
258 openShell(null, target
, 0);
261 function handleConsoleSubmit(e
, command
, frameID
) {
262 // Prevent page from refreshing.
265 return new Promise((resolve
) => {
266 // Get input command.
267 const cmd
= command
.value
;
269 // Setup GET request.
277 const paramString
= Object
.keys(params
)
279 return "&" + encodeURIComponent(key
) + "=" + encodeURIComponent(params
[key
]);
283 fetch(urlPath
+ "?" + paramString
)
288 const tmp
= document
.createElement("div");
289 tmp
.innerHTML
= data
;
292 // Handle expandable span for long list outputs.
293 // Example to test: list(range(13))
294 let wrapperAdded
= false;
295 const wrapperSpan
= document
.createElement("span");
296 const expansionButton
= createExpansionButtonForConsole();
298 tmp
.querySelectorAll("span.extended").forEach((spanToWrap
) => {
299 const parentDiv
= spanToWrap
.parentNode
;
301 parentDiv
.insertBefore(wrapperSpan
, spanToWrap
);
304 parentDiv
.removeChild(spanToWrap
);
305 wrapperSpan
.append(spanToWrap
);
306 spanToWrap
.hidden
= true;
308 expansionButton
.addEventListener("click", (event
) => {
309 event
.preventDefault();
310 spanToWrap
.hidden
= !spanToWrap
.hidden
;
311 expansionButton
.classList
.toggle("open");
316 // Add expansion button at end of wrapper.
318 wrapperSpan
.append(expansionButton
);
328 function fadeOut(element
) {
329 element
.style
.opacity
= 1;
332 element
.style
.opacity
-= 0.1;
333 if (element
.style
.opacity
< 0) {
334 element
.style
.display
= "none";
336 requestAnimationFrame(fade
);
341 function fadeIn(element
, display
) {
342 element
.style
.opacity
= 0;
343 element
.style
.display
= display
|| "block";
346 let val
= parseFloat(element
.style
.opacity
) + 0.1;
348 element
.style
.opacity
= val
;
349 requestAnimationFrame(fade
);
354 function docReady(fn
) {
355 if (document
.readyState
=== "complete" || document
.readyState
=== "interactive") {
358 document
.addEventListener("DOMContentLoaded", fn
);