docusaurus-live-brython 3.0.0-beta.11 → 3.0.0-beta.4
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.
- package/README.md +0 -12
- package/lib/index.d.ts +7 -0
- package/lib/index.js +0 -15
- package/lib/theme/CodeBlock/index.jsx +4 -2
- package/lib/theme/CodeEditor/Actions/DownloadCode.jsx +2 -2
- package/lib/theme/CodeEditor/Actions/Reset.jsx +2 -2
- package/lib/theme/CodeEditor/Actions/RunCode.d.ts +1 -1
- package/lib/theme/CodeEditor/Actions/RunCode.jsx +2 -2
- package/lib/theme/CodeEditor/Actions/ShowRaw.jsx +2 -2
- package/lib/theme/CodeEditor/Actions/ShowSyncStatus.jsx +3 -3
- package/lib/theme/CodeEditor/BrythonCommunicator.jsx +2 -2
- package/lib/theme/CodeEditor/Button/index.d.ts +2 -2
- package/lib/theme/CodeEditor/Button/index.jsx +1 -1
- package/lib/theme/CodeEditor/CodeHistory/index.jsx +2 -2
- package/lib/theme/CodeEditor/Editor/EditorAce.jsx +2 -2
- package/lib/theme/CodeEditor/Editor/Header/index.d.ts +1 -1
- package/lib/theme/CodeEditor/Editor/Header/index.jsx +6 -6
- package/lib/theme/CodeEditor/Editor/Result/Graphics/Canvas.d.ts +2 -2
- package/lib/theme/CodeEditor/Editor/Result/Graphics/Canvas.jsx +7 -7
- package/lib/theme/CodeEditor/Editor/Result/Graphics/Turtle.d.ts +2 -2
- package/lib/theme/CodeEditor/Editor/Result/Graphics/Turtle.jsx +8 -8
- package/lib/theme/CodeEditor/Editor/Result/Graphics/index.d.ts +3 -3
- package/lib/theme/CodeEditor/Editor/Result/Graphics/index.jsx +6 -6
- package/lib/theme/CodeEditor/Editor/Result/index.d.ts +3 -1
- package/lib/theme/CodeEditor/Editor/Result/index.jsx +3 -2
- package/lib/theme/CodeEditor/Editor/index.d.ts +1 -1
- package/lib/theme/CodeEditor/Editor/index.jsx +11 -11
- package/lib/theme/CodeEditor/Editor/utils/saveSvg.js +1 -1
- package/lib/theme/CodeEditor/Icon/index.d.ts +2 -2
- package/lib/theme/CodeEditor/Icon/index.jsx +1 -1
- package/lib/theme/CodeEditor/WithScript/Storage.d.ts +1 -1
- package/lib/theme/CodeEditor/WithScript/Store.d.ts +7 -1
- package/lib/theme/CodeEditor/WithScript/Store.jsx +235 -2
- package/lib/theme/CodeEditor/WithScript/Types.d.ts +0 -1
- package/lib/theme/CodeEditor/index.d.ts +3 -3
- package/lib/theme/CodeEditor/index.jsx +6 -6
- package/lib/types.d.ts +28 -0
- package/lib/types.js +1 -0
- package/package.json +23 -79
- package/src/index.ts +0 -10
- package/src/theme/CodeBlock/index.tsx +9 -2
- package/src/theme/CodeEditor/Actions/DownloadCode.tsx +2 -2
- package/src/theme/CodeEditor/Actions/Reset.tsx +2 -2
- package/src/theme/CodeEditor/Actions/RunCode.tsx +3 -3
- package/src/theme/CodeEditor/Actions/ShowRaw.tsx +2 -2
- package/src/theme/CodeEditor/Actions/ShowSyncStatus.tsx +3 -3
- package/src/theme/CodeEditor/BrythonCommunicator.tsx +3 -3
- package/src/theme/CodeEditor/Button/index.tsx +3 -3
- package/src/theme/CodeEditor/CodeHistory/index.tsx +2 -2
- package/src/theme/CodeEditor/Editor/EditorAce.tsx +2 -2
- package/src/theme/CodeEditor/Editor/Header/index.tsx +7 -7
- package/src/theme/CodeEditor/Editor/Result/Graphics/Canvas.tsx +7 -7
- package/src/theme/CodeEditor/Editor/Result/Graphics/Turtle.tsx +8 -8
- package/src/theme/CodeEditor/Editor/Result/Graphics/index.tsx +7 -7
- package/src/theme/CodeEditor/Editor/Result/index.tsx +6 -2
- package/src/theme/CodeEditor/Editor/index.tsx +15 -13
- package/src/theme/CodeEditor/Editor/utils/saveSvg.ts +1 -1
- package/src/theme/CodeEditor/Editor/utils/svgWithoutAnimations.ts +1 -1
- package/src/theme/CodeEditor/Icon/index.tsx +2 -2
- package/src/theme/CodeEditor/WithScript/Storage.ts +1 -1
- package/src/theme/CodeEditor/WithScript/Store.tsx +269 -3
- package/src/theme/CodeEditor/WithScript/Types.ts +0 -1
- package/src/theme/CodeEditor/index.tsx +8 -8
- package/src/types.ts +29 -0
- package/.prettierrc +0 -9
- package/lib/theme/CodeEditor/WithScript/createStore.d.ts +0 -2
- package/lib/theme/CodeEditor/WithScript/createStore.js +0 -223
- package/lib/theme/CodeEditor/hooks/index.d.ts +0 -2
- package/lib/theme/CodeEditor/hooks/index.js +0 -2
- package/lib/theme/CodeEditor/hooks/useScript.d.ts +0 -4
- package/lib/theme/CodeEditor/hooks/useScript.js +0 -10
- package/lib/theme/CodeEditor/hooks/useStore.d.ts +0 -2
- package/lib/theme/CodeEditor/hooks/useStore.js +0 -4
- package/src/theme/CodeEditor/WithScript/createStore.ts +0 -247
- package/src/theme/CodeEditor/hooks/index.ts +0 -2
- package/src/theme/CodeEditor/hooks/useScript.ts +0 -15
- package/src/theme/CodeEditor/hooks/useStore.ts +0 -9
|
@@ -1,223 +0,0 @@
|
|
|
1
|
-
import { v4 as uuidv4 } from 'uuid';
|
|
2
|
-
import { createStorageSlot } from "@docusaurus/theme-common";
|
|
3
|
-
import { getStorageScript, syncStorageScript } from "@theme/CodeEditor/WithScript/Storage";
|
|
4
|
-
import { checkCanvasOutput, checkGraphicsOutput, checkTurtleOutput, getPreCode, sanitizePyScript } from "@theme/CodeEditor/WithScript/helpers";
|
|
5
|
-
import { Status } from "@theme/CodeEditor/WithScript/Types";
|
|
6
|
-
import { DOM_ELEMENT_IDS } from "@theme/CodeEditor/constants";
|
|
7
|
-
import throttle from 'lodash/throttle';
|
|
8
|
-
export const createStore = (props, libDir, syncMaxOnceEvery) => {
|
|
9
|
-
const canSave = !!props.id;
|
|
10
|
-
const id = props.id || uuidv4();
|
|
11
|
-
const codeId = `code.${props.title || props.lang}.${id}`.replace(/(-|\.)/g, '_');
|
|
12
|
-
const createdAt = new Date();
|
|
13
|
-
const storageKey = `code.${props.title || 'code_block'}.${id}`;
|
|
14
|
-
const storage = createStorageSlot(storageKey);
|
|
15
|
-
storage.listen((e) => {
|
|
16
|
-
if (e.key === storageKey) {
|
|
17
|
-
try {
|
|
18
|
-
if (e.newValue) {
|
|
19
|
-
const script = JSON.parse(e.newValue);
|
|
20
|
-
if (new Date(script.updatedAt) > state.updatedAt) {
|
|
21
|
-
loadData(storage);
|
|
22
|
-
}
|
|
23
|
-
}
|
|
24
|
-
}
|
|
25
|
-
catch (err) {
|
|
26
|
-
console.warn(err);
|
|
27
|
-
}
|
|
28
|
-
}
|
|
29
|
-
});
|
|
30
|
-
const loadData = (store) => {
|
|
31
|
-
setState((s) => ({ ...s, status: canSave ? Status.SYNCING : s.status }));
|
|
32
|
-
const script = getStorageScript(store);
|
|
33
|
-
const loadedCode = script?.code ? prepareCode(script.code, { codeOnly: true }) : {};
|
|
34
|
-
addVersion.cancel();
|
|
35
|
-
if (!state.isLoaded) {
|
|
36
|
-
setState((s) => ({
|
|
37
|
-
...s,
|
|
38
|
-
isLoaded: true,
|
|
39
|
-
...(script || {}),
|
|
40
|
-
...loadedCode,
|
|
41
|
-
versions: script?.versions || [],
|
|
42
|
-
versionsLoaded: true,
|
|
43
|
-
status: canSave ? Status.SUCCESS : s.status
|
|
44
|
-
}));
|
|
45
|
-
return Status.SUCCESS;
|
|
46
|
-
}
|
|
47
|
-
if (script) {
|
|
48
|
-
setState((s) => ({ ...s, ...script, ...loadedCode, status: canSave ? Status.SUCCESS : s.status, versionsLoaded: true }));
|
|
49
|
-
return Status.SUCCESS;
|
|
50
|
-
}
|
|
51
|
-
setState((s) => ({ ...s, status: canSave ? Status.ERROR : s.status }));
|
|
52
|
-
return Status.ERROR;
|
|
53
|
-
};
|
|
54
|
-
const prepareCode = (raw, config = {}) => {
|
|
55
|
-
const { pre, code } = config.codeOnly
|
|
56
|
-
? { pre: getPreCode(state.pristineCode).pre, code: raw }
|
|
57
|
-
: getPreCode(raw);
|
|
58
|
-
const hasEdits = code !== (config.stateNotInitialized ? getPreCode(props.raw).code : state.pristineCode);
|
|
59
|
-
const updatedAt = new Date();
|
|
60
|
-
const hasCanvasOutput = checkCanvasOutput(raw);
|
|
61
|
-
const hasTurtleOutput = checkTurtleOutput(raw);
|
|
62
|
-
const hasGraphicsOutput = checkGraphicsOutput(raw);
|
|
63
|
-
if (props.versioned && !config.stateNotInitialized) {
|
|
64
|
-
addVersion({ code: code, createdAt: updatedAt, version: state.versions.length + 1 });
|
|
65
|
-
}
|
|
66
|
-
return {
|
|
67
|
-
code: code,
|
|
68
|
-
preCode: pre,
|
|
69
|
-
hasCanvasOutput: hasCanvasOutput,
|
|
70
|
-
hasTurtleOutput: hasTurtleOutput,
|
|
71
|
-
hasGraphicsOutput: hasGraphicsOutput,
|
|
72
|
-
hasEdits: hasEdits,
|
|
73
|
-
updatedAt: updatedAt
|
|
74
|
-
};
|
|
75
|
-
};
|
|
76
|
-
const setCode = (raw, action) => {
|
|
77
|
-
if (state.isPasted && action === 'remove') {
|
|
78
|
-
return;
|
|
79
|
-
}
|
|
80
|
-
const data = prepareCode(raw);
|
|
81
|
-
setState((state) => ({
|
|
82
|
-
...state,
|
|
83
|
-
...data
|
|
84
|
-
}));
|
|
85
|
-
if (props.id) {
|
|
86
|
-
const toStore = { code: data.code, createdAt: state.createdAt, updatedAt: data.updatedAt, versions: state.versions };
|
|
87
|
-
if (state.isPasted) {
|
|
88
|
-
addVersion.flush();
|
|
89
|
-
if (toStore.versions.length > 0) {
|
|
90
|
-
toStore.versions[toStore.versions.length - 1].pasted = true;
|
|
91
|
-
}
|
|
92
|
-
set(toStore);
|
|
93
|
-
set.flush();
|
|
94
|
-
state.isPasted = false;
|
|
95
|
-
}
|
|
96
|
-
else {
|
|
97
|
-
set(toStore);
|
|
98
|
-
}
|
|
99
|
-
}
|
|
100
|
-
};
|
|
101
|
-
const execScript = () => {
|
|
102
|
-
const toExec = `${state.code}`;
|
|
103
|
-
const lineShift = state.preCode.split(/\n/).length;
|
|
104
|
-
const src = `from brython_runner import run
|
|
105
|
-
run("""${sanitizePyScript(toExec || '')}""", '${codeId}', ${lineShift})
|
|
106
|
-
`;
|
|
107
|
-
if (!window.__BRYTHON__) {
|
|
108
|
-
alert('Brython not loaded');
|
|
109
|
-
return;
|
|
110
|
-
}
|
|
111
|
-
setState((s) => ({ ...s, isExecuting: true, isGraphicsmodalOpen: state.hasGraphicsOutput }));
|
|
112
|
-
const active = document.getElementById(DOM_ELEMENT_IDS.communicator(state.codeId));
|
|
113
|
-
active.setAttribute('data--start-time', `${Date.now()}`);
|
|
114
|
-
/**
|
|
115
|
-
* ensure that the script is executed after the current event loop.
|
|
116
|
-
* Otherwise, the brython script will not be able to access the graphics output.
|
|
117
|
-
*/
|
|
118
|
-
setTimeout(() => {
|
|
119
|
-
window.__BRYTHON__.runPythonSource(src, {
|
|
120
|
-
pythonpath: [libDir]
|
|
121
|
-
});
|
|
122
|
-
}, 0);
|
|
123
|
-
};
|
|
124
|
-
const load = async () => {
|
|
125
|
-
return loadData(storage);
|
|
126
|
-
};
|
|
127
|
-
const _set = async (script) => {
|
|
128
|
-
setState((s) => ({ ...s, status: canSave ? Status.SYNCING : s.status }));
|
|
129
|
-
if (syncStorageScript(script, storage)) {
|
|
130
|
-
setState((s) => ({ ...s, status: canSave ? Status.SUCCESS : s.status }));
|
|
131
|
-
return Status.SUCCESS;
|
|
132
|
-
}
|
|
133
|
-
setState((s) => ({ ...s, status: canSave ? Status.ERROR : s.status }));
|
|
134
|
-
return Status.ERROR;
|
|
135
|
-
};
|
|
136
|
-
const set = throttle(_set, syncMaxOnceEvery, { leading: false, trailing: true });
|
|
137
|
-
const _addVersion = (version) => {
|
|
138
|
-
if (!props.versioned || !props.id) {
|
|
139
|
-
return;
|
|
140
|
-
}
|
|
141
|
-
const versions = [...state.versions];
|
|
142
|
-
versions.push(version);
|
|
143
|
-
setState((s) => ({ ...s, versions: versions }));
|
|
144
|
-
};
|
|
145
|
-
const addVersion = throttle(_addVersion, syncMaxOnceEvery, { leading: false, trailing: true });
|
|
146
|
-
const saveNow = async () => {
|
|
147
|
-
addVersion.flush();
|
|
148
|
-
return set.flush();
|
|
149
|
-
};
|
|
150
|
-
const del = async () => {
|
|
151
|
-
storage.del();
|
|
152
|
-
return Status.SUCCESS;
|
|
153
|
-
};
|
|
154
|
-
const codeData = prepareCode(props.raw, { stateNotInitialized: true });
|
|
155
|
-
const setExecuting = (isExecuting) => {
|
|
156
|
-
setState((s) => ({ ...s, isExecuting: isExecuting }));
|
|
157
|
-
};
|
|
158
|
-
const addLogMessage = (log) => {
|
|
159
|
-
setState((s) => ({ ...s, logs: [...s.logs, log] }));
|
|
160
|
-
};
|
|
161
|
-
const clearLogMessages = () => {
|
|
162
|
-
setState((s) => ({ ...s, logs: [] }));
|
|
163
|
-
};
|
|
164
|
-
const closeGraphicsModal = () => {
|
|
165
|
-
setState((s) => ({ ...s, isGraphicsmodalOpen: false }));
|
|
166
|
-
};
|
|
167
|
-
const stopScript = () => {
|
|
168
|
-
const code = document.getElementById(DOM_ELEMENT_IDS.communicator(state.codeId));
|
|
169
|
-
if (code) {
|
|
170
|
-
code.removeAttribute('data--start-time');
|
|
171
|
-
}
|
|
172
|
-
};
|
|
173
|
-
let state = {
|
|
174
|
-
id: id,
|
|
175
|
-
codeId: codeId,
|
|
176
|
-
lang: props.lang,
|
|
177
|
-
showRaw: false,
|
|
178
|
-
pristineCode: codeData.code,
|
|
179
|
-
isExecuting: false,
|
|
180
|
-
logs: [],
|
|
181
|
-
isGraphicsmodalOpen: false,
|
|
182
|
-
hasEdits: false,
|
|
183
|
-
createdAt: createdAt,
|
|
184
|
-
isLoaded: false,
|
|
185
|
-
status: Status.IDLE,
|
|
186
|
-
versions: [],
|
|
187
|
-
versionsLoaded: false,
|
|
188
|
-
isPasted: false,
|
|
189
|
-
...codeData
|
|
190
|
-
};
|
|
191
|
-
const getState = () => state;
|
|
192
|
-
const listeners = new Set();
|
|
193
|
-
const setState = (fn) => {
|
|
194
|
-
state = fn(state);
|
|
195
|
-
listeners.forEach((l) => l());
|
|
196
|
-
};
|
|
197
|
-
const subscribe = (listener) => {
|
|
198
|
-
listeners.add(listener);
|
|
199
|
-
return () => listeners.delete(listener);
|
|
200
|
-
};
|
|
201
|
-
const loadVersions = async () => {
|
|
202
|
-
// noop
|
|
203
|
-
state.isLoaded = false;
|
|
204
|
-
load();
|
|
205
|
-
setState((s) => ({ ...s, versionsLoaded: true }));
|
|
206
|
-
return Promise.resolve();
|
|
207
|
-
};
|
|
208
|
-
return {
|
|
209
|
-
getState,
|
|
210
|
-
setState,
|
|
211
|
-
subscribe,
|
|
212
|
-
saveNow,
|
|
213
|
-
addLogMessage,
|
|
214
|
-
clearLogMessages,
|
|
215
|
-
closeGraphicsModal,
|
|
216
|
-
setCode,
|
|
217
|
-
execScript,
|
|
218
|
-
setExecuting,
|
|
219
|
-
stopScript,
|
|
220
|
-
load,
|
|
221
|
-
loadVersions
|
|
222
|
-
};
|
|
223
|
-
};
|
|
@@ -1,10 +0,0 @@
|
|
|
1
|
-
import { Context } from "@theme/CodeEditor/WithScript/Store";
|
|
2
|
-
import { ReactContextError } from "@docusaurus/theme-common";
|
|
3
|
-
import { useContext } from "react";
|
|
4
|
-
export function useScript() {
|
|
5
|
-
const context = useContext(Context);
|
|
6
|
-
if (context === null) {
|
|
7
|
-
throw new ReactContextError('ScriptContextProvider', 'The Component must be a child of the ScriptContextProvider component');
|
|
8
|
-
}
|
|
9
|
-
return context;
|
|
10
|
-
}
|
|
@@ -1,247 +0,0 @@
|
|
|
1
|
-
import { v4 as uuidv4 } from 'uuid';
|
|
2
|
-
import { createStorageSlot } from "@docusaurus/theme-common";
|
|
3
|
-
import { getStorageScript, syncStorageScript } from "@theme/CodeEditor/WithScript/Storage";
|
|
4
|
-
import { checkCanvasOutput, checkGraphicsOutput, checkTurtleOutput, getPreCode, sanitizePyScript } from "@theme/CodeEditor/WithScript/helpers";
|
|
5
|
-
import { type InitState, type LogMessage, type Script, Status, type Store, type StoredScript, type Version } from "@theme/CodeEditor/WithScript/Types";
|
|
6
|
-
import { DOM_ELEMENT_IDS } from "@theme/CodeEditor/constants";
|
|
7
|
-
import throttle from 'lodash/throttle';
|
|
8
|
-
|
|
9
|
-
export const createStore = (props: InitState, libDir: string, syncMaxOnceEvery: number): Store => {
|
|
10
|
-
const canSave = !!props.id;
|
|
11
|
-
const id = props.id || uuidv4();
|
|
12
|
-
const codeId = `code.${props.title || props.lang}.${id}`.replace(/(-|\.)/g, '_');
|
|
13
|
-
const createdAt = new Date();
|
|
14
|
-
const storageKey = `code.${props.title || 'code_block'}.${id}`;
|
|
15
|
-
const storage = createStorageSlot(storageKey);
|
|
16
|
-
storage.listen((e) => {
|
|
17
|
-
if (e.key === storageKey) {
|
|
18
|
-
try {
|
|
19
|
-
if (e.newValue) {
|
|
20
|
-
const script = JSON.parse(e.newValue) as StoredScript;
|
|
21
|
-
if (new Date(script.updatedAt) > state.updatedAt) {
|
|
22
|
-
loadData(storage);
|
|
23
|
-
}
|
|
24
|
-
}
|
|
25
|
-
} catch (err) {
|
|
26
|
-
console.warn(err);
|
|
27
|
-
}
|
|
28
|
-
}
|
|
29
|
-
});
|
|
30
|
-
|
|
31
|
-
const loadData = (store) => {
|
|
32
|
-
setState((s) => ({...s, status: canSave ? Status.SYNCING : s.status}));
|
|
33
|
-
const script = getStorageScript(store);
|
|
34
|
-
const loadedCode = script?.code ? prepareCode(script.code, { codeOnly: true }) : {};
|
|
35
|
-
addVersion.cancel();
|
|
36
|
-
if (!state.isLoaded) {
|
|
37
|
-
setState((s) => ({
|
|
38
|
-
...s,
|
|
39
|
-
isLoaded: true,
|
|
40
|
-
...(script || {}),
|
|
41
|
-
...loadedCode,
|
|
42
|
-
versions: script?.versions || [],
|
|
43
|
-
versionsLoaded: true,
|
|
44
|
-
status: canSave ? Status.SUCCESS : s.status
|
|
45
|
-
}));
|
|
46
|
-
return Status.SUCCESS;
|
|
47
|
-
}
|
|
48
|
-
if (script) {
|
|
49
|
-
setState((s) => ({...s, ...script, ...loadedCode, status: canSave ? Status.SUCCESS : s.status, versionsLoaded: true}));
|
|
50
|
-
return Status.SUCCESS;
|
|
51
|
-
}
|
|
52
|
-
setState((s) => ({...s, status: canSave ? Status.ERROR : s.status}));
|
|
53
|
-
return Status.ERROR;
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
const prepareCode = (raw: string, config: { codeOnly?: boolean, stateNotInitialized?: boolean } = {}) => {
|
|
58
|
-
const { pre, code } = config.codeOnly
|
|
59
|
-
? { pre: getPreCode(state.pristineCode).pre, code: raw }
|
|
60
|
-
: getPreCode(raw);
|
|
61
|
-
const hasEdits = code !== (config.stateNotInitialized ? getPreCode(props.raw).code : state.pristineCode);
|
|
62
|
-
const updatedAt = new Date();
|
|
63
|
-
const hasCanvasOutput = checkCanvasOutput(raw);
|
|
64
|
-
const hasTurtleOutput = checkTurtleOutput(raw);
|
|
65
|
-
const hasGraphicsOutput = checkGraphicsOutput(raw);
|
|
66
|
-
if (props.versioned && !config.stateNotInitialized) {
|
|
67
|
-
addVersion({code: code, createdAt: updatedAt, version: state.versions.length + 1});
|
|
68
|
-
}
|
|
69
|
-
return {
|
|
70
|
-
code: code,
|
|
71
|
-
preCode: pre,
|
|
72
|
-
hasCanvasOutput: hasCanvasOutput,
|
|
73
|
-
hasTurtleOutput: hasTurtleOutput,
|
|
74
|
-
hasGraphicsOutput: hasGraphicsOutput,
|
|
75
|
-
hasEdits: hasEdits,
|
|
76
|
-
updatedAt: updatedAt
|
|
77
|
-
};
|
|
78
|
-
}
|
|
79
|
-
|
|
80
|
-
const setCode = (raw: string, action?: 'insert' | 'remove' | string) => {
|
|
81
|
-
if (state.isPasted && action === 'remove') {
|
|
82
|
-
return;
|
|
83
|
-
}
|
|
84
|
-
const data = prepareCode(raw);
|
|
85
|
-
setState(
|
|
86
|
-
(state) => ({
|
|
87
|
-
...state,
|
|
88
|
-
...data
|
|
89
|
-
})
|
|
90
|
-
);
|
|
91
|
-
if (props.id) {
|
|
92
|
-
const toStore: StoredScript = {code: data.code, createdAt: state.createdAt, updatedAt: data.updatedAt, versions: state.versions};
|
|
93
|
-
if (state.isPasted) {
|
|
94
|
-
addVersion.flush();
|
|
95
|
-
if (toStore.versions.length > 0) {
|
|
96
|
-
toStore.versions[toStore.versions.length - 1].pasted = true;
|
|
97
|
-
}
|
|
98
|
-
set(toStore);
|
|
99
|
-
set.flush();
|
|
100
|
-
state.isPasted = false;
|
|
101
|
-
} else {
|
|
102
|
-
set(toStore);
|
|
103
|
-
}
|
|
104
|
-
}
|
|
105
|
-
};
|
|
106
|
-
|
|
107
|
-
const execScript = () => {
|
|
108
|
-
const toExec = `${state.code}`;
|
|
109
|
-
const lineShift = state.preCode.split(/\n/).length;
|
|
110
|
-
const src = `from brython_runner import run
|
|
111
|
-
run("""${sanitizePyScript(toExec || '')}""", '${codeId}', ${lineShift})
|
|
112
|
-
`;
|
|
113
|
-
if (!(window as any).__BRYTHON__) {
|
|
114
|
-
alert('Brython not loaded');
|
|
115
|
-
return;
|
|
116
|
-
}
|
|
117
|
-
setState((s) => ({...s, isExecuting: true, isGraphicsmodalOpen: state.hasGraphicsOutput}));
|
|
118
|
-
const active = document.getElementById(DOM_ELEMENT_IDS.communicator(state.codeId));
|
|
119
|
-
active.setAttribute('data--start-time', `${Date.now()}`);
|
|
120
|
-
/**
|
|
121
|
-
* ensure that the script is executed after the current event loop.
|
|
122
|
-
* Otherwise, the brython script will not be able to access the graphics output.
|
|
123
|
-
*/
|
|
124
|
-
setTimeout(() => {
|
|
125
|
-
(window as any).__BRYTHON__.runPythonSource(
|
|
126
|
-
src,
|
|
127
|
-
{
|
|
128
|
-
pythonpath: [libDir]
|
|
129
|
-
}
|
|
130
|
-
);
|
|
131
|
-
}, 0);
|
|
132
|
-
};
|
|
133
|
-
const load = async () => {
|
|
134
|
-
return loadData(storage);
|
|
135
|
-
};
|
|
136
|
-
const _set = async (script: StoredScript) => {
|
|
137
|
-
setState((s) => ({...s, status: canSave ? Status.SYNCING : s.status}));
|
|
138
|
-
if (syncStorageScript(script, storage)) {
|
|
139
|
-
setState((s) => ({...s, status: canSave ? Status.SUCCESS : s.status}));
|
|
140
|
-
return Status.SUCCESS;
|
|
141
|
-
}
|
|
142
|
-
setState((s) => ({...s, status: canSave ? Status.ERROR : s.status}));
|
|
143
|
-
return Status.ERROR;
|
|
144
|
-
};
|
|
145
|
-
|
|
146
|
-
const set = throttle(
|
|
147
|
-
_set,
|
|
148
|
-
syncMaxOnceEvery,
|
|
149
|
-
{leading: false, trailing: true}
|
|
150
|
-
);
|
|
151
|
-
|
|
152
|
-
const _addVersion = (version: Version) => {
|
|
153
|
-
if (!props.versioned || !props.id) {
|
|
154
|
-
return;
|
|
155
|
-
}
|
|
156
|
-
const versions = [...state.versions];
|
|
157
|
-
versions.push(version);
|
|
158
|
-
setState((s) => ({...s, versions: versions}));
|
|
159
|
-
}
|
|
160
|
-
const addVersion = throttle(
|
|
161
|
-
_addVersion,
|
|
162
|
-
syncMaxOnceEvery,
|
|
163
|
-
{leading: false, trailing: true}
|
|
164
|
-
);
|
|
165
|
-
|
|
166
|
-
const saveNow = async () => {
|
|
167
|
-
addVersion.flush();
|
|
168
|
-
return set.flush();
|
|
169
|
-
}
|
|
170
|
-
|
|
171
|
-
const del = async () => {
|
|
172
|
-
storage.del();
|
|
173
|
-
return Status.SUCCESS;
|
|
174
|
-
}
|
|
175
|
-
const codeData = prepareCode(props.raw, { stateNotInitialized: true });
|
|
176
|
-
const setExecuting = (isExecuting: boolean) => {
|
|
177
|
-
setState((s) => ({...s, isExecuting: isExecuting}))
|
|
178
|
-
};
|
|
179
|
-
const addLogMessage = (log: LogMessage) => {
|
|
180
|
-
setState((s) => ({...s, logs: [...s.logs, log]}));
|
|
181
|
-
};
|
|
182
|
-
const clearLogMessages = () => {
|
|
183
|
-
setState((s) => ({...s, logs: []}));
|
|
184
|
-
};
|
|
185
|
-
const closeGraphicsModal = () => {
|
|
186
|
-
setState((s) => ({...s, isGraphicsmodalOpen: false}));
|
|
187
|
-
};
|
|
188
|
-
const stopScript = () => {
|
|
189
|
-
const code = document.getElementById(DOM_ELEMENT_IDS.communicator(state.codeId));
|
|
190
|
-
if (code) {
|
|
191
|
-
code.removeAttribute('data--start-time');
|
|
192
|
-
}
|
|
193
|
-
};
|
|
194
|
-
let state: Script = {
|
|
195
|
-
id: id,
|
|
196
|
-
codeId: codeId,
|
|
197
|
-
lang: props.lang,
|
|
198
|
-
showRaw: false,
|
|
199
|
-
pristineCode: codeData.code,
|
|
200
|
-
isExecuting: false,
|
|
201
|
-
logs: [],
|
|
202
|
-
isGraphicsmodalOpen: false,
|
|
203
|
-
hasEdits: false,
|
|
204
|
-
createdAt: createdAt,
|
|
205
|
-
isLoaded: false,
|
|
206
|
-
status: Status.IDLE,
|
|
207
|
-
versions: [],
|
|
208
|
-
versionsLoaded: false,
|
|
209
|
-
isPasted: false,
|
|
210
|
-
...codeData
|
|
211
|
-
};
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
const getState = () => state;
|
|
215
|
-
const listeners = new Set<() => void>();
|
|
216
|
-
const setState = (fn: (state: Script) => Script) => {
|
|
217
|
-
state = fn(state);
|
|
218
|
-
listeners.forEach((l) => l());
|
|
219
|
-
};
|
|
220
|
-
const subscribe = (listener: () => void) => {
|
|
221
|
-
listeners.add(listener);
|
|
222
|
-
return () => listeners.delete(listener);
|
|
223
|
-
};
|
|
224
|
-
const loadVersions = async () => {
|
|
225
|
-
// noop
|
|
226
|
-
state.isLoaded = false;
|
|
227
|
-
load();
|
|
228
|
-
setState((s) => ({...s, versionsLoaded: true}));
|
|
229
|
-
return Promise.resolve();
|
|
230
|
-
}
|
|
231
|
-
|
|
232
|
-
return {
|
|
233
|
-
getState,
|
|
234
|
-
setState,
|
|
235
|
-
subscribe,
|
|
236
|
-
saveNow,
|
|
237
|
-
addLogMessage,
|
|
238
|
-
clearLogMessages,
|
|
239
|
-
closeGraphicsModal,
|
|
240
|
-
setCode,
|
|
241
|
-
execScript,
|
|
242
|
-
setExecuting,
|
|
243
|
-
stopScript,
|
|
244
|
-
load,
|
|
245
|
-
loadVersions
|
|
246
|
-
} satisfies Store;
|
|
247
|
-
};
|
|
@@ -1,15 +0,0 @@
|
|
|
1
|
-
import { Context } from "@theme/CodeEditor/WithScript/Store";
|
|
2
|
-
import {type Store } from "@theme/CodeEditor/WithScript/Types";
|
|
3
|
-
import { ReactContextError } from "@docusaurus/theme-common";
|
|
4
|
-
import { useContext } from "react";
|
|
5
|
-
|
|
6
|
-
export function useScript(): {store: Store} {
|
|
7
|
-
const context = useContext(Context);
|
|
8
|
-
if (context === null) {
|
|
9
|
-
throw new ReactContextError(
|
|
10
|
-
'ScriptContextProvider',
|
|
11
|
-
'The Component must be a child of the ScriptContextProvider component',
|
|
12
|
-
);
|
|
13
|
-
}
|
|
14
|
-
return context;
|
|
15
|
-
}
|
|
@@ -1,9 +0,0 @@
|
|
|
1
|
-
import {Selector, type Store } from "@theme/CodeEditor/WithScript/Types";
|
|
2
|
-
import { useCallback, useSyncExternalStore } from "react";
|
|
3
|
-
|
|
4
|
-
export const useStore = <T, R>(store: Store<T>, selector: Selector<T, R>): R => {
|
|
5
|
-
return useSyncExternalStore(
|
|
6
|
-
store.subscribe,
|
|
7
|
-
useCallback(() => selector(store.getState()), [store, selector])
|
|
8
|
-
);
|
|
9
|
-
}
|