@hackthedev/file-manager 1.0.0
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/FileManager.js +163 -0
- package/package.json +12 -0
package/FileManager.js
ADDED
|
@@ -0,0 +1,163 @@
|
|
|
1
|
+
class FileManager {
|
|
2
|
+
static async saveFile(content, filename) {
|
|
3
|
+
const blob = new Blob([content], {type: 'text/plain'}); // or 'application/json' if it's JSON
|
|
4
|
+
const link = document.createElement('a');
|
|
5
|
+
link.href = URL.createObjectURL(blob);
|
|
6
|
+
link.download = filename;
|
|
7
|
+
|
|
8
|
+
document.body.appendChild(link);
|
|
9
|
+
link.click();
|
|
10
|
+
document.body.removeChild(link);
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
static async pickFile(filter = "*") {
|
|
14
|
+
return new Promise((resolve) => {
|
|
15
|
+
const input = document.createElement("input");
|
|
16
|
+
input.type = "file";
|
|
17
|
+
input.accept = filter;
|
|
18
|
+
|
|
19
|
+
input.onchange = () => {
|
|
20
|
+
resolve(input.files?.[0] || null);
|
|
21
|
+
};
|
|
22
|
+
|
|
23
|
+
input.click();
|
|
24
|
+
});
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
static async readFile(callback, filter = ".txt,.json") {
|
|
28
|
+
const input = document.createElement('input');
|
|
29
|
+
input.type = 'file';
|
|
30
|
+
input.accept = filter; // optional, filters file types
|
|
31
|
+
|
|
32
|
+
input.onchange = (event) => {
|
|
33
|
+
const file = event.target.files[0];
|
|
34
|
+
if (!file) return;
|
|
35
|
+
|
|
36
|
+
const reader = new FileReader();
|
|
37
|
+
reader.onload = () => {
|
|
38
|
+
callback(reader.result);
|
|
39
|
+
};
|
|
40
|
+
reader.readAsText(file);
|
|
41
|
+
};
|
|
42
|
+
|
|
43
|
+
input.click();
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
static async fileToBase64(input) {
|
|
47
|
+
// if its already a base64 string
|
|
48
|
+
if (typeof input === "string" && input.startsWith("data:")) return input;
|
|
49
|
+
|
|
50
|
+
// if its a url
|
|
51
|
+
if (typeof input === "string") {
|
|
52
|
+
const res = await fetch(input);
|
|
53
|
+
const blob = await res.blob();
|
|
54
|
+
return await FileManager.fileToBase64(blob);
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
// if its a file or blob
|
|
58
|
+
return new Promise((resolve, reject) => {
|
|
59
|
+
const reader = new FileReader();
|
|
60
|
+
reader.onload = () => resolve(reader.result);
|
|
61
|
+
reader.onerror = reject;
|
|
62
|
+
reader.readAsDataURL(input);
|
|
63
|
+
});
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
static generateId(length) {
|
|
67
|
+
let result = '1';
|
|
68
|
+
const characters = '0123456789';
|
|
69
|
+
const charactersLength = characters.length;
|
|
70
|
+
let counter = 0;
|
|
71
|
+
while (counter < length - 1) {
|
|
72
|
+
result += characters.charAt(Math.floor(Math.random() * charactersLength));
|
|
73
|
+
counter += 1;
|
|
74
|
+
}
|
|
75
|
+
return result;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
static async srcToFile(src) {
|
|
79
|
+
if (!src || typeof src !== "string")
|
|
80
|
+
return {ok: false, error: "invalid_src"};
|
|
81
|
+
|
|
82
|
+
try {
|
|
83
|
+
const r = await fetch(src);
|
|
84
|
+
if (!r.ok)
|
|
85
|
+
return {ok: false, error: "fetch_failed", status: r.status};
|
|
86
|
+
|
|
87
|
+
const blob = await r.blob();
|
|
88
|
+
const ext = blob.type.split("/")[1] || "bin";
|
|
89
|
+
const filename = `${this.generateId(16)}.${ext}`;
|
|
90
|
+
const file = new File([blob], filename, {type: blob.type});
|
|
91
|
+
|
|
92
|
+
const res = await this.uploadFile([file]);
|
|
93
|
+
return res;
|
|
94
|
+
} catch (err) {
|
|
95
|
+
console.error("srcToFile error:", err);
|
|
96
|
+
return {ok: false, error: "srcToFile_failed"};
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
static async uploadFile(files, {
|
|
101
|
+
accountId = null,
|
|
102
|
+
accountToken = null,
|
|
103
|
+
onProgress = null,
|
|
104
|
+
params = {}
|
|
105
|
+
} = {}) {
|
|
106
|
+
const file = files[0] || files;
|
|
107
|
+
const chunkSize = 1024 * 256; // 256kb
|
|
108
|
+
const totalChunks = Math.ceil(file.size / chunkSize);
|
|
109
|
+
const fileId = crypto.randomUUID();
|
|
110
|
+
|
|
111
|
+
const filename = file.name;
|
|
112
|
+
|
|
113
|
+
let lastPercent = -1;
|
|
114
|
+
|
|
115
|
+
for (let i = 0; i < totalChunks; i++) {
|
|
116
|
+
const start = i * chunkSize;
|
|
117
|
+
const end = start + chunkSize;
|
|
118
|
+
const chunk = file.slice(start, end);
|
|
119
|
+
|
|
120
|
+
const arrayBuf = await chunk.arrayBuffer();
|
|
121
|
+
|
|
122
|
+
const search = new URLSearchParams({
|
|
123
|
+
filename,
|
|
124
|
+
chunkIndex: i,
|
|
125
|
+
totalChunks,
|
|
126
|
+
fileId,
|
|
127
|
+
...params
|
|
128
|
+
});
|
|
129
|
+
|
|
130
|
+
const url = `/upload?${search.toString()}`;
|
|
131
|
+
|
|
132
|
+
|
|
133
|
+
const res = await fetch(url, {
|
|
134
|
+
method: "POST",
|
|
135
|
+
body: arrayBuf,
|
|
136
|
+
headers: {
|
|
137
|
+
"x-user-id": accountId,
|
|
138
|
+
"x-auth-token": accountToken
|
|
139
|
+
},
|
|
140
|
+
});
|
|
141
|
+
|
|
142
|
+
const json = await res.json();
|
|
143
|
+
|
|
144
|
+
if (!json.ok)
|
|
145
|
+
return json;
|
|
146
|
+
|
|
147
|
+
const percent = Math.round(((i + 1) / totalChunks) * 100);
|
|
148
|
+
if (percent !== lastPercent) {
|
|
149
|
+
lastPercent = percent;
|
|
150
|
+
|
|
151
|
+
if(onProgress && typeof onProgress === "function"){
|
|
152
|
+
await onProgress(percent);
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
if (json.ok && json.path) {
|
|
157
|
+
return json;
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
return {ok: false, error: "unknown_upload_error"};
|
|
162
|
+
}
|
|
163
|
+
}
|
package/package.json
ADDED
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@hackthedev/file-manager",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "Frontend library with a few helper functions and dSyncFiles integration",
|
|
5
|
+
"license": "ISC",
|
|
6
|
+
"author": "",
|
|
7
|
+
"keywords": ["frontend"],
|
|
8
|
+
"main": "FileManager.js",
|
|
9
|
+
"scripts": {
|
|
10
|
+
"test": "echo \"Error: no test specified\" && exit 1"
|
|
11
|
+
}
|
|
12
|
+
}
|