Spaces:
Running
Running
Update src/containers/sb3-downloader.jsx
Browse files
src/containers/sb3-downloader.jsx
CHANGED
@@ -69,7 +69,8 @@ class SB3Downloader extends React.Component {
|
|
69 |
'downloadProject',
|
70 |
'saveAsNew',
|
71 |
'saveToLastFile',
|
72 |
-
'saveToLastFileOrNew'
|
|
|
73 |
]);
|
74 |
}
|
75 |
startedSaving () {
|
@@ -108,6 +109,26 @@ class SB3Downloader extends React.Component {
|
|
108 |
this.handleSaveError(e);
|
109 |
}
|
110 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
111 |
async saveToLastFile () {
|
112 |
try {
|
113 |
await this.saveToHandle(this.props.fileHandle);
|
@@ -226,6 +247,30 @@ class SB3Downloader extends React.Component {
|
|
226 |
});
|
227 |
});
|
228 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
229 |
handleSaveError (e) {
|
230 |
// AbortError can happen when someone cancels the file selector dialog
|
231 |
if (e && e.name === 'AbortError') {
|
|
|
69 |
'downloadProject',
|
70 |
'saveAsNew',
|
71 |
'saveToLastFile',
|
72 |
+
'saveToLastFileOrNew',
|
73 |
+
'saveAsFolder'
|
74 |
]);
|
75 |
}
|
76 |
startedSaving () {
|
|
|
109 |
this.handleSaveError(e);
|
110 |
}
|
111 |
}
|
112 |
+
async saveAsFolder() {
|
113 |
+
if (!this.props.canSaveProject) {
|
114 |
+
return;
|
115 |
+
}
|
116 |
+
try {
|
117 |
+
const handle = await FileSystemAPI.showDirectoryPicker("pm-project-folder", "documents");
|
118 |
+
|
119 |
+
this.startedSaving();
|
120 |
+
const jsZip = this.props.saveProjectZip();
|
121 |
+
this.extractJSZipToHandle(jsZip, handle);
|
122 |
+
this.finishedSaving();
|
123 |
+
|
124 |
+
const title = handle.name;
|
125 |
+
if (title) {
|
126 |
+
this.props.onSetProjectTitle(title);
|
127 |
+
}
|
128 |
+
} catch (e) {
|
129 |
+
this.handleSaveError(e);
|
130 |
+
}
|
131 |
+
}
|
132 |
async saveToLastFile () {
|
133 |
try {
|
134 |
await this.saveToHandle(this.props.fileHandle);
|
|
|
247 |
});
|
248 |
});
|
249 |
}
|
250 |
+
async extractJSZipToHandle (zip, handle) {
|
251 |
+
// Not sure how memory management works but im hoping this is fine
|
252 |
+
for (const [relativePath, zipEntry] of Object.entries(zip.files)) {
|
253 |
+
// files will be able to make directories
|
254 |
+
if (zipEntry.dir) continue;
|
255 |
+
|
256 |
+
const pathParts = relativePath.split("/");
|
257 |
+
const fileName = pathParts.pop();
|
258 |
+
|
259 |
+
// NOTE: Right now there's no reason to preserve directories, but the future save file format will use them.
|
260 |
+
// See here for more info: https://docs.penguinmod.com/save-format/
|
261 |
+
// make a directory for each file within one
|
262 |
+
let currentDir = handle;
|
263 |
+
for (const part of pathParts) {
|
264 |
+
currentDir = await currentDir.getDirectoryHandle(part, { create: true });
|
265 |
+
}
|
266 |
+
|
267 |
+
const fileHandle = await currentDir.getFileHandle(fileName, { create: true });
|
268 |
+
const writable = await fileHandle.createWritable();
|
269 |
+
const content = await zipEntry.async("arraybuffer");
|
270 |
+
await writable.write(content);
|
271 |
+
await writable.close();
|
272 |
+
}
|
273 |
+
}
|
274 |
handleSaveError (e) {
|
275 |
// AbortError can happen when someone cancels the file selector dialog
|
276 |
if (e && e.name === 'AbortError') {
|