munchboka-edutools 0.1.13__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.
Potentially problematic release.
This version of munchboka-edutools might be problematic. Click here for more details.
- munchboka_edutools/__init__.py +184 -0
- munchboka_edutools/_plotmath_shim.py +126 -0
- munchboka_edutools/_version.py +2 -0
- munchboka_edutools/directives/__init__.py +1 -0
- munchboka_edutools/directives/admonitions.py +389 -0
- munchboka_edutools/directives/cas_popup.py +272 -0
- munchboka_edutools/directives/clear.py +103 -0
- munchboka_edutools/directives/dialogue.py +137 -0
- munchboka_edutools/directives/escape_room.py +296 -0
- munchboka_edutools/directives/factor_tree.py +549 -0
- munchboka_edutools/directives/ggb.py +209 -0
- munchboka_edutools/directives/ggb_icon.py +105 -0
- munchboka_edutools/directives/ggb_popup.py +165 -0
- munchboka_edutools/directives/horner.py +324 -0
- munchboka_edutools/directives/interactive_code.py +75 -0
- munchboka_edutools/directives/jeopardy.py +252 -0
- munchboka_edutools/directives/multi_plot.py +1126 -0
- munchboka_edutools/directives/pair_puzzle.py +191 -0
- munchboka_edutools/directives/parsons.py +109 -0
- munchboka_edutools/directives/plot.py +3105 -0
- munchboka_edutools/directives/poly_icon.py +111 -0
- munchboka_edutools/directives/polydiv.py +344 -0
- munchboka_edutools/directives/popup.py +245 -0
- munchboka_edutools/directives/quiz.py +291 -0
- munchboka_edutools/directives/signchart.py +516 -0
- munchboka_edutools/directives/timed_quiz.py +436 -0
- munchboka_edutools/directives/turtle.py +157 -0
- munchboka_edutools/static/css/admonitions.css +2012 -0
- munchboka_edutools/static/css/cas_popup.css +242 -0
- munchboka_edutools/static/css/code_mirror_themes/github_dark_cm.css +112 -0
- munchboka_edutools/static/css/code_mirror_themes/github_dark_default_cm.css +40 -0
- munchboka_edutools/static/css/code_mirror_themes/github_dark_high_contrast_cm.css +141 -0
- munchboka_edutools/static/css/code_mirror_themes/github_light_cm.css +120 -0
- munchboka_edutools/static/css/code_mirror_themes/github_light_default_cm.css +108 -0
- munchboka_edutools/static/css/code_mirror_themes/one_dark_cm.css +121 -0
- munchboka_edutools/static/css/dialogue.css +92 -0
- munchboka_edutools/static/css/escapeRoom/escape-room.css +223 -0
- munchboka_edutools/static/css/figures.css +274 -0
- munchboka_edutools/static/css/general_style.css +74 -0
- munchboka_edutools/static/css/github-dark-high-contrast.css +141 -0
- munchboka_edutools/static/css/github-dark.css +112 -0
- munchboka_edutools/static/css/github-light.css +120 -0
- munchboka_edutools/static/css/interactive_code/style.css +575 -0
- munchboka_edutools/static/css/interactive_code.css +582 -0
- munchboka_edutools/static/css/jeopardy.css +529 -0
- munchboka_edutools/static/css/pairPuzzle/style.css +177 -0
- munchboka_edutools/static/css/parsons/parsonsPuzzle.css +331 -0
- munchboka_edutools/static/css/popup.css +115 -0
- munchboka_edutools/static/css/quiz.css +312 -0
- munchboka_edutools/static/css/timedQuiz.css +375 -0
- munchboka_edutools/static/icons/ggb/mode_evaluate.svg +1 -0
- munchboka_edutools/static/icons/ggb/mode_extremum.svg +1 -0
- munchboka_edutools/static/icons/ggb/mode_intersect.svg +1 -0
- munchboka_edutools/static/icons/ggb/mode_nsolve.svg +1 -0
- munchboka_edutools/static/icons/ggb/mode_numeric.svg +1 -0
- munchboka_edutools/static/icons/ggb/mode_point.svg +1 -0
- munchboka_edutools/static/icons/ggb/mode_solve.svg +1 -0
- munchboka_edutools/static/icons/misc/windows-logo.svg +1 -0
- munchboka_edutools/static/icons/outline/dark_mode/academic.svg +3 -0
- munchboka_edutools/static/icons/outline/dark_mode/backward.svg +3 -0
- munchboka_edutools/static/icons/outline/dark_mode/book.svg +3 -0
- munchboka_edutools/static/icons/outline/dark_mode/chat_bubble.svg +3 -0
- munchboka_edutools/static/icons/outline/dark_mode/check.svg +3 -0
- munchboka_edutools/static/icons/outline/dark_mode/cmd_line.svg +3 -0
- munchboka_edutools/static/icons/outline/dark_mode/file.svg +1 -0
- munchboka_edutools/static/icons/outline/dark_mode/fire.svg +4 -0
- munchboka_edutools/static/icons/outline/dark_mode/key.svg +3 -0
- munchboka_edutools/static/icons/outline/dark_mode/magnifying.svg +3 -0
- munchboka_edutools/static/icons/outline/dark_mode/pencil_square.svg +3 -0
- munchboka_edutools/static/icons/outline/dark_mode/play.svg +3 -0
- munchboka_edutools/static/icons/outline/dark_mode/question.svg +3 -0
- munchboka_edutools/static/icons/outline/dark_mode/square_check.svg +1 -0
- munchboka_edutools/static/icons/outline/dark_mode/stop.svg +3 -0
- munchboka_edutools/static/icons/outline/dark_mode/summary.svg +3 -0
- munchboka_edutools/static/icons/outline/dark_mode/undo.svg +3 -0
- munchboka_edutools/static/icons/outline/dark_mode/unlock.svg +3 -0
- munchboka_edutools/static/icons/outline/light_mode/academic.svg +3 -0
- munchboka_edutools/static/icons/outline/light_mode/backward.svg +3 -0
- munchboka_edutools/static/icons/outline/light_mode/book.svg +3 -0
- munchboka_edutools/static/icons/outline/light_mode/chat_bubble.svg +3 -0
- munchboka_edutools/static/icons/outline/light_mode/check.svg +3 -0
- munchboka_edutools/static/icons/outline/light_mode/cmd_line.svg +3 -0
- munchboka_edutools/static/icons/outline/light_mode/file.svg +1 -0
- munchboka_edutools/static/icons/outline/light_mode/fire.svg +4 -0
- munchboka_edutools/static/icons/outline/light_mode/key.svg +3 -0
- munchboka_edutools/static/icons/outline/light_mode/magnifying.svg +3 -0
- munchboka_edutools/static/icons/outline/light_mode/pencil_square.svg +3 -0
- munchboka_edutools/static/icons/outline/light_mode/play.svg +3 -0
- munchboka_edutools/static/icons/outline/light_mode/question.svg +3 -0
- munchboka_edutools/static/icons/outline/light_mode/square_check.svg +1 -0
- munchboka_edutools/static/icons/outline/light_mode/stop.svg +3 -0
- munchboka_edutools/static/icons/outline/light_mode/summary.svg +3 -0
- munchboka_edutools/static/icons/outline/light_mode/undo.svg +3 -0
- munchboka_edutools/static/icons/outline/light_mode/unlock.svg +3 -0
- munchboka_edutools/static/icons/polyicons/cubicdown.svg +3 -0
- munchboka_edutools/static/icons/polyicons/cubicup.svg +3 -0
- munchboka_edutools/static/icons/polyicons/frown.svg +3 -0
- munchboka_edutools/static/icons/polyicons/smile.svg +3 -0
- munchboka_edutools/static/icons/solid/dark_mode/academic.svg +5 -0
- munchboka_edutools/static/icons/solid/dark_mode/backward.svg +3 -0
- munchboka_edutools/static/icons/solid/dark_mode/book.svg +3 -0
- munchboka_edutools/static/icons/solid/dark_mode/brain.svg +1 -0
- munchboka_edutools/static/icons/solid/dark_mode/file.svg +1 -0
- munchboka_edutools/static/icons/solid/dark_mode/fire.svg +3 -0
- munchboka_edutools/static/icons/solid/dark_mode/key.svg +3 -0
- munchboka_edutools/static/icons/solid/dark_mode/pencil_square.svg +4 -0
- munchboka_edutools/static/icons/solid/dark_mode/play.svg +3 -0
- munchboka_edutools/static/icons/solid/dark_mode/python.svg +1 -0
- munchboka_edutools/static/icons/solid/dark_mode/scroll.svg +1 -0
- munchboka_edutools/static/icons/solid/dark_mode/stop.svg +3 -0
- munchboka_edutools/static/icons/solid/light_mode/academic.svg +5 -0
- munchboka_edutools/static/icons/solid/light_mode/backward.svg +3 -0
- munchboka_edutools/static/icons/solid/light_mode/book.svg +3 -0
- munchboka_edutools/static/icons/solid/light_mode/brain.svg +1 -0
- munchboka_edutools/static/icons/solid/light_mode/file.svg +1 -0
- munchboka_edutools/static/icons/solid/light_mode/fire.svg +3 -0
- munchboka_edutools/static/icons/solid/light_mode/key.svg +3 -0
- munchboka_edutools/static/icons/solid/light_mode/pencil_square.svg +4 -0
- munchboka_edutools/static/icons/solid/light_mode/play.svg +3 -0
- munchboka_edutools/static/icons/solid/light_mode/python.svg +1 -0
- munchboka_edutools/static/icons/solid/light_mode/scroll.svg +1 -0
- munchboka_edutools/static/icons/solid/light_mode/stop.svg +3 -0
- munchboka_edutools/static/icons/stickers/edit.svg +1 -0
- munchboka_edutools/static/icons/stickers/pencil_square.svg +3 -0
- munchboka_edutools/static/js/casThemeManager.js +99 -0
- munchboka_edutools/static/js/escapeRoom/escape-room.js +219 -0
- munchboka_edutools/static/js/geogebra-setup.js +6 -0
- munchboka_edutools/static/js/highlight-init.js +6 -0
- munchboka_edutools/static/js/interactiveCode/codeEditor.js +632 -0
- munchboka_edutools/static/js/interactiveCode/interactiveCodeSetup.js +348 -0
- munchboka_edutools/static/js/interactiveCode/pythonRunner.js +336 -0
- munchboka_edutools/static/js/interactiveCode/turtleCode.js +203 -0
- munchboka_edutools/static/js/interactiveCode/workerManager.js +353 -0
- munchboka_edutools/static/js/jeopardy.js +523 -0
- munchboka_edutools/static/js/pairPuzzle/draggableItem.js +64 -0
- munchboka_edutools/static/js/pairPuzzle/dropZone.js +119 -0
- munchboka_edutools/static/js/pairPuzzle/game.js +160 -0
- munchboka_edutools/static/js/parsons/parsonsPuzzle.js +641 -0
- munchboka_edutools/static/js/popup.js +85 -0
- munchboka_edutools/static/js/quiz.js +422 -0
- munchboka_edutools/static/js/skulpt/skulpt.js +35721 -0
- munchboka_edutools/static/js/timedQuiz/multipleChoiceQuestion.js +184 -0
- munchboka_edutools/static/js/timedQuiz/timedMultipleChoiceQuiz.js +244 -0
- munchboka_edutools/static/js/timedQuiz/utils.js +6 -0
- munchboka_edutools/static/js/utils.js +3 -0
- munchboka_edutools-0.1.13.dist-info/METADATA +108 -0
- munchboka_edutools-0.1.13.dist-info/RECORD +149 -0
- munchboka_edutools-0.1.13.dist-info/WHEEL +4 -0
- munchboka_edutools-0.1.13.dist-info/licenses/LICENSE +21 -0
|
@@ -0,0 +1,348 @@
|
|
|
1
|
+
class InteractiveCodeSetup {
|
|
2
|
+
constructor(containerId, initialCode, preloadPackages = null) {
|
|
3
|
+
this.containerId = containerId;
|
|
4
|
+
this.initialCode = initialCode;
|
|
5
|
+
this.preloadPackages = preloadPackages;
|
|
6
|
+
console.log("InteractiveCodeSetup - Preload packages:", this.preloadPackages);
|
|
7
|
+
this.uniqueId = this.generateUUID();
|
|
8
|
+
console.log("Unique ID:", this.uniqueId);
|
|
9
|
+
|
|
10
|
+
// HTML element IDs
|
|
11
|
+
this.editorId = `code-editor-${this.uniqueId}`;
|
|
12
|
+
this.runButtonId = `run-button-${this.uniqueId}`;
|
|
13
|
+
this.resetButtonId = `reset-button-${this.uniqueId}`;
|
|
14
|
+
this.cancelButtonId = `cancel-button-${this.uniqueId}`;
|
|
15
|
+
this.outputId = `output-${this.uniqueId}`;
|
|
16
|
+
this.errorBoxId = `error-box-${this.uniqueId}`;
|
|
17
|
+
|
|
18
|
+
// Store instances of CodeEditor and PythonRunner
|
|
19
|
+
this.editorInstance = null;
|
|
20
|
+
this.runnerInstance = null;
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
// Initialize the editor setup
|
|
24
|
+
this.createEditorHTML();
|
|
25
|
+
this.setupInteractiveEditor();
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
generateUUID() {
|
|
29
|
+
return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function(c) {
|
|
30
|
+
const r = Math.random() * 16 | 0, v = c === 'x' ? r : (r & 0x3 | 0x8);
|
|
31
|
+
return v.toString(16);
|
|
32
|
+
});
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
createEditorHTML() {
|
|
36
|
+
const container = document.getElementById(this.containerId);
|
|
37
|
+
if (!container) {
|
|
38
|
+
console.error(`Container with ID ${this.containerId} not found.`);
|
|
39
|
+
return;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
const runIcon = `
|
|
43
|
+
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" class="size-6">
|
|
44
|
+
<path stroke-linecap="round" stroke-linejoin="round" d="M5.25 5.653c0-.856.917-1.398 1.667-.986l11.54 6.347a1.125 1.125 0 0 1 0 1.972l-11.54 6.347a1.125 1.125 0 0 1-1.667-.986V5.653Z" />
|
|
45
|
+
</svg>
|
|
46
|
+
`;
|
|
47
|
+
const resetIcon = `
|
|
48
|
+
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="currentColor" class="size-6">
|
|
49
|
+
<path fill-rule="evenodd" d="M9.53 2.47a.75.75 0 0 1 0 1.06L4.81 8.25H15a6.75 6.75 0 0 1 0 13.5h-3a.75.75 0 0 1 0-1.5h3a5.25 5.25 0 1 0 0-10.5H4.81l4.72 4.72a.75.75 0 1 1-1.06 1.06l-6-6a.75.75 0 0 1 0-1.06l6-6a.75.75 0 0 1 1.06 0Z" clip-rule="evenodd" />
|
|
50
|
+
</svg>
|
|
51
|
+
`;
|
|
52
|
+
|
|
53
|
+
const cancelIcon = `
|
|
54
|
+
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" class="size-6">
|
|
55
|
+
<path stroke-linecap="round" stroke-linejoin="round" d="M5.25 7.5A2.25 2.25 0 0 1 7.5 5.25h9a2.25 2.25 0 0 1 2.25 2.25v9a2.25 2.25 0 0 1-2.25 2.25h-9a2.25 2.25 0 0 1-2.25-2.25v-9Z" />
|
|
56
|
+
</svg>
|
|
57
|
+
`;
|
|
58
|
+
|
|
59
|
+
const html = `
|
|
60
|
+
<div>
|
|
61
|
+
<textarea id="${this.editorId}" name="code-${this.uniqueId}">${this.initialCode}</textarea>
|
|
62
|
+
|
|
63
|
+
<button id="${this.runButtonId}" class="button button-run">Kjør kode ${runIcon}</button>
|
|
64
|
+
<button id="${this.resetButtonId}" class="button button-reset">Reset kode ${resetIcon}</button>
|
|
65
|
+
<button id="${this.cancelButtonId}" class="button button-cancel">Avbryt kjøring ${cancelIcon}</button>
|
|
66
|
+
</div>
|
|
67
|
+
<div id="${this.errorBoxId}"></div>
|
|
68
|
+
<pre id="${this.outputId}" class="pythonoutput"></pre>
|
|
69
|
+
`;
|
|
70
|
+
|
|
71
|
+
container.innerHTML = html;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
setupInteractiveEditor() {
|
|
75
|
+
this.editorInstance = new CodeEditor(this.editorId); // Initialize the CodeEditor
|
|
76
|
+
this.runnerInstance = new PythonRunner(this.outputId, this.errorBoxId, this.preloadPackages); // Initialize the PythonRunner
|
|
77
|
+
|
|
78
|
+
// Add event listeners for buttons
|
|
79
|
+
document.getElementById(this.runButtonId).addEventListener("click", () => this.runCode());
|
|
80
|
+
document.getElementById(this.resetButtonId).addEventListener("click", () => this.resetCode());
|
|
81
|
+
document.getElementById(this.cancelButtonId).addEventListener("click", () => this.cancelCodeExecution());
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
|
|
85
|
+
|
|
86
|
+
runCode() {
|
|
87
|
+
this.clearOutput();
|
|
88
|
+
this.runnerInstance.run(this.editorInstance); // Pass the editor instance to PythonRunner for execution
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
resetCode() {
|
|
92
|
+
this.clearOutput();
|
|
93
|
+
this.editorInstance.resetEditor(this.initialCode); // Reset the editor content to the initial code
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
cancelCodeExecution() {
|
|
97
|
+
if (this.runnerInstance.workerManager) {
|
|
98
|
+
this.runnerInstance.workerManager.restartWorker(); // Restart the worker to cancel code execution
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
clearOutput() {
|
|
103
|
+
document.getElementById(this.outputId).textContent = "";
|
|
104
|
+
document.getElementById(this.errorBoxId).textContent = "";
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
|
|
109
|
+
function makeInteractiveCode(containerId, initialCode, preloadPackages = null) {
|
|
110
|
+
return new InteractiveCodeSetup(containerId, initialCode, preloadPackages);
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
|
|
114
|
+
// predictionInteractiveCodeSetup.js
|
|
115
|
+
|
|
116
|
+
class PredictionInteractiveCodeSetup extends InteractiveCodeSetup {
|
|
117
|
+
constructor(containerId, initialCode) {
|
|
118
|
+
super(containerId, initialCode);
|
|
119
|
+
|
|
120
|
+
// Additional IDs for the prediction feature
|
|
121
|
+
this.predictionInputId = `prediction-input-${this.uniqueId}`;
|
|
122
|
+
this.lockPredictionButtonId = `lock-prediction-button-${this.uniqueId}`;
|
|
123
|
+
this.predictionDisplayId = `prediction-display-${this.uniqueId}`;
|
|
124
|
+
this.predictionOutputId = `prediction-output-${this.uniqueId}`;
|
|
125
|
+
this.predictionOutputContainerId = `prediction-output-container-${this.uniqueId}`;
|
|
126
|
+
this.predictionContainerId = `prediction-container-${this.uniqueId}`;
|
|
127
|
+
// this.initialCode = initialCode;
|
|
128
|
+
|
|
129
|
+
// Flag to track whether the prediction has been displayed
|
|
130
|
+
this.predictionDisplayed = false;
|
|
131
|
+
|
|
132
|
+
// Modify the HTML to include prediction elements
|
|
133
|
+
this.addPredictionHTML();
|
|
134
|
+
|
|
135
|
+
// Set up the prediction feature
|
|
136
|
+
this.setupPredictionFeature();
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
addPredictionHTML() {
|
|
140
|
+
const container = document.getElementById(this.containerId);
|
|
141
|
+
if (!container) {
|
|
142
|
+
console.error(`Container with ID ${this.containerId} not found.`);
|
|
143
|
+
return;
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
// Build the prediction input HTML
|
|
147
|
+
const predictionHtml = `
|
|
148
|
+
<div id="${this.predictionContainerId}" class="prediction-container">
|
|
149
|
+
<textarea id="${this.predictionInputId}" rows="3" placeholder="Skriv inn svaret ditt her! \n \nTrykk på Enter (⏎) for en ny linje."></textarea>
|
|
150
|
+
<button id="${this.lockPredictionButtonId}" class="button button-run">Sjekk svaret!</button>
|
|
151
|
+
</div>
|
|
152
|
+
`;
|
|
153
|
+
|
|
154
|
+
// Insert the prediction input after the existing editor HTML
|
|
155
|
+
container.insertAdjacentHTML('beforeend', predictionHtml);
|
|
156
|
+
|
|
157
|
+
// Create the prediction-output container
|
|
158
|
+
const predictionOutputContainer = document.createElement('div');
|
|
159
|
+
predictionOutputContainer.id = this.predictionOutputContainerId;
|
|
160
|
+
predictionOutputContainer.className = 'prediction-output-container';
|
|
161
|
+
predictionOutputContainer.style.display = 'none';
|
|
162
|
+
|
|
163
|
+
// Create the prediction display
|
|
164
|
+
const predictionDisplay = document.createElement('div');
|
|
165
|
+
predictionDisplay.className = 'prediction-display';
|
|
166
|
+
predictionDisplay.innerHTML = `
|
|
167
|
+
<h3>Ditt svar:</h3>
|
|
168
|
+
<pre id="${this.predictionDisplayId}"></pre>
|
|
169
|
+
`;
|
|
170
|
+
|
|
171
|
+
// Create the output display for prediction phase
|
|
172
|
+
const outputDisplay = document.createElement('div');
|
|
173
|
+
outputDisplay.className = 'output-display';
|
|
174
|
+
outputDisplay.innerHTML = `
|
|
175
|
+
<h3>Faktisk utskrift:</h3>
|
|
176
|
+
<pre id="${this.predictionOutputId}" class="pythonoutput"></pre>
|
|
177
|
+
`;
|
|
178
|
+
|
|
179
|
+
// Append the displays to the prediction-output container
|
|
180
|
+
predictionOutputContainer.appendChild(predictionDisplay);
|
|
181
|
+
predictionOutputContainer.appendChild(outputDisplay);
|
|
182
|
+
|
|
183
|
+
// Append the prediction-output container after the error box
|
|
184
|
+
const errorBoxElement = document.getElementById(this.errorBoxId);
|
|
185
|
+
if (errorBoxElement) {
|
|
186
|
+
errorBoxElement.insertAdjacentElement('afterend', predictionOutputContainer);
|
|
187
|
+
} else {
|
|
188
|
+
console.error(`Error box element with ID ${this.errorBoxId} not found.`);
|
|
189
|
+
container.appendChild(predictionOutputContainer);
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
// Save a reference to the original output element
|
|
193
|
+
this.originalOutputElement = document.getElementById(this.outputId);
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
|
|
197
|
+
|
|
198
|
+
setupPredictionFeature() {
|
|
199
|
+
// Make the code editor read-only initially
|
|
200
|
+
// Use setTimeout to ensure the editor is fully initialized
|
|
201
|
+
const setupReadOnly = () => {
|
|
202
|
+
// Check if editor instance exists and has been properly initialized
|
|
203
|
+
if (this.editorInstance && this.editorInstance.editor) {
|
|
204
|
+
console.log("Setting editor to read-only");
|
|
205
|
+
this.editorInstance.editor.setOption('readOnly', true);
|
|
206
|
+
|
|
207
|
+
// Hide the buttons now that we know the editor is ready
|
|
208
|
+
document.getElementById(this.runButtonId).style.display = 'none';
|
|
209
|
+
document.getElementById(this.resetButtonId).style.display = 'none';
|
|
210
|
+
document.getElementById(this.cancelButtonId).style.display = 'none';
|
|
211
|
+
} else {
|
|
212
|
+
console.log("Editor not ready yet, retrying in 100ms...");
|
|
213
|
+
// Retry after a short delay
|
|
214
|
+
setTimeout(setupReadOnly, 100);
|
|
215
|
+
}
|
|
216
|
+
};
|
|
217
|
+
|
|
218
|
+
// Start the setup process
|
|
219
|
+
setupReadOnly();
|
|
220
|
+
|
|
221
|
+
|
|
222
|
+
// this.editorInstance.editor.setOption('readOnly', true);
|
|
223
|
+
|
|
224
|
+
// // Hide the run/reset/cancel buttons until the prediction is made
|
|
225
|
+
// document.getElementById(this.runButtonId).style.display = 'none';
|
|
226
|
+
// document.getElementById(this.resetButtonId).style.display = 'none';
|
|
227
|
+
// document.getElementById(this.cancelButtonId).style.display = 'none';
|
|
228
|
+
|
|
229
|
+
// Add event listener for the lock prediction button
|
|
230
|
+
document.getElementById(this.lockPredictionButtonId).addEventListener("click", () => this.lockPrediction());
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
lockPrediction() {
|
|
234
|
+
const prediction = document.getElementById(this.predictionInputId).value;
|
|
235
|
+
|
|
236
|
+
// Store the prediction
|
|
237
|
+
this.prediction = prediction;
|
|
238
|
+
|
|
239
|
+
// Hide the prediction input area
|
|
240
|
+
const predictionContainer = document.getElementById(this.predictionContainerId);
|
|
241
|
+
if (predictionContainer) {
|
|
242
|
+
predictionContainer.style.display = 'none';
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
// Make the code editor editable
|
|
246
|
+
this.editorInstance.editor.setOption('readOnly', false);
|
|
247
|
+
|
|
248
|
+
// Show the run/reset/cancel buttons
|
|
249
|
+
document.getElementById(this.runButtonId).style.display = 'inline-block';
|
|
250
|
+
document.getElementById(this.resetButtonId).style.display = 'inline-block';
|
|
251
|
+
document.getElementById(this.cancelButtonId).style.display = 'inline-block';
|
|
252
|
+
|
|
253
|
+
// Automatically run the code
|
|
254
|
+
this.runCode();
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
runCode() {
|
|
258
|
+
if (this.predictionDisplayed) {
|
|
259
|
+
// Replace with a new InteractiveCodeSetup instance
|
|
260
|
+
this.initialCode = this.editorInstance.getValue();
|
|
261
|
+
this.replaceWithInteractiveCodeSetup();
|
|
262
|
+
|
|
263
|
+
} else {
|
|
264
|
+
// First run after prediction is locked in
|
|
265
|
+
this.clearOutput();
|
|
266
|
+
this.runnerInstance.run(this.editorInstance, this.predictionOutputId); // Pass the new output ID
|
|
267
|
+
|
|
268
|
+
// Display the prediction and output side by side
|
|
269
|
+
this.displayPredictionAndOutput();
|
|
270
|
+
|
|
271
|
+
// Set flag to indicate prediction has been displayed
|
|
272
|
+
this.predictionDisplayed = true;
|
|
273
|
+
}
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
resetCode() {
|
|
277
|
+
if (this.predictionDisplayed) {
|
|
278
|
+
// Replace with a new InteractiveCodeSetup instance
|
|
279
|
+
this.replaceWithInteractiveCodeSetup();
|
|
280
|
+
} else {
|
|
281
|
+
// First reset (unlikely, but handle just in case)
|
|
282
|
+
this.clearOutput();
|
|
283
|
+
this.editorInstance.resetEditor(this.initialCode);
|
|
284
|
+
}
|
|
285
|
+
}
|
|
286
|
+
|
|
287
|
+
cancelCodeExecution() {
|
|
288
|
+
if (this.predictionDisplayed) {
|
|
289
|
+
// Replace with a new InteractiveCodeSetup instance
|
|
290
|
+
this.replaceWithInteractiveCodeSetup();
|
|
291
|
+
} else {
|
|
292
|
+
// First cancel after prediction is locked in
|
|
293
|
+
if (this.runnerInstance.workerManager) {
|
|
294
|
+
this.runnerInstance.workerManager.restartWorker();
|
|
295
|
+
}
|
|
296
|
+
}
|
|
297
|
+
}
|
|
298
|
+
|
|
299
|
+
replaceWithInteractiveCodeSetup() {
|
|
300
|
+
// Get the container element
|
|
301
|
+
const container = document.getElementById(this.containerId);
|
|
302
|
+
if (container) {
|
|
303
|
+
// Clear the container's content
|
|
304
|
+
container.innerHTML = '';
|
|
305
|
+
|
|
306
|
+
// Create a new instance of InteractiveCodeSetup
|
|
307
|
+
new InteractiveCodeSetup(this.containerId, this.initialCode);
|
|
308
|
+
} else {
|
|
309
|
+
console.error(`Container with ID ${this.containerId} not found.`);
|
|
310
|
+
}
|
|
311
|
+
}
|
|
312
|
+
|
|
313
|
+
displayPredictionAndOutput() {
|
|
314
|
+
// Display the user's prediction
|
|
315
|
+
document.getElementById(this.predictionDisplayId).textContent = this.prediction;
|
|
316
|
+
|
|
317
|
+
// Hide the original output element
|
|
318
|
+
if (this.originalOutputElement) {
|
|
319
|
+
this.originalOutputElement.style.display = 'none';
|
|
320
|
+
}
|
|
321
|
+
|
|
322
|
+
// Show the prediction-output container
|
|
323
|
+
document.getElementById(this.predictionOutputContainerId).style.display = 'flex';
|
|
324
|
+
}
|
|
325
|
+
|
|
326
|
+
clearOutput() {
|
|
327
|
+
if (this.predictionDisplayed) {
|
|
328
|
+
const outputElement = document.getElementById(this.predictionOutputId);
|
|
329
|
+
if (outputElement) {
|
|
330
|
+
outputElement.textContent = "";
|
|
331
|
+
}
|
|
332
|
+
} else {
|
|
333
|
+
const outputElement = document.getElementById(this.outputId);
|
|
334
|
+
if (outputElement) {
|
|
335
|
+
outputElement.textContent = "";
|
|
336
|
+
}
|
|
337
|
+
}
|
|
338
|
+
const errorBoxElement = document.getElementById(this.errorBoxId);
|
|
339
|
+
if (errorBoxElement) {
|
|
340
|
+
errorBoxElement.textContent = "";
|
|
341
|
+
}
|
|
342
|
+
}
|
|
343
|
+
}
|
|
344
|
+
|
|
345
|
+
// Function to initialize the prediction code editor
|
|
346
|
+
function makePredictionInteractiveCode(containerId, initialCode) {
|
|
347
|
+
return new PredictionInteractiveCodeSetup(containerId, initialCode);
|
|
348
|
+
}
|
|
@@ -0,0 +1,336 @@
|
|
|
1
|
+
// pythonRunner.js
|
|
2
|
+
|
|
3
|
+
class PythonRunner {
|
|
4
|
+
constructor(outputId, errorBoxId, preloadPackages = ['casify']) {
|
|
5
|
+
this.outputId = outputId; // ID of the HTML element where output will be displayed
|
|
6
|
+
this.errorBoxId = errorBoxId; // ID of the HTML element for displaying errors
|
|
7
|
+
this.workerManager = WorkerManager.getInstance(preloadPackages);
|
|
8
|
+
this.preloadPackages = preloadPackages;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* Prepares and runs the code provided in the editor.
|
|
13
|
+
* @param {Object} editor - The CodeMirror editor instance containing the code.
|
|
14
|
+
*/
|
|
15
|
+
async run(editor, outputId = null) {
|
|
16
|
+
// Wait until worker is ready and preload packages are loaded
|
|
17
|
+
try {
|
|
18
|
+
await this.workerManager.workerReadyPromise;
|
|
19
|
+
} catch (error) {
|
|
20
|
+
console.error("Worker failed to initialize:", error);
|
|
21
|
+
this.handleErrorMessage("Failed to initialize Python environment.");
|
|
22
|
+
return;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
this.editorInstance = editor;
|
|
26
|
+
this.editorInstance.clearLineHighlights();
|
|
27
|
+
let code = editor.getValue();
|
|
28
|
+
this.currentCode = code;
|
|
29
|
+
|
|
30
|
+
if (outputId) {
|
|
31
|
+
this.outputId = outputId;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
// Handle input statements and modify the code accordingly
|
|
35
|
+
const inputStatements = this.findInputStatements(this.currentCode);
|
|
36
|
+
if (inputStatements.length > 0) {
|
|
37
|
+
const userValues = await this.getUserInputs(inputStatements);
|
|
38
|
+
this.currentCode = this.replaceInputStatements(this.currentCode, userValues);
|
|
39
|
+
console.log("Modified code:", this.currentCode);
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
// Extract and load necessary packages
|
|
43
|
+
const packages = this.extractPackageNames(this.currentCode);
|
|
44
|
+
|
|
45
|
+
if (!packages.includes('matplotlib')) {
|
|
46
|
+
packages.push('matplotlib');
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
console.log("Packages to load:", packages);
|
|
50
|
+
if (packages.length > 0) {
|
|
51
|
+
try {
|
|
52
|
+
await this.workerManager.loadPackages(packages);
|
|
53
|
+
} catch (error) {
|
|
54
|
+
// Handle package load error
|
|
55
|
+
console.error("Failed to load packages:", error);
|
|
56
|
+
this.handleErrorMessage(error.message);
|
|
57
|
+
return;
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
|
|
62
|
+
const callback = (data) => {
|
|
63
|
+
if (data.type === 'stdout') {
|
|
64
|
+
this.handleWorkerMessage(data);
|
|
65
|
+
} else if (data.type === 'stderr') {
|
|
66
|
+
this.handleErrorMessage(data.msg); // Displays the error
|
|
67
|
+
} else if (data.type === 'plot') {
|
|
68
|
+
const outputElement = document.getElementById(this.outputId);
|
|
69
|
+
if (!outputElement) {
|
|
70
|
+
console.error("Output element not found:", this.outputId);
|
|
71
|
+
return;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
const img = document.createElement('img');
|
|
75
|
+
img.src = 'data:image/png;base64,' + data.data;
|
|
76
|
+
img.style.width = '100%'; // Or any other appropriate styling
|
|
77
|
+
img.style.height = 'auto'; // Or any other appropriate styling
|
|
78
|
+
img.style.maxHeight = '500px'; // Example: set a max width
|
|
79
|
+
|
|
80
|
+
outputElement.appendChild(img);
|
|
81
|
+
this.scrollToBottom(outputElement); // Scroll to show new plot
|
|
82
|
+
} else if (data.type === 'executionComplete') {
|
|
83
|
+
console.log("Code execution complete for messageId:", data.messageId);
|
|
84
|
+
}
|
|
85
|
+
};
|
|
86
|
+
|
|
87
|
+
|
|
88
|
+
this.workerManager.runCode(this.currentCode, callback);
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
|
|
92
|
+
/**
|
|
93
|
+
* Handles incoming messages from the WorkerManager.
|
|
94
|
+
* @param {Object} data - The parsed message data from the worker.
|
|
95
|
+
*/
|
|
96
|
+
handleWorkerMessage(data) {
|
|
97
|
+
const { type, msg } = data;
|
|
98
|
+
console.log("Message from worker:", data);
|
|
99
|
+
const outputElement = document.getElementById(this.outputId);
|
|
100
|
+
|
|
101
|
+
if (!outputElement) {
|
|
102
|
+
console.error("Output element not found:", this.outputId);
|
|
103
|
+
return;
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
if (type === 'stdout') {
|
|
107
|
+
// Replace "&" with "∧", "oo" with "∞", and "|" with "∨"
|
|
108
|
+
let formattedMsg = msg
|
|
109
|
+
.replace(/And\(([^)]+)\)/g, (match, p1) => {
|
|
110
|
+
// Split conditions by comma, trim spaces, and wrap each in parentheses
|
|
111
|
+
const conditions = p1.split(',').map(cond => cond.trim());
|
|
112
|
+
return conditions.map(cond => `(${cond})`).join(' ∧ ');
|
|
113
|
+
})
|
|
114
|
+
// .replace(/&/g, '∧')
|
|
115
|
+
.replace(/oo/g, '∞')
|
|
116
|
+
.replace(/\|/g, '∨');
|
|
117
|
+
outputElement.innerHTML += this.formatErrorMessage(formattedMsg);
|
|
118
|
+
this.highlightLine(this.editorInstance, data.msg);
|
|
119
|
+
this.scrollToBottom(outputElement);
|
|
120
|
+
|
|
121
|
+
} else if (type === 'stderr') {
|
|
122
|
+
console.log("Error message:", msg);
|
|
123
|
+
this.handleErrorMessage(msg);
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
scrollToBottom(element) {
|
|
128
|
+
element.scrollTop = element.scrollHeight;
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
/**
|
|
132
|
+
* Handles error messages from the worker.
|
|
133
|
+
* @param {string} msg - The error message.
|
|
134
|
+
*/
|
|
135
|
+
handleErrorMessage(msg) {
|
|
136
|
+
const errorElement = document.getElementById(this.errorBoxId);
|
|
137
|
+
if (errorElement) {
|
|
138
|
+
errorElement.innerHTML = this.formatErrorMessage(msg);
|
|
139
|
+
}
|
|
140
|
+
this.highlightLine(this.editorInstance, msg);
|
|
141
|
+
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
/**
|
|
145
|
+
* Formats output messages for display.
|
|
146
|
+
* @param {string} msg - The message to be formatted.
|
|
147
|
+
* @returns {string} - The formatted message.
|
|
148
|
+
*/
|
|
149
|
+
formatOutput(msg) {
|
|
150
|
+
return msg;
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
|
|
154
|
+
highlightLine(editor, msg) {
|
|
155
|
+
const linePattern = /File "<exec>", line (\d+)/;
|
|
156
|
+
const match = linePattern.exec(msg);
|
|
157
|
+
if (match) {
|
|
158
|
+
const lineNumber = parseInt(match[1]) - 1;
|
|
159
|
+
console.log("Highlighting line:", lineNumber);
|
|
160
|
+
editor.highlightLine(lineNumber);
|
|
161
|
+
console.log("Highlighting error at line:", lineNumber);
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
formatErrorMessage(errorMsg) {
|
|
166
|
+
let formattedMessage = errorMsg;
|
|
167
|
+
let content = '';
|
|
168
|
+
let title = '';
|
|
169
|
+
let knownError = false;
|
|
170
|
+
|
|
171
|
+
|
|
172
|
+
// Highlight the line number in the pattern 'File "<exec>", line <number>'
|
|
173
|
+
const fileLinePattern = /File "<exec>", line (\d+)/g;
|
|
174
|
+
formattedMessage = formattedMessage.replace(fileLinePattern, (match, p1) => {
|
|
175
|
+
return match.replace(`line ${p1}`, `<span class="error-line">line ${p1}</span>`);
|
|
176
|
+
});
|
|
177
|
+
|
|
178
|
+
|
|
179
|
+
// Highlight the error type
|
|
180
|
+
const errorTypeMatch = errorMsg.match(/(\w+Error):/);
|
|
181
|
+
if (errorTypeMatch) {
|
|
182
|
+
console.log("Error type match:", errorTypeMatch[1]);
|
|
183
|
+
formattedMessage = formattedMessage.replace(errorTypeMatch[1], `<span class="error-type">${errorTypeMatch[1]}</span>`);
|
|
184
|
+
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
|
|
188
|
+
return formattedMessage;
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
|
|
192
|
+
|
|
193
|
+
/**
|
|
194
|
+
* Extracts package names from the code based on import statements.
|
|
195
|
+
* @param {string} code - The Python code to be analyzed.
|
|
196
|
+
* @returns {Array<string>} - An array of package names.
|
|
197
|
+
*/
|
|
198
|
+
extractPackageNames(code) {
|
|
199
|
+
// Matches "import <package> as <alias>" and "import <package>"
|
|
200
|
+
const importRegex = /^\s*import\s+([^;\s]+)\s*/gm;
|
|
201
|
+
|
|
202
|
+
// Matches "from <package> import <something>"
|
|
203
|
+
const fromImportRegex = /^\s*from\s+([^;\s]+)\s+import/gm;
|
|
204
|
+
|
|
205
|
+
const packages = new Set();
|
|
206
|
+
const standardLibs = new Set([
|
|
207
|
+
'abc', 'aifc', 'argparse', 'array', 'ast', 'asynchat', 'asyncio', 'asyncore', 'atexit', 'audioop', 'base64',
|
|
208
|
+
'bdb', 'binascii', 'binhex', 'bisect', 'builtins', 'bz2', 'cProfile', 'calendar', 'cgi', 'cgitb', 'chunk',
|
|
209
|
+
'cmath', 'cmd', 'code', 'codecs', 'codeop', 'collections', 'colorsys', 'compileall', 'concurrent', 'configparser',
|
|
210
|
+
'contextlib', 'copy', 'copyreg', 'crypt', 'csv', 'ctypes', 'curses', 'dataclasses', 'datetime', 'dbm', 'decimal',
|
|
211
|
+
'difflib', 'dis', 'distutils', 'doctest', 'email', 'encodings', 'ensurepip', 'enum', 'errno', 'faulthandler',
|
|
212
|
+
'fcntl', 'filecmp', 'fileinput', 'fnmatch', 'formatter', 'fractions', 'ftplib', 'functools', 'gc', 'getopt',
|
|
213
|
+
'getpass', 'gettext', 'glob', 'grp', 'gzip', 'hashlib', 'heapq', 'hmac', 'html', 'http', 'imaplib', 'imghdr',
|
|
214
|
+
'imp', 'importlib', 'inspect', 'io', 'ipaddress', 'itertools', 'json', 'keyword', 'lib2to3', 'linecache', 'locale',
|
|
215
|
+
'logging', 'lzma', 'mailbox', 'mailcap', 'marshal', 'math', 'mimetypes', 'mmap', 'modulefinder', 'msilib', 'msvcrt',
|
|
216
|
+
'multiprocessing', 'netrc', 'nntplib', 'numbers', 'operator', 'optparse', 'os', 'ossaudiodev', 'parser', 'pathlib',
|
|
217
|
+
'pdb', 'pickle', 'pickletools', 'pipes', 'pkgutil', 'platform', 'plistlib', 'poplib', 'posix', 'pprint', 'profile',
|
|
218
|
+
'pstats', 'pty', 'pwd', 'py_compile', 'pyclbr', 'pydoc', 'queue', 'quopri', 'random', 're', 'readline', 'reprlib',
|
|
219
|
+
'resource', 'rlcompleter', 'runpy', 'sched', 'secrets', 'select', 'selectors', 'shelve', 'shlex', 'shutil', 'signal',
|
|
220
|
+
'site', 'smtpd', 'smtplib', 'sndhdr', 'socket', 'socketserver', 'spwd', 'sqlite3', 'ssl', 'stat', 'statistics',
|
|
221
|
+
'string', 'stringprep', 'struct', 'subprocess', 'sunau', 'symbol', 'symtable', 'sys', 'sysconfig', 'tabnanny',
|
|
222
|
+
'tarfile', 'telnetlib', 'tempfile', 'termios', 'test', 'textwrap', 'threading', 'time', 'timeit', 'tkinter', 'token',
|
|
223
|
+
'tokenize', 'trace', 'traceback', 'tracemalloc', 'tty', 'turtle', 'turtledemo', 'types', 'typing', 'unicodedata',
|
|
224
|
+
'unittest', 'urllib', 'uu', 'uuid', 'venv', 'warnings', 'wave', 'weakref', 'webbrowser', 'winreg', 'winsound',
|
|
225
|
+
'wsgiref', 'xdrlib', 'xml', 'xmlrpc', 'zipapp', 'zipfile', 'zipimport', 'zlib'
|
|
226
|
+
]);
|
|
227
|
+
|
|
228
|
+
let match;
|
|
229
|
+
|
|
230
|
+
// Process "import" statements
|
|
231
|
+
while ((match = importRegex.exec(code)) !== null) {
|
|
232
|
+
const packageName = match[1].split('.')[0];
|
|
233
|
+
if (!standardLibs.has(packageName)) {
|
|
234
|
+
packages.add(packageName);
|
|
235
|
+
}
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
// Process "from ... import" statements
|
|
239
|
+
while ((match = fromImportRegex.exec(code)) !== null) {
|
|
240
|
+
const packageName = match[1].split('.')[0];
|
|
241
|
+
if (!standardLibs.has(packageName)) {
|
|
242
|
+
packages.add(packageName);
|
|
243
|
+
}
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
console.log("Packages to load:", Array.from(packages));
|
|
247
|
+
|
|
248
|
+
return Array.from(packages);
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
/**
|
|
252
|
+
* Finds input statements in the code.
|
|
253
|
+
* @param {string} code - The Python code to be analyzed.
|
|
254
|
+
* @returns {Array<Object>} - An array of input statements found.
|
|
255
|
+
*/
|
|
256
|
+
findInputStatements(code) {
|
|
257
|
+
const inputRegex = /(\w+)\s*=\s*(int|float|eval)?\(?input\(["'](.*?)["']\)\)?/g;
|
|
258
|
+
let match;
|
|
259
|
+
let inputs = [];
|
|
260
|
+
|
|
261
|
+
while ((match = inputRegex.exec(code)) !== null) {
|
|
262
|
+
inputs.push({
|
|
263
|
+
variable: match[1],
|
|
264
|
+
promptText: match[3]
|
|
265
|
+
});
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
return inputs;
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
/**
|
|
272
|
+
* Prompts the user for input when input statements are found in the code.
|
|
273
|
+
* @param {Array<Object>} inputs - An array of input statements.
|
|
274
|
+
* @returns {Object} - A dictionary of user inputs mapped to variable names.
|
|
275
|
+
*/
|
|
276
|
+
async getUserInputs(inputs) {
|
|
277
|
+
let userValues = {};
|
|
278
|
+
|
|
279
|
+
for (let input of inputs) {
|
|
280
|
+
let promptText = input.promptText.replace(/['"]+/g, '');
|
|
281
|
+
let userValue = await this.promptUser(promptText);
|
|
282
|
+
userValues[input.variable] = userValue;
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
return userValues;
|
|
286
|
+
}
|
|
287
|
+
|
|
288
|
+
/**
|
|
289
|
+
* Prompts the user for input.
|
|
290
|
+
* @param {string} promptText - The text to display in the prompt.
|
|
291
|
+
* @returns {Promise<string>} - A promise that resolves with the user input.
|
|
292
|
+
*/
|
|
293
|
+
promptUser(promptText) {
|
|
294
|
+
return new Promise((resolve) => {
|
|
295
|
+
let userInput = prompt(promptText);
|
|
296
|
+
resolve(userInput);
|
|
297
|
+
});
|
|
298
|
+
}
|
|
299
|
+
|
|
300
|
+
/**
|
|
301
|
+
* Replaces input statements in the code with user-provided values.
|
|
302
|
+
* @param {string} code - The Python code.
|
|
303
|
+
* @param {Object} userValues - A dictionary of user-provided values.
|
|
304
|
+
* @returns {string} - The modified code with input statements replaced.
|
|
305
|
+
*/
|
|
306
|
+
|
|
307
|
+
replaceInputStatements(code, userValues) {
|
|
308
|
+
let codeLines = code.split('\n');
|
|
309
|
+
|
|
310
|
+
codeLines = codeLines.map(line => {
|
|
311
|
+
for (let variable in userValues) {
|
|
312
|
+
console.log("Variable: ", variable);
|
|
313
|
+
// Adjust the regex to handle Unicode characters in variable names
|
|
314
|
+
const inputRegex = new RegExp(`\\b${variable}\\b\\s*=\\s*(float|int|eval)?\\(?input\\(.*?\\)\\)?`, 'gu');
|
|
315
|
+
|
|
316
|
+
if (inputRegex.test(line)) {
|
|
317
|
+
let userValue = userValues[variable];
|
|
318
|
+
|
|
319
|
+
// Detect the type of the user input
|
|
320
|
+
if (!isNaN(userValue)) {
|
|
321
|
+
// Check if the input is a number (int or float)
|
|
322
|
+
//userValue = Number(userValue); // Convert the string to a number
|
|
323
|
+
} else if (typeof userValue === 'string') {
|
|
324
|
+
// Check if the input is a string and doesn't contain only numbers
|
|
325
|
+
userValue = `"${userValue}"`; // Add quotes around string inputs
|
|
326
|
+
}
|
|
327
|
+
|
|
328
|
+
line = line.replace(inputRegex, `${variable} = ${userValue}`);
|
|
329
|
+
}
|
|
330
|
+
}
|
|
331
|
+
return line;
|
|
332
|
+
});
|
|
333
|
+
|
|
334
|
+
return codeLines.join('\n');
|
|
335
|
+
}
|
|
336
|
+
}
|