]> jfr.im git - dlqueue.git/blob - venv/lib/python3.11/site-packages/werkzeug/debug/shared/debugger.js
init: venv aand flask
[dlqueue.git] / venv / lib / python3.11 / site-packages / werkzeug / debug / shared / debugger.js
1 docReady(() => {
2 if (!EVALEX_TRUSTED) {
3 initPinBox();
4 }
5 // if we are in console mode, show the console.
6 if (CONSOLE_MODE && EVALEX) {
7 createInteractiveConsole();
8 }
9
10 const frames = document.querySelectorAll("div.traceback div.frame");
11 if (EVALEX) {
12 addConsoleIconToFrames(frames);
13 }
14 addEventListenersToElements(document.querySelectorAll("div.detail"), "click", () =>
15 document.querySelector("div.traceback").scrollIntoView(false)
16 );
17 addToggleFrameTraceback(frames);
18 addToggleTraceTypesOnClick(document.querySelectorAll("h2.traceback"));
19 addInfoPrompt(document.querySelectorAll("span.nojavascript"));
20 wrapPlainTraceback();
21 });
22
23 function addToggleFrameTraceback(frames) {
24 frames.forEach((frame) => {
25 frame.addEventListener("click", () => {
26 frame.getElementsByTagName("pre")[0].parentElement.classList.toggle("expanded");
27 });
28 })
29 }
30
31
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);
38 }
39
40 function initPinBox() {
41 document.querySelector(".pin-prompt form").addEventListener(
42 "submit",
43 function (event) {
44 event.preventDefault();
45 const pin = encodeURIComponent(this.pin.value);
46 const encodedSecret = encodeURIComponent(SECRET);
47 const btn = this.btn;
48 btn.disabled = true;
49
50 fetch(
51 `${document.location.pathname}?__debugger__=yes&cmd=pinauth&pin=${pin}&s=${encodedSecret}`
52 )
53 .then((res) => res.json())
54 .then(({auth, exhausted}) => {
55 if (auth) {
56 EVALEX_TRUSTED = true;
57 fadeOut(document.getElementsByClassName("pin-prompt")[0]);
58 } else {
59 alert(
60 `Error: ${
61 exhausted
62 ? "too many attempts. Restart server to retry."
63 : "incorrect pin"
64 }`
65 );
66 }
67 })
68 .catch((err) => {
69 alert("Error: Could not verify PIN. Network error?");
70 console.error(err);
71 })
72 .finally(() => (btn.disabled = false));
73 },
74 false
75 );
76 }
77
78 function promptForPin() {
79 if (!EVALEX_TRUSTED) {
80 const encodedSecret = encodeURIComponent(SECRET);
81 fetch(
82 `${document.location.pathname}?__debugger__=yes&cmd=printpin&s=${encodedSecret}`
83 );
84 const pinPrompt = document.getElementsByClassName("pin-prompt")[0];
85 fadeIn(pinPrompt);
86 document.querySelector('.pin-prompt input[name="pin"]').focus();
87 }
88 }
89
90 /**
91 * Helper function for shell initialization
92 */
93 function openShell(consoleNode, target, frameID) {
94 promptForPin();
95 if (consoleNode) {
96 slideToggle(consoleNode);
97 return consoleNode;
98 }
99 let historyPos = 0;
100 const history = [""];
101 const consoleElement = createConsole();
102 const output = createConsoleOutput();
103 const form = createConsoleInputForm();
104 const command = createConsoleInput();
105
106 target.parentNode.appendChild(consoleElement);
107 consoleElement.append(output);
108 consoleElement.append(form);
109 form.append(command);
110 command.focus();
111 slideToggle(consoleElement);
112
113 form.addEventListener("submit", (e) => {
114 handleConsoleSubmit(e, command, frameID).then((consoleOutput) => {
115 output.append(consoleOutput);
116 command.focus();
117 consoleElement.scrollTo(0, consoleElement.scrollHeight);
118 const old = history.pop();
119 history.push(command.value);
120 if (typeof old !== "undefined") {
121 history.push(old);
122 }
123 historyPos = history.length - 1;
124 command.value = "";
125 });
126 });
127
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) {
134 e.preventDefault();
135 historyPos--;
136 } else if (e.key === "ArrowDown" && historyPos < history.length - 1) {
137 historyPos++;
138 }
139 command.value = history[historyPos];
140 }
141 return false;
142 });
143
144 return consoleElement;
145 }
146
147 function addEventListenersToElements(elements, event, listener) {
148 elements.forEach((el) => el.addEventListener(event, listener));
149 }
150
151 /**
152 * Add extra info
153 */
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. " +
160 (!EVALEX
161 ? ""
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");
169 }
170 }
171
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);
177
178 for (let j = 0; j < target.getElementsByTagName("pre").length; j++) {
179 const img = createIconForConsole();
180 img.addEventListener("click", (e) => {
181 e.stopPropagation();
182 consoleNode = openShell(consoleNode, target, frameID);
183 return false;
184 });
185 target.getElementsByTagName("pre")[j].append(img);
186 }
187 }
188 }
189
190 function slideToggle(target) {
191 target.classList.toggle("active");
192 }
193
194 /**
195 * toggle traceback types on click.
196 */
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");
202 });
203 elements[i].style.cursor = "pointer";
204 document.querySelector("div.plain").classList.toggle("hidden");
205 }
206 }
207
208 function createConsole() {
209 const consoleNode = document.createElement("pre");
210 consoleNode.classList.add("console");
211 consoleNode.classList.add("active");
212 return consoleNode;
213 }
214
215 function createConsoleOutput() {
216 const output = document.createElement("div");
217 output.classList.add("output");
218 output.innerHTML = "[console ready]";
219 return output;
220 }
221
222 function createConsoleInputForm() {
223 const form = document.createElement("form");
224 form.innerHTML = "&gt;&gt;&gt; ";
225 return form;
226 }
227
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");
235 return command;
236 }
237
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");
242 return img;
243 }
244
245 function createExpansionButtonForConsole() {
246 const expansionButton = document.createElement("a");
247 expansionButton.setAttribute("href", "#");
248 expansionButton.setAttribute("class", "toggle");
249 expansionButton.innerHTML = "&nbsp;&nbsp;";
250 return expansionButton;
251 }
252
253 function createInteractiveConsole() {
254 const target = document.querySelector("div.console div.inner");
255 while (target.firstChild) {
256 target.removeChild(target.firstChild);
257 }
258 openShell(null, target, 0);
259 }
260
261 function handleConsoleSubmit(e, command, frameID) {
262 // Prevent page from refreshing.
263 e.preventDefault();
264
265 return new Promise((resolve) => {
266 // Get input command.
267 const cmd = command.value;
268
269 // Setup GET request.
270 const urlPath = "";
271 const params = {
272 __debugger__: "yes",
273 cmd: cmd,
274 frm: frameID,
275 s: SECRET,
276 };
277 const paramString = Object.keys(params)
278 .map((key) => {
279 return "&" + encodeURIComponent(key) + "=" + encodeURIComponent(params[key]);
280 })
281 .join("");
282
283 fetch(urlPath + "?" + paramString)
284 .then((res) => {
285 return res.text();
286 })
287 .then((data) => {
288 const tmp = document.createElement("div");
289 tmp.innerHTML = data;
290 resolve(tmp);
291
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();
297
298 tmp.querySelectorAll("span.extended").forEach((spanToWrap) => {
299 const parentDiv = spanToWrap.parentNode;
300 if (!wrapperAdded) {
301 parentDiv.insertBefore(wrapperSpan, spanToWrap);
302 wrapperAdded = true;
303 }
304 parentDiv.removeChild(spanToWrap);
305 wrapperSpan.append(spanToWrap);
306 spanToWrap.hidden = true;
307
308 expansionButton.addEventListener("click", (event) => {
309 event.preventDefault();
310 spanToWrap.hidden = !spanToWrap.hidden;
311 expansionButton.classList.toggle("open");
312 return false;
313 });
314 });
315
316 // Add expansion button at end of wrapper.
317 if (wrapperAdded) {
318 wrapperSpan.append(expansionButton);
319 }
320 })
321 .catch((err) => {
322 console.error(err);
323 });
324 return false;
325 });
326 }
327
328 function fadeOut(element) {
329 element.style.opacity = 1;
330
331 (function fade() {
332 element.style.opacity -= 0.1;
333 if (element.style.opacity < 0) {
334 element.style.display = "none";
335 } else {
336 requestAnimationFrame(fade);
337 }
338 })();
339 }
340
341 function fadeIn(element, display) {
342 element.style.opacity = 0;
343 element.style.display = display || "block";
344
345 (function fade() {
346 let val = parseFloat(element.style.opacity) + 0.1;
347 if (val <= 1) {
348 element.style.opacity = val;
349 requestAnimationFrame(fade);
350 }
351 })();
352 }
353
354 function docReady(fn) {
355 if (document.readyState === "complete" || document.readyState === "interactive") {
356 setTimeout(fn, 1);
357 } else {
358 document.addEventListener("DOMContentLoaded", fn);
359 }
360 }