js-dos 8.1.5 → 8.1.6
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/dist/emulators/emulators.js +2 -0
- package/dist/emulators/emulators.js.map +1 -0
- package/dist/emulators/types/build.d.ts +28 -0
- package/dist/emulators/types/dos/bundle/dos-bundle.d.ts +20 -0
- package/dist/emulators/types/dos/dosbox/ts/direct.d.ts +3 -0
- package/dist/emulators/types/dos/dosbox/ts/worker.d.ts +3 -0
- package/dist/emulators/types/emulators.d.ts +76 -0
- package/dist/emulators/types/http.d.ts +9 -0
- package/dist/emulators/types/impl/ci-impl.d.ts +29 -0
- package/dist/emulators/types/impl/emulators-impl.d.ts +26 -0
- package/dist/emulators/types/impl/modules.d.ts +38 -0
- package/dist/emulators/types/libzip/libzip.d.ts +16 -0
- package/dist/emulators/types/protocol/messages-queue.d.ts +8 -0
- package/dist/emulators/types/protocol/protocol.d.ts +128 -0
- package/dist/emulators/wdosbox-x.js +55 -0
- package/dist/emulators/wdosbox-x.js.symbols +8760 -0
- package/dist/emulators/wdosbox-x.wasm +0 -0
- package/dist/emulators/wdosbox.js +55 -0
- package/dist/emulators/wdosbox.js.symbols +3001 -0
- package/dist/emulators/wdosbox.wasm +0 -0
- package/dist/emulators/wlibzip.js +21 -0
- package/dist/emulators/wlibzip.js.symbols +268 -0
- package/dist/emulators/wlibzip.wasm +0 -0
- package/dist/js-dos.css +1 -0
- package/dist/js-dos.js +22 -0
- package/dist/js-dos.js.map +1 -0
- package/package.json +1 -1
- package/release.zip +0 -0
- package/.eslintrc.json +0 -43
- package/.github/workflows/build.yml +0 -51
- package/.gitmodules +0 -4
- package/index.html +0 -110
- package/postcss.config.cjs +0 -8
- package/src/app.css +0 -14
- package/src/base.css +0 -10
- package/src/components/checkbox.tsx +0 -41
- package/src/components/close-button.tsx +0 -17
- package/src/components/components.css +0 -28
- package/src/components/dos-option-checkbox.tsx +0 -94
- package/src/components/dos-option-select.tsx +0 -108
- package/src/components/dos-option-slider.tsx +0 -35
- package/src/components/error.tsx +0 -16
- package/src/components/loading.tsx +0 -26
- package/src/components/lock.tsx +0 -10
- package/src/components/select.tsx +0 -33
- package/src/components/slider.tsx +0 -69
- package/src/download-file.ts +0 -18
- package/src/frame/account-frame.tsx +0 -156
- package/src/frame/editor/defaults.ts +0 -419
- package/src/frame/editor/editor-conf-frame.tsx +0 -227
- package/src/frame/editor/editor-frame.css +0 -55
- package/src/frame/editor/editor-fs-frame.tsx +0 -314
- package/src/frame/fat-drives-frame.tsx +0 -199
- package/src/frame/frame.css +0 -119
- package/src/frame/frame.tsx +0 -34
- package/src/frame/image-rendering-frame.tsx +0 -8
- package/src/frame/network-frame.tsx +0 -157
- package/src/frame/quick-save-frame.tsx +0 -98
- package/src/frame/settings-frame.tsx +0 -14
- package/src/frame/stats-frame.tsx +0 -87
- package/src/host/bundle-storage.ts +0 -91
- package/src/host/fullscreen.ts +0 -35
- package/src/host/lcache.ts +0 -203
- package/src/host/lstorage.ts +0 -156
- package/src/i18n.ts +0 -185
- package/src/index.css +0 -7
- package/src/load.ts +0 -132
- package/src/login/login.css +0 -9
- package/src/login/login.tsx +0 -77
- package/src/main.tsx +0 -197
- package/src/public/types.ts +0 -45
- package/src/sidebar/account-button.tsx +0 -33
- package/src/sidebar/cloud-save-button.tsx +0 -89
- package/src/sidebar/diskette-icon.tsx +0 -14
- package/src/sidebar/fullscreen-button.tsx +0 -44
- package/src/sidebar/network-button.tsx +0 -39
- package/src/sidebar/sidebar-button.tsx +0 -244
- package/src/sidebar/sidebar.css +0 -47
- package/src/sidebar/sidebar.tsx +0 -30
- package/src/sockdrive/LICENSE +0 -674
- package/src/sockdrive/README.md +0 -45
- package/src/sockdrive/include/sockdrive.h +0 -23
- package/src/sockdrive/js/.eslintrc.json +0 -43
- package/src/sockdrive/js/package.json +0 -29
- package/src/sockdrive/js/src/fatfs/chains.js +0 -318
- package/src/sockdrive/js/src/fatfs/dir.js +0 -385
- package/src/sockdrive/js/src/fatfs/helpers.js +0 -210
- package/src/sockdrive/js/src/fatfs/index.js +0 -606
- package/src/sockdrive/js/src/fatfs/structs.js +0 -255
- package/src/sockdrive/js/src/fatfs/vol.js +0 -166
- package/src/sockdrive/js/src/sockdrive/cache.ts +0 -56
- package/src/sockdrive/js/src/sockdrive/drive.ts +0 -471
- package/src/sockdrive/js/src/sockdrive/lru.ts +0 -221
- package/src/sockdrive/js/src/sockdrive/types.ts +0 -14
- package/src/sockdrive/js/src/sockdrive-fat.d.ts +0 -64
- package/src/sockdrive/js/src/sockdrive-fat.ts +0 -226
- package/src/sockdrive/js/src/sockdrive-native.ts +0 -100
- package/src/sockdrive/js/src/test/test.ts +0 -289
- package/src/sockdrive/js/tsconfig.json +0 -11
- package/src/sockdrive/js/webpack.config.js +0 -68
- package/src/sockdrive/js/yarn.lock +0 -1808
- package/src/store/auth.ts +0 -115
- package/src/store/dos.ts +0 -305
- package/src/store/editor.ts +0 -61
- package/src/store/init.ts +0 -48
- package/src/store/storage.ts +0 -32
- package/src/store/ui.ts +0 -191
- package/src/store.tsx +0 -116
- package/src/ui.tsx +0 -140
- package/src/v8/changes.ts +0 -56
- package/src/v8/config.ts +0 -20
- package/src/v8/subscriptions.ts +0 -62
- package/src/vite-env.d.ts +0 -5
- package/src/window/dos/controls/keyboard.ts +0 -32
- package/src/window/dos/controls/keys.ts +0 -331
- package/src/window/dos/controls/mouse/mount.ts +0 -99
- package/src/window/dos/controls/mouse/mouse-locked.ts +0 -51
- package/src/window/dos/controls/mouse/mouse-not-locked.ts +0 -84
- package/src/window/dos/controls/mouse/mouse-swipe.ts +0 -57
- package/src/window/dos/controls/mouse/pointer.ts +0 -85
- package/src/window/dos/controls/mouse.ts +0 -21
- package/src/window/dos/dos-dhry2.tsx +0 -191
- package/src/window/dos/dos-runtime.tsx +0 -216
- package/src/window/dos/dos-window.tsx +0 -91
- package/src/window/dos/render/canvas.ts +0 -65
- package/src/window/dos/render/resize.ts +0 -31
- package/src/window/dos/render/webgl.ts +0 -173
- package/src/window/dos/sound/audio-node.ts +0 -148
- package/src/window/error-window.tsx +0 -9
- package/src/window/loading-window.tsx +0 -54
- package/src/window/prerun-window.tsx +0 -121
- package/src/window/select-window.tsx +0 -118
- package/src/window/window.css +0 -78
- package/src/window/window.tsx +0 -49
- package/src/ws/ws-sockdrive.ts +0 -123
- package/src/ws/ws-transport-layer.ts +0 -468
- package/tailwind.config.cjs +0 -48
- package/tsconfig.json +0 -32
- package/tsconfig.node.json +0 -9
- package/vite.config.ts +0 -25
|
@@ -1,227 +0,0 @@
|
|
|
1
|
-
import { useDispatch, useSelector } from "react-redux";
|
|
2
|
-
import { useT } from "../../i18n";
|
|
3
|
-
import { State } from "../../store";
|
|
4
|
-
import { editorSlice } from "../../store/editor";
|
|
5
|
-
import { dosboxconf } from "./defaults";
|
|
6
|
-
import { dosSlice } from "../../store/dos";
|
|
7
|
-
import { useEffect, useState } from "preact/hooks";
|
|
8
|
-
import { sockdriveBackend } from "../../store/init";
|
|
9
|
-
import { uiSlice } from "../../store/ui";
|
|
10
|
-
|
|
11
|
-
const imgmount = "imgmount\\s+(\\d+)\\s+sockdrive\\s+([^\\s]+)\\s+([^\\s]+)\\s+([^\\s]+)\\s*$";
|
|
12
|
-
const cleanup = "imgmount\\s+(\\d+)\\s+sockdrive\\s+.*$";
|
|
13
|
-
|
|
14
|
-
interface Sockdrive {
|
|
15
|
-
num: string,
|
|
16
|
-
backend: string,
|
|
17
|
-
owner: string,
|
|
18
|
-
drive: string,
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
export function EditorConf() {
|
|
22
|
-
const t = useT();
|
|
23
|
-
const bundleConfig = useSelector((state: State) => state.editor.bundleConfig);
|
|
24
|
-
const account = useSelector((state: State) => state.auth.account);
|
|
25
|
-
const backend = useSelector((state: State) => state.dos.backend);
|
|
26
|
-
const { sockdriveEndpoint, sockdriveWssEndpoint } = useSelector((state: State) =>
|
|
27
|
-
sockdriveBackend[state.init.sockdriveBackendName] ??
|
|
28
|
-
sockdriveBackend["js-dos"]);
|
|
29
|
-
const dispatch = useDispatch();
|
|
30
|
-
const [myDrives, setMyDrives] = useState<{ name: string, owner: string }[]>([]);
|
|
31
|
-
|
|
32
|
-
useEffect(() => {
|
|
33
|
-
if (!account || !account.token) {
|
|
34
|
-
setMyDrives([]);
|
|
35
|
-
} else {
|
|
36
|
-
fetch(sockdriveEndpoint + "/list/drives/" + account.token.access_token)
|
|
37
|
-
.then((r) => r.json())
|
|
38
|
-
.then(setMyDrives)
|
|
39
|
-
.catch(console.error);
|
|
40
|
-
}
|
|
41
|
-
}, [account?.token, sockdriveEndpoint]);
|
|
42
|
-
|
|
43
|
-
function parseSockDrives(conf: string) {
|
|
44
|
-
const drives: { [num: string]: Sockdrive } = {};
|
|
45
|
-
const re = new RegExp(imgmount, "gm");
|
|
46
|
-
let m: RegExpExecArray | null;
|
|
47
|
-
while (m = re.exec(conf)) {
|
|
48
|
-
/* eslint-disable-next-line no-unused-vars */
|
|
49
|
-
const [_, num, backend, owner, drive] = m;
|
|
50
|
-
drives[num] = {
|
|
51
|
-
num,
|
|
52
|
-
backend,
|
|
53
|
-
owner,
|
|
54
|
-
drive,
|
|
55
|
-
};
|
|
56
|
-
}
|
|
57
|
-
return drives;
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
const [sockdrives, setSockdrives] = useState<{ [num: string]: Sockdrive }>(
|
|
61
|
-
parseSockDrives(bundleConfig?.dosboxConf ?? ""));
|
|
62
|
-
|
|
63
|
-
function setSockdrivesAndUpdateConf(sockdrives: { [num: string]: Sockdrive }) {
|
|
64
|
-
setSockdrives(sockdrives);
|
|
65
|
-
if (bundleConfig) {
|
|
66
|
-
const parts: string[] = [];
|
|
67
|
-
for (const next of Object.values(sockdrives)) {
|
|
68
|
-
if (next.owner.length > 0 && next.drive.length > 0) {
|
|
69
|
-
parts.push(`imgmount ${next.num} sockdrive ${next.backend} ${next.owner} ${next.drive}`);
|
|
70
|
-
}
|
|
71
|
-
}
|
|
72
|
-
|
|
73
|
-
let contents = bundleConfig.dosboxConf;
|
|
74
|
-
contents = contents.replaceAll(new RegExp(cleanup, "gm"), "");
|
|
75
|
-
if (parts.length > 0) {
|
|
76
|
-
let start = contents.indexOf("[autoexec]");
|
|
77
|
-
if (start === -1) {
|
|
78
|
-
start = contents.length;
|
|
79
|
-
} else {
|
|
80
|
-
start += 10;
|
|
81
|
-
}
|
|
82
|
-
const footer = contents.substring(start);
|
|
83
|
-
contents = contents.substring(0, start);
|
|
84
|
-
contents += "\n" + parts.join("\n") + "\n" + footer.trim();
|
|
85
|
-
}
|
|
86
|
-
updateDosboxConf(contents);
|
|
87
|
-
}
|
|
88
|
-
}
|
|
89
|
-
|
|
90
|
-
function changeConfig(contents: string) {
|
|
91
|
-
setSockdrives(parseSockDrives(contents));
|
|
92
|
-
updateDosboxConf(contents);
|
|
93
|
-
}
|
|
94
|
-
|
|
95
|
-
function updateDosboxConf(newConf: string) {
|
|
96
|
-
dispatch(dosSlice.actions.mouseCapture(newConf.indexOf("autolock=true") > 0));
|
|
97
|
-
dispatch(editorSlice.actions.dosboxConf(newConf));
|
|
98
|
-
dispatch(dosSlice.actions.dosBackendLocked(newConf.indexOf("sockdrive") >= 0));
|
|
99
|
-
}
|
|
100
|
-
|
|
101
|
-
if (bundleConfig === null) {
|
|
102
|
-
return null;
|
|
103
|
-
}
|
|
104
|
-
|
|
105
|
-
return <div class="editor-conf-frame flex flex-col flex-grow w-full gap-2">
|
|
106
|
-
<div class="">{t("dosboxconf_template")}</div>
|
|
107
|
-
<div class="flex flex-row flex-wrap items-center gap-2">
|
|
108
|
-
{dosboxconf
|
|
109
|
-
.map(({ name, backend, contents }) => {
|
|
110
|
-
return <button class="btn btn-sm"
|
|
111
|
-
onClick={() => {
|
|
112
|
-
dispatch(dosSlice.actions.dosBackend(backend === "dosboxX" ? "dosboxX" : "dosbox"));
|
|
113
|
-
changeConfig(contents.replaceAll("{wss-makevm}", sockdriveWssEndpoint));
|
|
114
|
-
}}>
|
|
115
|
-
{name}
|
|
116
|
-
</button>;
|
|
117
|
-
})}
|
|
118
|
-
</div>
|
|
119
|
-
{backend === "dosboxX" && <>
|
|
120
|
-
<button class="btn btn-ghost btn-xs self-start" target="_blank"
|
|
121
|
-
onClick={() => dispatch(uiSlice.actions.frameFatDrives())}>
|
|
122
|
-
{t("net_drives")}:
|
|
123
|
-
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24"
|
|
124
|
-
stroke-width="1.5" stroke="currentColor" class="w-4 h-4">
|
|
125
|
-
<path stroke-linecap="round" stroke-linejoin="round" d="m12.75 15 3-3m0 0-3-3m3
|
|
126
|
-
3h-7.5M21 12a9 9 0 1 1-18 0 9 9 0 0 1 18 0Z" />
|
|
127
|
-
</svg>
|
|
128
|
-
</button>
|
|
129
|
-
{["2", "3"].map((num) => {
|
|
130
|
-
return <div class="flex flex-row justify-start items-center gap-3 w-full">
|
|
131
|
-
<p>{num === "2" ? "C:" : "D:"}</p>
|
|
132
|
-
<div class="flex flex-col gap-2">
|
|
133
|
-
<div class="flex flex-row gap-1 items-center">
|
|
134
|
-
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24"
|
|
135
|
-
stroke-width="1.5" stroke="currentColor" class="w-4 h-4">
|
|
136
|
-
<path stroke-linecap="round" stroke-linejoin="round" d="M17.982 18.725A7.488 7.488
|
|
137
|
-
0 0 0 12 15.75a7.488 7.488 0 0 0-5.982 2.975m11.963 0a9 9 0 1 0-11.963 0m11.963
|
|
138
|
-
0A8.966 8.966 0 0 1 12 21a8.966 8.966 0 0 1-5.982-2.275M15 9.75a3
|
|
139
|
-
3 0 1 1-6 0 3 3 0 0 1 6 0Z" />
|
|
140
|
-
</svg>
|
|
141
|
-
<input class="input input-xs" type="text" value={sockdrives[num]?.owner ?? ""}
|
|
142
|
-
onChange={(e) => {
|
|
143
|
-
const newSockdrives = { ...sockdrives };
|
|
144
|
-
newSockdrives[num] = {
|
|
145
|
-
num,
|
|
146
|
-
backend: sockdrives[num]?.backend ?? sockdriveWssEndpoint,
|
|
147
|
-
owner: e.currentTarget.value,
|
|
148
|
-
drive: sockdrives[num]?.drive ?? "",
|
|
149
|
-
};
|
|
150
|
-
setSockdrivesAndUpdateConf(newSockdrives);
|
|
151
|
-
}}></input>
|
|
152
|
-
</div>
|
|
153
|
-
<div class="flex flex-row gap-1 items-center">
|
|
154
|
-
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24"
|
|
155
|
-
stroke-width="1.5" stroke="currentColor" class="w-4 h-4">
|
|
156
|
-
<path stroke-linecap="round" stroke-linejoin="round" d="M20.25 6.375c0 2.278-3.694
|
|
157
|
-
4.125-8.25 4.125S3.75 8.653 3.75 6.375m16.5 0c0-2.278-3.694-4.125-8.25-4.125S3.75
|
|
158
|
-
4.097 3.75 6.375m16.5 0v11.25c0 2.278-3.694 4.125-8.25
|
|
159
|
-
4.125s-8.25-1.847-8.25-4.125V6.375m16.5 0v3.75m-16.5-3.75v3.75m16.5
|
|
160
|
-
0v3.75C20.25 16.153
|
|
161
|
-
16.556 18 12 18s-8.25-1.847-8.25-4.125v-3.75m16.5 0c0 2.278-3.694 4.125-8.25
|
|
162
|
-
4.125s-8.25-1.847-8.25-4.125" />
|
|
163
|
-
</svg>
|
|
164
|
-
|
|
165
|
-
<input class="input input-xs" type="text" value={sockdrives[num]?.drive ?? ""}
|
|
166
|
-
onChange={(e) => {
|
|
167
|
-
const newSockdrives = { ...sockdrives };
|
|
168
|
-
newSockdrives[num] = {
|
|
169
|
-
num,
|
|
170
|
-
backend: sockdrives[num]?.backend ?? sockdriveWssEndpoint,
|
|
171
|
-
owner: sockdrives[num]?.owner ?? "",
|
|
172
|
-
drive: e.currentTarget.value,
|
|
173
|
-
};
|
|
174
|
-
setSockdrivesAndUpdateConf(newSockdrives);
|
|
175
|
-
}}></input>
|
|
176
|
-
</div>
|
|
177
|
-
</div>
|
|
178
|
-
<div class="dropdown dropdown-bottom dropdown-end">
|
|
179
|
-
<button tabIndex={0} role="button" class="btn btn-sm">
|
|
180
|
-
<svg xmlns="http://www.w3.org/2000/svg" fill="none"
|
|
181
|
-
viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" class="w-4 h-4">
|
|
182
|
-
<path stroke-linecap="round" stroke-linejoin="round"
|
|
183
|
-
d="M3.75 9.776c.112-.017.227-.026.344-.026h15.812c.117 0 .232.009.344.026m-16.5
|
|
184
|
-
0a2.25 2.25 0 0 0-1.883 2.542l.857 6a2.25 2.25 0 0 0 2.227 1.932H19.05a2.25
|
|
185
|
-
2.25 0 0 0 2.227-1.932l.857-6a2.25 2.25 0 0 0-1.883-2.542m-16.5 0V6A2.25 2.25
|
|
186
|
-
0 0 1 6 3.75h3.879a1.5 1.5 0 0 1 1.06.44l2.122 2.12a1.5 1.5 0 0 0
|
|
187
|
-
1.06.44H18A2.25 2.25 0 0 1 20.25 9v.776" />
|
|
188
|
-
</svg>
|
|
189
|
-
</button>
|
|
190
|
-
<ul tabIndex={0} class="dropdown-content z-[1] menu p-2 shadow bg-base-100
|
|
191
|
-
rounded-box w-52 max-h-80 overflow-auto">
|
|
192
|
-
{myDrives.map(({ name, owner }) => {
|
|
193
|
-
return <li onClick={(e) => {
|
|
194
|
-
const newSockdrives = { ...sockdrives };
|
|
195
|
-
newSockdrives[num] = {
|
|
196
|
-
num,
|
|
197
|
-
owner,
|
|
198
|
-
backend: sockdriveWssEndpoint,
|
|
199
|
-
drive: name,
|
|
200
|
-
};
|
|
201
|
-
setSockdrivesAndUpdateConf(newSockdrives);
|
|
202
|
-
e.currentTarget.parentElement!.blur();
|
|
203
|
-
}}><a>{name}</a></li>;
|
|
204
|
-
})}
|
|
205
|
-
</ul>
|
|
206
|
-
</div>
|
|
207
|
-
<button class="btn btn-sm" onClick={() => {
|
|
208
|
-
const newSockdrives = { ...sockdrives };
|
|
209
|
-
delete newSockdrives[num];
|
|
210
|
-
setSockdrivesAndUpdateConf(newSockdrives);
|
|
211
|
-
}}>
|
|
212
|
-
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5"
|
|
213
|
-
stroke="currentColor" class="w-4 h-4">
|
|
214
|
-
<path stroke-linecap="round" stroke-linejoin="round"
|
|
215
|
-
d="M12 9.75 14.25 12m0 0 2.25 2.25M14.25 12l2.25-2.25M14.25 12 12 14.25m-2.58
|
|
216
|
-
4.92-6.374-6.375a1.125 1.125 0 0 1 0-1.59L9.42 4.83c.21-.211.497-.33.795-.33H19.5a2.25
|
|
217
|
-
2.25 0 0 1 2.25 2.25v10.5a2.25 2.25 0 0 1-2.25 2.25h-9.284c-.298 0-.585-.119-.795-.33Z"
|
|
218
|
-
/>
|
|
219
|
-
</svg>
|
|
220
|
-
</button>
|
|
221
|
-
</div>;
|
|
222
|
-
})}
|
|
223
|
-
</>}
|
|
224
|
-
<textarea class="flex-grow" value={bundleConfig.dosboxConf}
|
|
225
|
-
onChange={(e) => changeConfig(e.currentTarget?.value ?? "")} />
|
|
226
|
-
</div>;
|
|
227
|
-
}
|
|
@@ -1,55 +0,0 @@
|
|
|
1
|
-
.jsdos-rso {
|
|
2
|
-
.editor-conf-frame {
|
|
3
|
-
@apply w-full overflow-hidden flex-grow flex flex-col items-start justify-center h-full px-4;
|
|
4
|
-
|
|
5
|
-
textarea {
|
|
6
|
-
@apply w-full textarea;
|
|
7
|
-
resize: none;
|
|
8
|
-
}
|
|
9
|
-
}
|
|
10
|
-
|
|
11
|
-
.editor-fs-frame {
|
|
12
|
-
@apply h-full;
|
|
13
|
-
|
|
14
|
-
.fs-tree-view {
|
|
15
|
-
@apply form-control bg-base-100 rounded w-full h-full;
|
|
16
|
-
|
|
17
|
-
.fs-tree {
|
|
18
|
-
|
|
19
|
-
ol {
|
|
20
|
-
@apply ml-2;
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
li {
|
|
24
|
-
@apply my-2;
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
button {
|
|
28
|
-
border: none;
|
|
29
|
-
background: none;
|
|
30
|
-
filter: none;
|
|
31
|
-
min-height: auto;
|
|
32
|
-
height: auto;
|
|
33
|
-
@apply m-0 p-0;
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
svg {
|
|
37
|
-
@apply text-accent;
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
input {
|
|
41
|
-
@apply checkbox checkbox-accent mr-2 w-4 h-4;
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
.rct-text,
|
|
45
|
-
.rct-bare-label,
|
|
46
|
-
label {
|
|
47
|
-
display: flex;
|
|
48
|
-
flex-direction: row;
|
|
49
|
-
justify-content: start;
|
|
50
|
-
align-items: center;
|
|
51
|
-
}
|
|
52
|
-
}
|
|
53
|
-
}
|
|
54
|
-
}
|
|
55
|
-
}
|
|
@@ -1,314 +0,0 @@
|
|
|
1
|
-
import { FsNode } from "emulators/dist/types/protocol/protocol";
|
|
2
|
-
import { useEffect, useRef, useState } from "preact/hooks";
|
|
3
|
-
import CheckboxTree, { Node, OnCheckNode, OnExpandNode } from "react-checkbox-tree";
|
|
4
|
-
import { useSelector, useStore } from "react-redux";
|
|
5
|
-
import { useT } from "../../i18n";
|
|
6
|
-
import { loadBundle } from "../../load";
|
|
7
|
-
import { State, useNonSerializableStore } from "../../store";
|
|
8
|
-
import { downloadArrayToFs } from "../../download-file";
|
|
9
|
-
|
|
10
|
-
interface NodeExt extends Node {
|
|
11
|
-
fsNode: FsNode,
|
|
12
|
-
}
|
|
13
|
-
|
|
14
|
-
export function EditorFsFrame() {
|
|
15
|
-
const t = useT();
|
|
16
|
-
const haveCi = useSelector((state: State) => state.dos.ci);
|
|
17
|
-
const nonSerializableStore = useNonSerializableStore();
|
|
18
|
-
const [fsSize, setFsSize] = useState<number>(0);
|
|
19
|
-
const [fsTree, _setFsTree] = useState<NodeExt[] | null>(null);
|
|
20
|
-
const [expanded, setExpanded] = useState<string[]>([]);
|
|
21
|
-
const [checked, setChecked] = useState<string[]>([]);
|
|
22
|
-
const [uploadingFile, setUploadingFile] = useState<string | null>(null);
|
|
23
|
-
const [makingBundle, setMakingBundle] = useState<boolean>(false);
|
|
24
|
-
|
|
25
|
-
function setFsTree(fsTree: NodeExt[] | null) {
|
|
26
|
-
_setFsTree(fsTree);
|
|
27
|
-
setFsSize(Math.round(calcFsSize(fsTree) / 1024 / 1024 * 100) / 100);
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
useEffect(() => {
|
|
31
|
-
if (nonSerializableStore.ci === null || !haveCi) {
|
|
32
|
-
return;
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
let cancled = false;
|
|
36
|
-
nonSerializableStore.ci.fsTree()
|
|
37
|
-
.then((tree) => {
|
|
38
|
-
if (!cancled) {
|
|
39
|
-
setFsTree(toNodes(tree));
|
|
40
|
-
}
|
|
41
|
-
})
|
|
42
|
-
.catch((e) => {
|
|
43
|
-
console.error(e);
|
|
44
|
-
if (!cancled) {
|
|
45
|
-
setFsTree(null);
|
|
46
|
-
}
|
|
47
|
-
});
|
|
48
|
-
|
|
49
|
-
return () => {
|
|
50
|
-
cancled = true;
|
|
51
|
-
};
|
|
52
|
-
}, [haveCi]);
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
function onExpand(expanded: Array<string>, node: OnExpandNode) {
|
|
56
|
-
setExpanded(expanded);
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
function onCheck(checked: Array<string>, node: OnCheckNode) {
|
|
60
|
-
setChecked(checked);
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
async function onRefresh() {
|
|
64
|
-
setFsTree(null);
|
|
65
|
-
if (nonSerializableStore.ci === null || !haveCi) {
|
|
66
|
-
return;
|
|
67
|
-
}
|
|
68
|
-
const tree = await nonSerializableStore.ci.fsTree();
|
|
69
|
-
setFsTree(toNodes(tree));
|
|
70
|
-
}
|
|
71
|
-
|
|
72
|
-
// const check = <input type="checkbox" class="checkbox" />;
|
|
73
|
-
return <div class="editor-fs-frame frame-root items-start px-4">
|
|
74
|
-
{(makingBundle || uploadingFile !== null) &&
|
|
75
|
-
<div class="card card-bordered bg-base-100 shadow-xl w-full">
|
|
76
|
-
<div class="card-body">
|
|
77
|
-
<div class="card-title">
|
|
78
|
-
{t(makingBundle ? "please_wait" : "uploading_file")}
|
|
79
|
-
</div>
|
|
80
|
-
<span class="break-words">
|
|
81
|
-
{makingBundle ? t("making_bundle") : uploadingFile}
|
|
82
|
-
</span>
|
|
83
|
-
</div>
|
|
84
|
-
</div>}
|
|
85
|
-
{!makingBundle && uploadingFile === null && fsTree &&
|
|
86
|
-
<div className="fs-tree-view">
|
|
87
|
-
<Actions
|
|
88
|
-
onRefresh={onRefresh}
|
|
89
|
-
onUploadingFile={setUploadingFile}
|
|
90
|
-
onMakingBundle={setMakingBundle} />
|
|
91
|
-
<div class="bg-base-200 px-2 py-1 text-right">
|
|
92
|
-
{t("size")}: {fsSize} Mb
|
|
93
|
-
</div>
|
|
94
|
-
<div class="fs-tree">
|
|
95
|
-
<CheckboxTree
|
|
96
|
-
icons={{
|
|
97
|
-
expandOpen: <FolderOpened /> as any,
|
|
98
|
-
expandClose: <FolderClosed /> as any,
|
|
99
|
-
// expandAll: <div class="bg-red-100 w-4 h-4"></div> as any,
|
|
100
|
-
// parentOpen: <div class="bg-blue-100 w-4 h-4"></div> as any,
|
|
101
|
-
// parentClose: <div class="bg-purple-100 w-4 h-4"></div> as any,
|
|
102
|
-
}}
|
|
103
|
-
iconsClass="icon"
|
|
104
|
-
nativeCheckboxes={false}
|
|
105
|
-
onlyLeafCheckboxes={true}
|
|
106
|
-
nodes={fsTree}
|
|
107
|
-
checked={checked}
|
|
108
|
-
onCheck={onCheck}
|
|
109
|
-
expanded={expanded}
|
|
110
|
-
onExpand={onExpand} />
|
|
111
|
-
</div>
|
|
112
|
-
</div>}
|
|
113
|
-
</div>;
|
|
114
|
-
}
|
|
115
|
-
|
|
116
|
-
function toNodes(fsTree: FsNode): NodeExt[] {
|
|
117
|
-
const fs: NodeExt[] = [];
|
|
118
|
-
for (const next of (fsTree.nodes?.sort(nodeSorter) || [])) {
|
|
119
|
-
fs.push(toNode(next, "."));
|
|
120
|
-
}
|
|
121
|
-
return fs;
|
|
122
|
-
}
|
|
123
|
-
|
|
124
|
-
function toNode(fsNode: FsNode, path: string): NodeExt {
|
|
125
|
-
const fullPath = path + "/" + fsNode.name;
|
|
126
|
-
const nodeExt: NodeExt = {
|
|
127
|
-
label: fsNode.name,
|
|
128
|
-
value: fullPath,
|
|
129
|
-
fsNode,
|
|
130
|
-
};
|
|
131
|
-
|
|
132
|
-
if (fsNode.nodes !== null) {
|
|
133
|
-
const children = fsNode.nodes.sort(nodeSorter)
|
|
134
|
-
.map((next) => toNode(next, fullPath));
|
|
135
|
-
nodeExt.children = children;
|
|
136
|
-
}
|
|
137
|
-
|
|
138
|
-
return nodeExt;
|
|
139
|
-
}
|
|
140
|
-
|
|
141
|
-
function Actions(props: {
|
|
142
|
-
onRefresh: () => void,
|
|
143
|
-
onUploadingFile: (file: string | null) => void,
|
|
144
|
-
onMakingBundle: (making: boolean) => void,
|
|
145
|
-
}) {
|
|
146
|
-
const t = useT();
|
|
147
|
-
const uploadDirRef = useRef<HTMLInputElement>(null);
|
|
148
|
-
const uploadFileRef = useRef<HTMLInputElement>(null);
|
|
149
|
-
const store = useStore();
|
|
150
|
-
const nonSerializableStore = useNonSerializableStore();
|
|
151
|
-
const { onRefresh, onUploadingFile, onMakingBundle } = props;
|
|
152
|
-
|
|
153
|
-
useEffect(() => {
|
|
154
|
-
if (uploadDirRef.current !== null) {
|
|
155
|
-
uploadDirRef.current.setAttribute("directory", "");
|
|
156
|
-
uploadDirRef.current.setAttribute("webkitdirectory", "");
|
|
157
|
-
}
|
|
158
|
-
}, [uploadDirRef]);
|
|
159
|
-
|
|
160
|
-
function onUploadClick(file: boolean) {
|
|
161
|
-
const input = (file ? uploadFileRef : uploadDirRef).current;
|
|
162
|
-
if (input === null) {
|
|
163
|
-
return;
|
|
164
|
-
}
|
|
165
|
-
|
|
166
|
-
input.click();
|
|
167
|
-
}
|
|
168
|
-
|
|
169
|
-
async function onUpload(event: any) {
|
|
170
|
-
const ci = nonSerializableStore.ci;
|
|
171
|
-
const files: FileList = event.target.files;
|
|
172
|
-
if (ci === null || files === null) {
|
|
173
|
-
return;
|
|
174
|
-
}
|
|
175
|
-
|
|
176
|
-
try {
|
|
177
|
-
for (const file of files) {
|
|
178
|
-
onUploadingFile(file.name);
|
|
179
|
-
const parts = (file.webkitRelativePath ?? "").split("/");
|
|
180
|
-
parts.shift();
|
|
181
|
-
const relPath = parts.join("/");
|
|
182
|
-
await ci.fsWriteFile(relPath.length == 0 ? file.name : relPath, file.stream());
|
|
183
|
-
}
|
|
184
|
-
} finally {
|
|
185
|
-
onUploadingFile(null);
|
|
186
|
-
}
|
|
187
|
-
|
|
188
|
-
await onRefresh();
|
|
189
|
-
}
|
|
190
|
-
|
|
191
|
-
async function onRestart() {
|
|
192
|
-
const ci = nonSerializableStore.ci;
|
|
193
|
-
if (ci === null || !window.confirm(t("fs_restart"))) {
|
|
194
|
-
return;
|
|
195
|
-
}
|
|
196
|
-
|
|
197
|
-
onMakingBundle(true);
|
|
198
|
-
try {
|
|
199
|
-
const bundle = await ci.persist(false);
|
|
200
|
-
if (bundle) {
|
|
201
|
-
loadBundle(bundle, true, store);
|
|
202
|
-
}
|
|
203
|
-
} finally {
|
|
204
|
-
onMakingBundle(false);
|
|
205
|
-
}
|
|
206
|
-
}
|
|
207
|
-
|
|
208
|
-
async function onDownload() {
|
|
209
|
-
const ci = nonSerializableStore.ci;
|
|
210
|
-
if (ci === null) {
|
|
211
|
-
return;
|
|
212
|
-
}
|
|
213
|
-
|
|
214
|
-
onMakingBundle(true);
|
|
215
|
-
try {
|
|
216
|
-
const bundle = await ci.persist(false);
|
|
217
|
-
if (bundle) {
|
|
218
|
-
downloadArrayToFs("bundle.jsdos", bundle);
|
|
219
|
-
}
|
|
220
|
-
} finally {
|
|
221
|
-
onMakingBundle(false);
|
|
222
|
-
}
|
|
223
|
-
}
|
|
224
|
-
|
|
225
|
-
return <div class="h-6 flex flex-row">
|
|
226
|
-
<input class="hidden" type="file" multiple ref={uploadDirRef} onChange={onUpload} />
|
|
227
|
-
<input class="hidden" type="file" multiple ref={uploadFileRef} onChange={onUpload} />
|
|
228
|
-
<button class="refresh btn-xs rounded-none" onClick={onRefresh}>
|
|
229
|
-
<svg xmlns="http://www.w3.org/2000/svg" fill="none"
|
|
230
|
-
viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" class="w-4 h-4">
|
|
231
|
-
<path stroke-linecap="round" stroke-linejoin="round"
|
|
232
|
-
d="M16.023 9.348h4.992v-.001M2.985 19.644v-4.992m0 0h4.992m-4.993 0l3.181
|
|
233
|
-
3.183a8.25 8.25 0 0013.803-3.7M4.031 9.865a8.25 8.25 0 0113.803-3.7l3.181
|
|
234
|
-
3.182m0-4.991v4.99" />
|
|
235
|
-
</svg>
|
|
236
|
-
</button>
|
|
237
|
-
<button class="add-file btn-xs rounded-none" onClick={() => onUploadClick(true)}>
|
|
238
|
-
<svg xmlns="http://www.w3.org/2000/svg" fill="none"
|
|
239
|
-
viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" class="w-4 h-4">
|
|
240
|
-
<path stroke-linecap="round" stroke-linejoin="round" d="M19.5 14.25v-2.625a3.375
|
|
241
|
-
3.375 0 00-3.375-3.375h-1.5A1.125 1.125 0 0113.5 7.125v-1.5a3.375 3.375 0
|
|
242
|
-
00-3.375-3.375H8.25m3.75 9v6m3-3H9m1.5-12H5.625c-.621 0-1.125.504-1.125
|
|
243
|
-
1.125v17.25c0 .621.504 1.125 1.125 1.125h12.75c.621 0 1.125-.504 1.125-1.125V11.25a9
|
|
244
|
-
9 0 00-9-9z" />
|
|
245
|
-
</svg>
|
|
246
|
-
</button>
|
|
247
|
-
<button class="add-dir btn-xs rounded-none" onClick={() => onUploadClick(false)}>
|
|
248
|
-
<svg xmlns="http://www.w3.org/2000/svg" fill="none"
|
|
249
|
-
viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" class="w-4 h-4">
|
|
250
|
-
<path stroke-linecap="round" stroke-linejoin="round"
|
|
251
|
-
d="M12 10.5v6m3-3H9m4.06-7.19l-2.12-2.12a1.5 1.5 0 00-1.061-.44H4.5A2.25
|
|
252
|
-
2.25 0 002.25 6v12a2.25 2.25 0 002.25 2.25h15A2.25 2.25 0 0021.75
|
|
253
|
-
18V9a2.25 2.25 0 00-2.25-2.25h-5.379a1.5 1.5 0 01-1.06-.44z" />
|
|
254
|
-
</svg>
|
|
255
|
-
</button>
|
|
256
|
-
<div class="flex-grow"></div>
|
|
257
|
-
<button class="download btn-xs rounded-none" onClick={onDownload}>
|
|
258
|
-
<svg xmlns="http://www.w3.org/2000/svg" fill="none"
|
|
259
|
-
viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" class="w-4 h-4">
|
|
260
|
-
<path stroke-linecap="round" stroke-linejoin="round" d="M9 13.5l3 3m0 0l3-3m-3
|
|
261
|
-
3v-6m1.06-4.19l-2.12-2.12a1.5 1.5 0 00-1.061-.44H4.5A2.25 2.25 0 002.25 6v12a2.25 2.25
|
|
262
|
-
0 002.25 2.25h15A2.25 2.25 0 0021.75 18V9a2.25 2.25 0 00-2.25-2.25h-5.379a1.5 1.5
|
|
263
|
-
0 01-1.06-.44z" />
|
|
264
|
-
</svg>
|
|
265
|
-
</button>
|
|
266
|
-
<button class="restart btn-xs rounded-none" onClick={onRestart}>
|
|
267
|
-
<svg xmlns="http://www.w3.org/2000/svg" fill="none"
|
|
268
|
-
viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" class="w-4 h-4">
|
|
269
|
-
<path stroke-linecap="round" stroke-linejoin="round" d="M21 7.5V18M15 7.5V18M3
|
|
270
|
-
16.811V8.69c0-.864.933-1.406 1.683-.977l7.108 4.061a1.125 1.125 0 010 1.954l-7.108
|
|
271
|
-
4.061A1.125 1.125 0 013 16.811z" />
|
|
272
|
-
</svg>
|
|
273
|
-
</button>
|
|
274
|
-
</div>;
|
|
275
|
-
}
|
|
276
|
-
|
|
277
|
-
function nodeSorter(a: FsNode, b: FsNode) {
|
|
278
|
-
if (a.nodes !== null && b.nodes !== null) {
|
|
279
|
-
return b.name.localeCompare(a.name);
|
|
280
|
-
}
|
|
281
|
-
|
|
282
|
-
return a.nodes === null ? 1 : -1;
|
|
283
|
-
}
|
|
284
|
-
|
|
285
|
-
function FolderOpened() {
|
|
286
|
-
return <svg xmlns="http://www.w3.org/2000/svg" fill="none"
|
|
287
|
-
viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" class="w-4 h-4 mr-2">
|
|
288
|
-
<path stroke-linecap="round" stroke-linejoin="round" d="M19.5 8.25l-7.5 7.5-7.5-7.5" />
|
|
289
|
-
</svg>;
|
|
290
|
-
}
|
|
291
|
-
|
|
292
|
-
function FolderClosed() {
|
|
293
|
-
return <svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24"
|
|
294
|
-
stroke-width="1.5" stroke="currentColor" class="w-4 h-4 mr-2">
|
|
295
|
-
<path stroke-linecap="round" stroke-linejoin="round" d="M8.25 4.5l7.5 7.5-7.5 7.5" />
|
|
296
|
-
</svg>;
|
|
297
|
-
}
|
|
298
|
-
|
|
299
|
-
function calcFsSize(fsTree: NodeExt[] | null) {
|
|
300
|
-
if (!fsTree) {
|
|
301
|
-
return 0;
|
|
302
|
-
}
|
|
303
|
-
|
|
304
|
-
let size = 0;
|
|
305
|
-
for (const next of fsTree) {
|
|
306
|
-
if (next.fsNode.size !== null) {
|
|
307
|
-
size += next.fsNode.size!;
|
|
308
|
-
} else {
|
|
309
|
-
size += calcFsSize(next.children as NodeExt[]);
|
|
310
|
-
}
|
|
311
|
-
}
|
|
312
|
-
|
|
313
|
-
return size;
|
|
314
|
-
}
|