js-dos 8.1.4 → 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.
Files changed (141) hide show
  1. package/README.md +1 -1
  2. package/dist/emulators/emulators.js +2 -0
  3. package/dist/emulators/emulators.js.map +1 -0
  4. package/dist/emulators/types/build.d.ts +28 -0
  5. package/dist/emulators/types/dos/bundle/dos-bundle.d.ts +20 -0
  6. package/dist/emulators/types/dos/dosbox/ts/direct.d.ts +3 -0
  7. package/dist/emulators/types/dos/dosbox/ts/worker.d.ts +3 -0
  8. package/dist/emulators/types/emulators.d.ts +76 -0
  9. package/dist/emulators/types/http.d.ts +9 -0
  10. package/dist/emulators/types/impl/ci-impl.d.ts +29 -0
  11. package/dist/emulators/types/impl/emulators-impl.d.ts +26 -0
  12. package/dist/emulators/types/impl/modules.d.ts +38 -0
  13. package/dist/emulators/types/libzip/libzip.d.ts +16 -0
  14. package/dist/emulators/types/protocol/messages-queue.d.ts +8 -0
  15. package/dist/emulators/types/protocol/protocol.d.ts +128 -0
  16. package/dist/emulators/wdosbox-x.js +55 -0
  17. package/dist/emulators/wdosbox-x.js.symbols +8760 -0
  18. package/dist/emulators/wdosbox-x.wasm +0 -0
  19. package/dist/emulators/wdosbox.js +55 -0
  20. package/dist/emulators/wdosbox.js.symbols +3001 -0
  21. package/dist/emulators/wdosbox.wasm +0 -0
  22. package/dist/emulators/wlibzip.js +21 -0
  23. package/dist/emulators/wlibzip.js.symbols +268 -0
  24. package/dist/emulators/wlibzip.wasm +0 -0
  25. package/dist/js-dos.css +1 -0
  26. package/dist/js-dos.js +22 -0
  27. package/dist/js-dos.js.map +1 -0
  28. package/package.json +1 -1
  29. package/release.zip +0 -0
  30. package/.eslintrc.json +0 -43
  31. package/.github/workflows/build.yml +0 -51
  32. package/.gitmodules +0 -4
  33. package/index.html +0 -110
  34. package/postcss.config.cjs +0 -8
  35. package/src/app.css +0 -14
  36. package/src/base.css +0 -10
  37. package/src/components/checkbox.tsx +0 -41
  38. package/src/components/close-button.tsx +0 -17
  39. package/src/components/components.css +0 -28
  40. package/src/components/dos-option-checkbox.tsx +0 -94
  41. package/src/components/dos-option-select.tsx +0 -108
  42. package/src/components/dos-option-slider.tsx +0 -35
  43. package/src/components/error.tsx +0 -16
  44. package/src/components/loading.tsx +0 -26
  45. package/src/components/lock.tsx +0 -10
  46. package/src/components/select.tsx +0 -33
  47. package/src/components/slider.tsx +0 -69
  48. package/src/download-file.ts +0 -18
  49. package/src/frame/account-frame.tsx +0 -156
  50. package/src/frame/editor/defaults.ts +0 -419
  51. package/src/frame/editor/editor-conf-frame.tsx +0 -227
  52. package/src/frame/editor/editor-frame.css +0 -55
  53. package/src/frame/editor/editor-fs-frame.tsx +0 -314
  54. package/src/frame/fat-drives-frame.tsx +0 -199
  55. package/src/frame/frame.css +0 -119
  56. package/src/frame/frame.tsx +0 -34
  57. package/src/frame/image-rendering-frame.tsx +0 -8
  58. package/src/frame/network-frame.tsx +0 -157
  59. package/src/frame/quick-save-frame.tsx +0 -98
  60. package/src/frame/settings-frame.tsx +0 -14
  61. package/src/frame/stats-frame.tsx +0 -87
  62. package/src/host/bundle-storage.ts +0 -91
  63. package/src/host/fullscreen.ts +0 -35
  64. package/src/host/lcache.ts +0 -203
  65. package/src/host/lstorage.ts +0 -156
  66. package/src/i18n.ts +0 -185
  67. package/src/index.css +0 -7
  68. package/src/load.ts +0 -132
  69. package/src/login/login.css +0 -9
  70. package/src/login/login.tsx +0 -77
  71. package/src/main.tsx +0 -197
  72. package/src/public/types.ts +0 -45
  73. package/src/sidebar/account-button.tsx +0 -33
  74. package/src/sidebar/cloud-save-button.tsx +0 -89
  75. package/src/sidebar/diskette-icon.tsx +0 -14
  76. package/src/sidebar/fullscreen-button.tsx +0 -44
  77. package/src/sidebar/network-button.tsx +0 -39
  78. package/src/sidebar/sidebar-button.tsx +0 -244
  79. package/src/sidebar/sidebar.css +0 -47
  80. package/src/sidebar/sidebar.tsx +0 -30
  81. package/src/sockdrive/LICENSE +0 -674
  82. package/src/sockdrive/README.md +0 -45
  83. package/src/sockdrive/include/sockdrive.h +0 -23
  84. package/src/sockdrive/js/.eslintrc.json +0 -43
  85. package/src/sockdrive/js/package.json +0 -29
  86. package/src/sockdrive/js/src/fatfs/chains.js +0 -318
  87. package/src/sockdrive/js/src/fatfs/dir.js +0 -385
  88. package/src/sockdrive/js/src/fatfs/helpers.js +0 -210
  89. package/src/sockdrive/js/src/fatfs/index.js +0 -606
  90. package/src/sockdrive/js/src/fatfs/structs.js +0 -255
  91. package/src/sockdrive/js/src/fatfs/vol.js +0 -166
  92. package/src/sockdrive/js/src/sockdrive/cache.ts +0 -56
  93. package/src/sockdrive/js/src/sockdrive/drive.ts +0 -471
  94. package/src/sockdrive/js/src/sockdrive/lru.ts +0 -221
  95. package/src/sockdrive/js/src/sockdrive/types.ts +0 -14
  96. package/src/sockdrive/js/src/sockdrive-fat.d.ts +0 -64
  97. package/src/sockdrive/js/src/sockdrive-fat.ts +0 -226
  98. package/src/sockdrive/js/src/sockdrive-native.ts +0 -100
  99. package/src/sockdrive/js/src/test/test.ts +0 -289
  100. package/src/sockdrive/js/tsconfig.json +0 -11
  101. package/src/sockdrive/js/webpack.config.js +0 -68
  102. package/src/sockdrive/js/yarn.lock +0 -1808
  103. package/src/store/auth.ts +0 -115
  104. package/src/store/dos.ts +0 -305
  105. package/src/store/editor.ts +0 -61
  106. package/src/store/init.ts +0 -48
  107. package/src/store/storage.ts +0 -32
  108. package/src/store/ui.ts +0 -191
  109. package/src/store.tsx +0 -116
  110. package/src/ui.tsx +0 -140
  111. package/src/v8/changes.ts +0 -56
  112. package/src/v8/config.ts +0 -20
  113. package/src/v8/subscriptions.ts +0 -62
  114. package/src/vite-env.d.ts +0 -5
  115. package/src/window/dos/controls/keyboard.ts +0 -32
  116. package/src/window/dos/controls/keys.ts +0 -331
  117. package/src/window/dos/controls/mouse/mount.ts +0 -99
  118. package/src/window/dos/controls/mouse/mouse-locked.ts +0 -51
  119. package/src/window/dos/controls/mouse/mouse-not-locked.ts +0 -84
  120. package/src/window/dos/controls/mouse/mouse-swipe.ts +0 -57
  121. package/src/window/dos/controls/mouse/pointer.ts +0 -85
  122. package/src/window/dos/controls/mouse.ts +0 -21
  123. package/src/window/dos/dos-dhry2.tsx +0 -191
  124. package/src/window/dos/dos-runtime.tsx +0 -216
  125. package/src/window/dos/dos-window.tsx +0 -91
  126. package/src/window/dos/render/canvas.ts +0 -65
  127. package/src/window/dos/render/resize.ts +0 -31
  128. package/src/window/dos/render/webgl.ts +0 -173
  129. package/src/window/dos/sound/audio-node.ts +0 -148
  130. package/src/window/error-window.tsx +0 -9
  131. package/src/window/loading-window.tsx +0 -54
  132. package/src/window/prerun-window.tsx +0 -121
  133. package/src/window/select-window.tsx +0 -118
  134. package/src/window/window.css +0 -78
  135. package/src/window/window.tsx +0 -49
  136. package/src/ws/ws-sockdrive.ts +0 -123
  137. package/src/ws/ws-transport-layer.ts +0 -468
  138. package/tailwind.config.cjs +0 -48
  139. package/tsconfig.json +0 -32
  140. package/tsconfig.node.json +0 -9
  141. 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
- }