munchboka-edutools 0.2.3__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 +428 -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/escape_room2.py +318 -0
- munchboka_edutools/directives/factor_tree.py +552 -0
- munchboka_edutools/directives/flashcards.py +233 -0
- munchboka_edutools/directives/ggb.py +209 -0
- munchboka_edutools/directives/ggb_icon.py +105 -0
- munchboka_edutools/directives/ggb_popup.py +308 -0
- munchboka_edutools/directives/horner.py +326 -0
- munchboka_edutools/directives/interactive_code.py +75 -0
- munchboka_edutools/directives/jeopardy.py +252 -0
- munchboka_edutools/directives/jeopardy2.py +636 -0
- munchboka_edutools/directives/multi_plot.py +2524 -0
- munchboka_edutools/directives/multi_plot2.py +252 -0
- munchboka_edutools/directives/pair_puzzle.py +191 -0
- munchboka_edutools/directives/parsons.py +109 -0
- munchboka_edutools/directives/plot.py +3758 -0
- munchboka_edutools/directives/poly_icon.py +111 -0
- munchboka_edutools/directives/polydiv.py +346 -0
- munchboka_edutools/directives/popup.py +245 -0
- munchboka_edutools/directives/quiz.py +291 -0
- munchboka_edutools/directives/quiz2.py +453 -0
- munchboka_edutools/directives/signchart.py +519 -0
- munchboka_edutools/directives/signchart2.py +1545 -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 +321 -0
- munchboka_edutools/static/css/flashcards.css +219 -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 +147 -0
- munchboka_edutools/static/css/github-light.css +155 -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 +553 -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 +377 -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/flashcards.js +199 -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 +648 -0
- munchboka_edutools/static/js/interactiveCode/interactiveCodeSetup.js +441 -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 +560 -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 +566 -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.2.3.dist-info/METADATA +109 -0
- munchboka_edutools-0.2.3.dist-info/RECORD +157 -0
- munchboka_edutools-0.2.3.dist-info/WHEEL +4 -0
- munchboka_edutools-0.2.3.dist-info/licenses/LICENSE +21 -0
|
@@ -0,0 +1,441 @@
|
|
|
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
|
+
// Set up localStorage persistence
|
|
84
|
+
this.setupLocalStoragePersistence();
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
setupLocalStoragePersistence() {
|
|
88
|
+
const storageKey = `interactive-code-${this.containerId}`;
|
|
89
|
+
|
|
90
|
+
// Restore saved code if available
|
|
91
|
+
const restoreState = () => {
|
|
92
|
+
if (this.editorInstance && this.editorInstance.editor) {
|
|
93
|
+
try {
|
|
94
|
+
const savedCode = localStorage.getItem(storageKey);
|
|
95
|
+
if (savedCode && savedCode !== this.initialCode) {
|
|
96
|
+
this.editorInstance.editor.setValue(savedCode);
|
|
97
|
+
}
|
|
98
|
+
// Update timestamp
|
|
99
|
+
localStorage.setItem(storageKey + '-timestamp', Date.now().toString());
|
|
100
|
+
} catch (e) {
|
|
101
|
+
// Silently fail if restore fails
|
|
102
|
+
}
|
|
103
|
+
} else {
|
|
104
|
+
// Retry if editor not ready
|
|
105
|
+
setTimeout(restoreState, 100);
|
|
106
|
+
}
|
|
107
|
+
};
|
|
108
|
+
|
|
109
|
+
// Start restoration
|
|
110
|
+
setTimeout(restoreState, 100);
|
|
111
|
+
|
|
112
|
+
// Save code when page unloads
|
|
113
|
+
window.addEventListener('beforeunload', () => {
|
|
114
|
+
this.saveState(storageKey);
|
|
115
|
+
});
|
|
116
|
+
|
|
117
|
+
// Also save when editor content changes (debounced)
|
|
118
|
+
let saveTimeout = null;
|
|
119
|
+
if (this.editorInstance && this.editorInstance.editor) {
|
|
120
|
+
this.editorInstance.editor.on('change', () => {
|
|
121
|
+
clearTimeout(saveTimeout);
|
|
122
|
+
saveTimeout = setTimeout(() => {
|
|
123
|
+
this.saveState(storageKey);
|
|
124
|
+
}, 1000); // Save 1 second after user stops typing
|
|
125
|
+
});
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
saveState(storageKey) {
|
|
130
|
+
if (!this.editorInstance || !this.editorInstance.editor) return;
|
|
131
|
+
try {
|
|
132
|
+
const code = this.editorInstance.getValue();
|
|
133
|
+
localStorage.setItem(storageKey, code);
|
|
134
|
+
localStorage.setItem(storageKey + '-timestamp', Date.now().toString());
|
|
135
|
+
} catch (e) {
|
|
136
|
+
// If quota exceeded, try cleanup and retry
|
|
137
|
+
if (e.name === 'QuotaExceededError') {
|
|
138
|
+
this.cleanupOldStates();
|
|
139
|
+
try {
|
|
140
|
+
const code = this.editorInstance.getValue();
|
|
141
|
+
localStorage.setItem(storageKey, code);
|
|
142
|
+
localStorage.setItem(storageKey + '-timestamp', Date.now().toString());
|
|
143
|
+
} catch (retryError) {
|
|
144
|
+
// Still failed - silently give up
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
cleanupOldStates() {
|
|
151
|
+
try {
|
|
152
|
+
// Find all interactive code states with timestamps
|
|
153
|
+
const codeStates = [];
|
|
154
|
+
for (let i = 0; i < localStorage.length; i++) {
|
|
155
|
+
const key = localStorage.key(i);
|
|
156
|
+
if (key && key.startsWith('interactive-code-') && key.endsWith('-timestamp')) {
|
|
157
|
+
const stateKey = key.replace('-timestamp', '');
|
|
158
|
+
const timestamp = parseInt(localStorage.getItem(key) || '0', 10);
|
|
159
|
+
codeStates.push({ key: stateKey, timestamp: timestamp });
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
// Sort by timestamp (oldest first)
|
|
164
|
+
codeStates.sort((a, b) => a.timestamp - b.timestamp);
|
|
165
|
+
|
|
166
|
+
// Delete oldest 25% of states (minimum 1, maximum 10)
|
|
167
|
+
const numToDelete = Math.max(1, Math.min(10, Math.floor(codeStates.length * 0.25)));
|
|
168
|
+
for (let i = 0; i < numToDelete && i < codeStates.length; i++) {
|
|
169
|
+
localStorage.removeItem(codeStates[i].key);
|
|
170
|
+
localStorage.removeItem(codeStates[i].key + '-timestamp');
|
|
171
|
+
}
|
|
172
|
+
} catch (e) {
|
|
173
|
+
// Cleanup failed - silently continue
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
|
|
178
|
+
|
|
179
|
+
runCode() {
|
|
180
|
+
this.clearOutput();
|
|
181
|
+
this.runnerInstance.run(this.editorInstance); // Pass the editor instance to PythonRunner for execution
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
resetCode() {
|
|
185
|
+
this.clearOutput();
|
|
186
|
+
this.editorInstance.resetEditor(this.initialCode); // Reset the editor content to the initial code
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
cancelCodeExecution() {
|
|
190
|
+
if (this.runnerInstance.workerManager) {
|
|
191
|
+
this.runnerInstance.workerManager.restartWorker(); // Restart the worker to cancel code execution
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
clearOutput() {
|
|
196
|
+
document.getElementById(this.outputId).textContent = "";
|
|
197
|
+
document.getElementById(this.errorBoxId).textContent = "";
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
|
|
202
|
+
function makeInteractiveCode(containerId, initialCode, preloadPackages = null) {
|
|
203
|
+
return new InteractiveCodeSetup(containerId, initialCode, preloadPackages);
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
|
|
207
|
+
// predictionInteractiveCodeSetup.js
|
|
208
|
+
|
|
209
|
+
class PredictionInteractiveCodeSetup extends InteractiveCodeSetup {
|
|
210
|
+
constructor(containerId, initialCode) {
|
|
211
|
+
super(containerId, initialCode);
|
|
212
|
+
|
|
213
|
+
// Additional IDs for the prediction feature
|
|
214
|
+
this.predictionInputId = `prediction-input-${this.uniqueId}`;
|
|
215
|
+
this.lockPredictionButtonId = `lock-prediction-button-${this.uniqueId}`;
|
|
216
|
+
this.predictionDisplayId = `prediction-display-${this.uniqueId}`;
|
|
217
|
+
this.predictionOutputId = `prediction-output-${this.uniqueId}`;
|
|
218
|
+
this.predictionOutputContainerId = `prediction-output-container-${this.uniqueId}`;
|
|
219
|
+
this.predictionContainerId = `prediction-container-${this.uniqueId}`;
|
|
220
|
+
// this.initialCode = initialCode;
|
|
221
|
+
|
|
222
|
+
// Flag to track whether the prediction has been displayed
|
|
223
|
+
this.predictionDisplayed = false;
|
|
224
|
+
|
|
225
|
+
// Modify the HTML to include prediction elements
|
|
226
|
+
this.addPredictionHTML();
|
|
227
|
+
|
|
228
|
+
// Set up the prediction feature
|
|
229
|
+
this.setupPredictionFeature();
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
addPredictionHTML() {
|
|
233
|
+
const container = document.getElementById(this.containerId);
|
|
234
|
+
if (!container) {
|
|
235
|
+
console.error(`Container with ID ${this.containerId} not found.`);
|
|
236
|
+
return;
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
// Build the prediction input HTML
|
|
240
|
+
const predictionHtml = `
|
|
241
|
+
<div id="${this.predictionContainerId}" class="prediction-container">
|
|
242
|
+
<textarea id="${this.predictionInputId}" rows="3" placeholder="Skriv inn svaret ditt her! \n \nTrykk på Enter (⏎) for en ny linje."></textarea>
|
|
243
|
+
<button id="${this.lockPredictionButtonId}" class="button button-run">Sjekk svaret!</button>
|
|
244
|
+
</div>
|
|
245
|
+
`;
|
|
246
|
+
|
|
247
|
+
// Insert the prediction input after the existing editor HTML
|
|
248
|
+
container.insertAdjacentHTML('beforeend', predictionHtml);
|
|
249
|
+
|
|
250
|
+
// Create the prediction-output container
|
|
251
|
+
const predictionOutputContainer = document.createElement('div');
|
|
252
|
+
predictionOutputContainer.id = this.predictionOutputContainerId;
|
|
253
|
+
predictionOutputContainer.className = 'prediction-output-container';
|
|
254
|
+
predictionOutputContainer.style.display = 'none';
|
|
255
|
+
|
|
256
|
+
// Create the prediction display
|
|
257
|
+
const predictionDisplay = document.createElement('div');
|
|
258
|
+
predictionDisplay.className = 'prediction-display';
|
|
259
|
+
predictionDisplay.innerHTML = `
|
|
260
|
+
<h3>Ditt svar:</h3>
|
|
261
|
+
<pre id="${this.predictionDisplayId}"></pre>
|
|
262
|
+
`;
|
|
263
|
+
|
|
264
|
+
// Create the output display for prediction phase
|
|
265
|
+
const outputDisplay = document.createElement('div');
|
|
266
|
+
outputDisplay.className = 'output-display';
|
|
267
|
+
outputDisplay.innerHTML = `
|
|
268
|
+
<h3>Faktisk utskrift:</h3>
|
|
269
|
+
<pre id="${this.predictionOutputId}" class="pythonoutput"></pre>
|
|
270
|
+
`;
|
|
271
|
+
|
|
272
|
+
// Append the displays to the prediction-output container
|
|
273
|
+
predictionOutputContainer.appendChild(predictionDisplay);
|
|
274
|
+
predictionOutputContainer.appendChild(outputDisplay);
|
|
275
|
+
|
|
276
|
+
// Append the prediction-output container after the error box
|
|
277
|
+
const errorBoxElement = document.getElementById(this.errorBoxId);
|
|
278
|
+
if (errorBoxElement) {
|
|
279
|
+
errorBoxElement.insertAdjacentElement('afterend', predictionOutputContainer);
|
|
280
|
+
} else {
|
|
281
|
+
console.error(`Error box element with ID ${this.errorBoxId} not found.`);
|
|
282
|
+
container.appendChild(predictionOutputContainer);
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
// Save a reference to the original output element
|
|
286
|
+
this.originalOutputElement = document.getElementById(this.outputId);
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
|
|
290
|
+
|
|
291
|
+
setupPredictionFeature() {
|
|
292
|
+
// Make the code editor read-only initially
|
|
293
|
+
// Use setTimeout to ensure the editor is fully initialized
|
|
294
|
+
const setupReadOnly = () => {
|
|
295
|
+
// Check if editor instance exists and has been properly initialized
|
|
296
|
+
if (this.editorInstance && this.editorInstance.editor) {
|
|
297
|
+
console.log("Setting editor to read-only");
|
|
298
|
+
this.editorInstance.editor.setOption('readOnly', true);
|
|
299
|
+
|
|
300
|
+
// Hide the buttons now that we know the editor is ready
|
|
301
|
+
document.getElementById(this.runButtonId).style.display = 'none';
|
|
302
|
+
document.getElementById(this.resetButtonId).style.display = 'none';
|
|
303
|
+
document.getElementById(this.cancelButtonId).style.display = 'none';
|
|
304
|
+
} else {
|
|
305
|
+
console.log("Editor not ready yet, retrying in 100ms...");
|
|
306
|
+
// Retry after a short delay
|
|
307
|
+
setTimeout(setupReadOnly, 100);
|
|
308
|
+
}
|
|
309
|
+
};
|
|
310
|
+
|
|
311
|
+
// Start the setup process
|
|
312
|
+
setupReadOnly();
|
|
313
|
+
|
|
314
|
+
|
|
315
|
+
// this.editorInstance.editor.setOption('readOnly', true);
|
|
316
|
+
|
|
317
|
+
// // Hide the run/reset/cancel buttons until the prediction is made
|
|
318
|
+
// document.getElementById(this.runButtonId).style.display = 'none';
|
|
319
|
+
// document.getElementById(this.resetButtonId).style.display = 'none';
|
|
320
|
+
// document.getElementById(this.cancelButtonId).style.display = 'none';
|
|
321
|
+
|
|
322
|
+
// Add event listener for the lock prediction button
|
|
323
|
+
document.getElementById(this.lockPredictionButtonId).addEventListener("click", () => this.lockPrediction());
|
|
324
|
+
}
|
|
325
|
+
|
|
326
|
+
lockPrediction() {
|
|
327
|
+
const prediction = document.getElementById(this.predictionInputId).value;
|
|
328
|
+
|
|
329
|
+
// Store the prediction
|
|
330
|
+
this.prediction = prediction;
|
|
331
|
+
|
|
332
|
+
// Hide the prediction input area
|
|
333
|
+
const predictionContainer = document.getElementById(this.predictionContainerId);
|
|
334
|
+
if (predictionContainer) {
|
|
335
|
+
predictionContainer.style.display = 'none';
|
|
336
|
+
}
|
|
337
|
+
|
|
338
|
+
// Make the code editor editable
|
|
339
|
+
this.editorInstance.editor.setOption('readOnly', false);
|
|
340
|
+
|
|
341
|
+
// Show the run/reset/cancel buttons
|
|
342
|
+
document.getElementById(this.runButtonId).style.display = 'inline-block';
|
|
343
|
+
document.getElementById(this.resetButtonId).style.display = 'inline-block';
|
|
344
|
+
document.getElementById(this.cancelButtonId).style.display = 'inline-block';
|
|
345
|
+
|
|
346
|
+
// Automatically run the code
|
|
347
|
+
this.runCode();
|
|
348
|
+
}
|
|
349
|
+
|
|
350
|
+
runCode() {
|
|
351
|
+
if (this.predictionDisplayed) {
|
|
352
|
+
// Replace with a new InteractiveCodeSetup instance
|
|
353
|
+
this.initialCode = this.editorInstance.getValue();
|
|
354
|
+
this.replaceWithInteractiveCodeSetup();
|
|
355
|
+
|
|
356
|
+
} else {
|
|
357
|
+
// First run after prediction is locked in
|
|
358
|
+
this.clearOutput();
|
|
359
|
+
this.runnerInstance.run(this.editorInstance, this.predictionOutputId); // Pass the new output ID
|
|
360
|
+
|
|
361
|
+
// Display the prediction and output side by side
|
|
362
|
+
this.displayPredictionAndOutput();
|
|
363
|
+
|
|
364
|
+
// Set flag to indicate prediction has been displayed
|
|
365
|
+
this.predictionDisplayed = true;
|
|
366
|
+
}
|
|
367
|
+
}
|
|
368
|
+
|
|
369
|
+
resetCode() {
|
|
370
|
+
if (this.predictionDisplayed) {
|
|
371
|
+
// Replace with a new InteractiveCodeSetup instance
|
|
372
|
+
this.replaceWithInteractiveCodeSetup();
|
|
373
|
+
} else {
|
|
374
|
+
// First reset (unlikely, but handle just in case)
|
|
375
|
+
this.clearOutput();
|
|
376
|
+
this.editorInstance.resetEditor(this.initialCode);
|
|
377
|
+
}
|
|
378
|
+
}
|
|
379
|
+
|
|
380
|
+
cancelCodeExecution() {
|
|
381
|
+
if (this.predictionDisplayed) {
|
|
382
|
+
// Replace with a new InteractiveCodeSetup instance
|
|
383
|
+
this.replaceWithInteractiveCodeSetup();
|
|
384
|
+
} else {
|
|
385
|
+
// First cancel after prediction is locked in
|
|
386
|
+
if (this.runnerInstance.workerManager) {
|
|
387
|
+
this.runnerInstance.workerManager.restartWorker();
|
|
388
|
+
}
|
|
389
|
+
}
|
|
390
|
+
}
|
|
391
|
+
|
|
392
|
+
replaceWithInteractiveCodeSetup() {
|
|
393
|
+
// Get the container element
|
|
394
|
+
const container = document.getElementById(this.containerId);
|
|
395
|
+
if (container) {
|
|
396
|
+
// Clear the container's content
|
|
397
|
+
container.innerHTML = '';
|
|
398
|
+
|
|
399
|
+
// Create a new instance of InteractiveCodeSetup
|
|
400
|
+
new InteractiveCodeSetup(this.containerId, this.initialCode);
|
|
401
|
+
} else {
|
|
402
|
+
console.error(`Container with ID ${this.containerId} not found.`);
|
|
403
|
+
}
|
|
404
|
+
}
|
|
405
|
+
|
|
406
|
+
displayPredictionAndOutput() {
|
|
407
|
+
// Display the user's prediction
|
|
408
|
+
document.getElementById(this.predictionDisplayId).textContent = this.prediction;
|
|
409
|
+
|
|
410
|
+
// Hide the original output element
|
|
411
|
+
if (this.originalOutputElement) {
|
|
412
|
+
this.originalOutputElement.style.display = 'none';
|
|
413
|
+
}
|
|
414
|
+
|
|
415
|
+
// Show the prediction-output container
|
|
416
|
+
document.getElementById(this.predictionOutputContainerId).style.display = 'flex';
|
|
417
|
+
}
|
|
418
|
+
|
|
419
|
+
clearOutput() {
|
|
420
|
+
if (this.predictionDisplayed) {
|
|
421
|
+
const outputElement = document.getElementById(this.predictionOutputId);
|
|
422
|
+
if (outputElement) {
|
|
423
|
+
outputElement.textContent = "";
|
|
424
|
+
}
|
|
425
|
+
} else {
|
|
426
|
+
const outputElement = document.getElementById(this.outputId);
|
|
427
|
+
if (outputElement) {
|
|
428
|
+
outputElement.textContent = "";
|
|
429
|
+
}
|
|
430
|
+
}
|
|
431
|
+
const errorBoxElement = document.getElementById(this.errorBoxId);
|
|
432
|
+
if (errorBoxElement) {
|
|
433
|
+
errorBoxElement.textContent = "";
|
|
434
|
+
}
|
|
435
|
+
}
|
|
436
|
+
}
|
|
437
|
+
|
|
438
|
+
// Function to initialize the prediction code editor
|
|
439
|
+
function makePredictionInteractiveCode(containerId, initialCode) {
|
|
440
|
+
return new PredictionInteractiveCodeSetup(containerId, initialCode);
|
|
441
|
+
}
|