Skip to content

Commit 83d69eb

Browse files
committed
import and export zipped projects
1 parent a903b9b commit 83d69eb

5 files changed

Lines changed: 96 additions & 5 deletions

File tree

src/webpage/index.ts

Lines changed: 64 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,9 @@ import {instructions} from "./fetches.js";
77
import {I18n} from "./i18n.js";
88
import {Project} from "./projects/project.js";
99
import {ProjFiles} from "./projects/projectFiles.js";
10+
import {getUserUpload} from "./utils/utils.js";
1011
import "./ziputils/zip.js";
12+
import {CentDir, Zip} from "./ziputils/zip.js";
1113
const actionRow = document.getElementById("actionRow");
1214
if (!actionRow) throw Error("action row not in document");
1315
const cons = new Console();
@@ -32,12 +34,14 @@ fileMenu.addButton(
3234
focusedEditor.save();
3335
},
3436
);
37+
3538
fileMenu.addButton(
3639
() => I18n.file.saveAll(),
3740
() => {
3841
editors.map((_) => _.save());
3942
},
4043
);
44+
4145
fileMenu.addButton(
4246
() => I18n.file.saveAs(),
4347
() => {
@@ -80,6 +84,57 @@ fileButton.textContent = I18n.file.file();
8084
actionRow.append(fileButton);
8185
fileMenu.bindContextmenu(fileButton, undefined, undefined, true);
8286

87+
const projectMenu = new Contextmenu("Project");
88+
projectMenu.addButton(
89+
() => I18n.file.download(),
90+
() => {
91+
projFile?.pro.downloadProject();
92+
},
93+
{
94+
visable: () => !!projFile,
95+
},
96+
);
97+
projectMenu.addButton(
98+
() => I18n.file.deleteProject(),
99+
async () => {
100+
if (curProject) {
101+
if (!confirm(I18n.confirmDeleteProject(curProject.name))) {
102+
return;
103+
}
104+
105+
await curProject.deleteProject();
106+
openProject(undefined);
107+
}
108+
},
109+
{
110+
visable: () => !!projFile,
111+
},
112+
);
113+
projectMenu.addButton(
114+
() => I18n.file.import(),
115+
async () => {
116+
const user = await getUserUpload("application/zip");
117+
if (!user) return;
118+
const zip = new Zip(await user.arrayBuffer());
119+
let fs = zip.fileStructure;
120+
let entries = Object.entries(fs);
121+
let name = user.name.split(".")[0];
122+
while (entries.length === 1 && !(entries[0][1] instanceof CentDir)) {
123+
fs = entries[0][1];
124+
name = entries[0][0];
125+
entries = Object.entries(fs);
126+
}
127+
const project = await Project.new(name);
128+
await zip.writeIntoDir(project.dir.handle, fs);
129+
openProject(project);
130+
},
131+
);
132+
133+
const projectButton = document.createElement("button");
134+
projectButton.textContent = I18n.file.project();
135+
actionRow.append(projectButton);
136+
projectMenu.bindContextmenu(projectButton, undefined, undefined, true);
137+
83138
const menu = new Contextmenu("run");
84139

85140
const assemble = document.getElementById("assemble") as HTMLElement;
@@ -656,8 +711,16 @@ function downloadEditor(editor: Editor) {
656711
}
657712
let curProject: Project | undefined;
658713
let projFile: ProjFiles | undefined;
659-
async function openProject(proj: Project) {
714+
async function openProject(proj?: Project) {
715+
if (!proj) {
716+
curProject = undefined;
717+
projFile = undefined;
718+
editors = [];
719+
editArea();
720+
return;
721+
}
660722
curProject = proj;
723+
661724
projFile = new ProjFiles(proj);
662725
projFile.addEventListener("open", async (e) => {
663726
const editor = Editor.editMap.get(`${proj.name}:${e.fileName}`);

src/webpage/projects/project.ts

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
1-
import {Directory} from "../utils/utils.js";
1+
import {Directory, downloadBuffer} from "../utils/utils.js";
2+
import {Zip} from "../ziputils/zip.js";
23

34
class Project {
45
name: string;
@@ -117,5 +118,13 @@ main:
117118
console.error("internal error, please fix me sometime :P");
118119
}
119120
}
121+
async deleteProject() {
122+
const home = await Directory.home;
123+
await home.handle.removeEntry(this.name, {recursive: true});
124+
}
125+
async downloadProject() {
126+
const buff = await Zip.zip(this.dir.handle);
127+
downloadBuffer(buff, this.name + ".zip");
128+
}
120129
}
121130
export {Project};

src/webpage/utils/utils.ts

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,20 @@ class Directory {
7878
return new Directory(await this.handle.getDirectoryHandle(name, {create: true}));
7979
}
8080
}
81+
export function getUserUpload(mimeType = "") {
82+
return new Promise<null | File>((res) => {
83+
const input = document.createElement("input");
84+
input.type = "file";
85+
input.accept = mimeType;
86+
input.multiple = false;
87+
input.onchange = () => {
88+
if (input.files) {
89+
res(input.files.item(0));
90+
}
91+
};
92+
input.click();
93+
});
94+
}
8195
export function downloadBuffer(buff: ArrayBuffer, name: string) {
8296
const blob = new Blob([buff], {type: "text/plain"});
8397
const objectURL = URL.createObjectURL(blob);

src/webpage/ziputils/zip.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
import {I18n} from "../i18n";
2-
import {downloadBuffer} from "../utils/utils";
32

43
const enum compMethod {
54
none = 0,
@@ -107,7 +106,7 @@ function guessText(buff: Uint8Array) {
107106
const newBuff = new Uint8Array([...buff]);
108107
return new TextDecoder().decode(newBuff.buffer) || "";
109108
}
110-
class CentDir {
109+
export class CentDir {
111110
verMade: number;
112111
verExt: number;
113112
flags: number;
@@ -371,6 +370,7 @@ export class Zip {
371370
});
372371
const write = await fileH.createWritable({keepExistingData: false});
373372
write.write(await file.file.getFile());
373+
await write.close();
374374
} else {
375375
const dirH = await dir.getDirectoryHandle(name, {
376376
create: true,

translations/en.json

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -98,6 +98,7 @@
9898
"startProject": "Start a new project",
9999
"openFile": "Open a file!",
100100
"confirmDelete": "Are you sure you want to delete $1?",
101+
"confirmDeleteProject":"Are you sure you want to delete $1? (this deletes all files in the project)",
101102
"memPlaces":{
102103
"data":"$1 (.data)",
103104
"text":"$1 (.text)",
@@ -120,12 +121,16 @@
120121
"unsaved": "There are unsaved changes, are you sure you want to close this file?",
121122
"file": {
122123
"file": "File",
124+
"project":"Project",
123125
"open": "Open",
124126
"new": "New",
125127
"save": "Save file",
126128
"saveAs": "Save file as",
127129
"saveAll": "Save All",
128-
"delete": "Delete File"
130+
"delete": "Delete File",
131+
"download":"Download Project",
132+
"deleteProject":"Delete Project",
133+
"import":"Import Project"
129134
},
130135
"submit": "Submit",
131136
"instructions":{

0 commit comments

Comments
 (0)