@cocreate/file 1.19.0 → 1.19.2

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/src/client.js CHANGED
@@ -22,13 +22,13 @@
22
22
  * For details, visit <https://cocreate.app/licenses/> or contact us at sales@cocreate.app.
23
23
  */
24
24
 
25
- import Observer from '@cocreate/observer';
26
- import Crud from '@cocreate/crud-client';
27
- import Elements from '@cocreate/elements';
28
- import Actions from '@cocreate/actions';
29
- import { render } from '@cocreate/render';
30
- import { queryElements } from '@cocreate/utils';
31
- import '@cocreate/element-prototype';
25
+ import Observer from "@cocreate/observer";
26
+ import Crud from "@cocreate/crud-client";
27
+ import Elements from "@cocreate/elements";
28
+ import Actions from "@cocreate/actions";
29
+ import { render } from "@cocreate/render";
30
+ import { queryElements } from "@cocreate/utils";
31
+ import "@cocreate/element-prototype";
32
32
 
33
33
  const inputs = new Map();
34
34
  const Files = new Map();
@@ -36,968 +36,999 @@ const Files = new Map();
36
36
  /**
37
37
  * Initializes file elements. If no parameter is provided, it queries and initializes all elements with type="file".
38
38
  * It can also initialize a single element or an array of elements. Specifically focuses on elements of type 'file'.
39
- *
40
- * @param {(Element|Element[]|null)} [elements] - Optional. An element, an array of elements, or null.
39
+ *
40
+ * @param {(Element|Element[]|null)} [elements] - Optional. An element, an array of elements, or null.
41
41
  * - If null or omitted, the function queries and initializes all elements in the document with type="file".
42
42
  * - If a single element is provided, it initializes that element (assuming it is of type "file").
43
43
  * - If an array of elements is provided, each element in the array is initialized.
44
44
  */
45
45
  async function init(elements) {
46
- if (!elements)
47
- elements = document.querySelectorAll('[type="file"]')
48
- else if (!Array.isArray(elements))
49
- elements = [elements]
50
- for (let i = 0; i < elements.length; i++) {
51
- let nestedInput, isInput = elements[i].tagName === 'INPUT'
52
- if (!isInput) {
53
- nestedInput = elements[i].querySelector('input[type="file"]')
54
- }
55
-
56
- elements[i].getValue = async () => await getFiles([elements[i]])
57
- elements[i].getFiles = async () => await getFiles([elements[i]])
58
- elements[i].setValue = (files) => setFiles(elements[i], files);
59
- elements[i].renderValue = (files) => setFiles(elements[i], files);
60
-
61
- // if (elements[i].renderValue) {
62
- // let data = await elements[i].getValue()
63
- // if (data)
64
- // elements[i].setValue(data)
65
- // }
66
-
67
- if (elements[i].hasAttribute('directory')) {
68
- if (!isInput && window.showDirectoryPicker)
69
- elements[i].addEventListener("click", fileEvent);
70
- else if ('webkitdirectory' in elements[i]) {
71
- elements[i].webkitdirectory = true
72
- if (!isInput && !nestedInput) {
73
- nestedInput = document.createElement("input");
74
- nestedInput.type = "file";
75
- nestedInput.setAttribute('hidden', '')
76
- elements[i].appendChild(nestedInput);
77
- }
78
-
79
- if (nestedInput) {
80
- elements[i].addEventListener("click", function () {
81
- nestedInput.click()
82
- });
83
- nestedInput.addEventListener("change", fileEvent);
84
- } else
85
- elements[i].addEventListener("change", fileEvent);
86
- } else
87
- console.error("Directory selection not supported in this browser.");
88
- } else if (!isInput && window.showOpenFilePicker)
89
- elements[i].addEventListener("click", fileEvent);
90
- else {
91
- if (!isInput && !nestedInput) {
92
- nestedInput = document.createElement("input");
93
- nestedInput.type = "file";
94
- nestedInput.setAttribute('hidden', '')
95
- elements[i].appendChild(nestedInput);
96
- }
97
-
98
- if (nestedInput) {
99
- elements[i].addEventListener("click", function () {
100
- nestedInput.click()
101
- });
102
- nestedInput.addEventListener("change", fileEvent);
103
- } else
104
- elements[i].addEventListener("change", fileEvent);
105
- }
106
- }
46
+ if (!elements) elements = document.querySelectorAll('[type="file"]');
47
+ else if (!Array.isArray(elements)) elements = [elements];
48
+ for (let i = 0; i < elements.length; i++) {
49
+ let nestedInput,
50
+ isInput = elements[i].tagName === "INPUT";
51
+ if (!isInput) {
52
+ nestedInput = elements[i].querySelector('input[type="file"]');
53
+ }
54
+
55
+ elements[i].getValue = async () => await getFiles([elements[i]]);
56
+ elements[i].getFiles = async () => await getFiles([elements[i]]);
57
+ elements[i].setValue = (files) => setFiles(elements[i], files);
58
+ elements[i].renderValue = (files) => setFiles(elements[i], files);
59
+
60
+ // if (elements[i].renderValue) {
61
+ // let data = await elements[i].getValue()
62
+ // if (data)
63
+ // elements[i].setValue(data)
64
+ // }
65
+
66
+ if (elements[i].hasAttribute("directory")) {
67
+ if (!isInput && window.showDirectoryPicker)
68
+ elements[i].addEventListener("click", fileEvent);
69
+ else if ("webkitdirectory" in elements[i]) {
70
+ elements[i].webkitdirectory = true;
71
+ if (!isInput && !nestedInput) {
72
+ nestedInput = document.createElement("input");
73
+ nestedInput.type = "file";
74
+ nestedInput.setAttribute("hidden", "");
75
+ elements[i].appendChild(nestedInput);
76
+ nestedInput.fileElement = elements[i];
77
+ }
78
+
79
+ if (nestedInput) {
80
+ elements[i].addEventListener("click", function () {
81
+ nestedInput.click();
82
+ });
83
+ nestedInput.addEventListener("change", fileEvent);
84
+ } else elements[i].addEventListener("change", fileEvent);
85
+ } else
86
+ console.error(
87
+ "Directory selection not supported in this browser."
88
+ );
89
+ } else if (!isInput && window.showOpenFilePicker)
90
+ elements[i].addEventListener("click", fileEvent);
91
+ else {
92
+ if (!isInput && !nestedInput) {
93
+ nestedInput = document.createElement("input");
94
+ nestedInput.type = "file";
95
+ nestedInput.setAttribute("hidden", "");
96
+ elements[i].appendChild(nestedInput);
97
+ nestedInput.fileElement = elements[i];
98
+ }
99
+
100
+ if (nestedInput) {
101
+ elements[i].addEventListener("click", function () {
102
+ nestedInput.click();
103
+ });
104
+ nestedInput.addEventListener("change", fileEvent);
105
+ } else elements[i].addEventListener("change", fileEvent);
106
+ }
107
+ }
107
108
  }
108
109
 
109
110
  async function fileEvent(event) {
110
- try {
111
- const input = event.currentTarget;
112
- let multiple = input.multiple
113
- if (!multiple) {
114
- multiple = input.getAttribute('multiple');
115
- if (multiple !== null && multiple !== "false") {
116
- multiple = true;
117
- } else {
118
- multiple = false;
119
- }
120
- }
121
-
122
- let selected = inputs.get(input) || new Map()
123
- let files = input.files;
124
- if (!files || !files.length) {
125
- event.preventDefault()
126
- if (input.hasAttribute('directory')) {
127
- let handle = await window.showDirectoryPicker();
128
- let file = {
129
- name: handle.name,
130
- directory: '/',
131
- path: '/' + handle.name,
132
- type: 'text/directory',
133
- 'content-type': 'text/directory'
134
- }
135
- file.input = input
136
- file.id = await getFileId(file)
137
- if (selected.has(file.id)) {
138
- console.log('Duplicate file has been selected. This could be in error as the browser does not provide a clear way of checking duplictaes')
139
- }
140
-
141
- file.handle = handle
142
-
143
- if (!multiple) {
144
- for (let [id] of selected) {
145
- Files.delete(id);
146
- }
147
- selected.clear();
148
- }
149
-
150
- selected.set(file.id, file)
151
- Files.set(file.id, file)
152
-
153
- files = await getDirectoryHandles(handle, handle.name)
154
- } else {
155
- files = await window.showOpenFilePicker({ multiple });
156
- }
157
- }
158
-
159
- for (let i = 0; i < files.length; i++) {
160
- const handle = files[i]
161
- if (files[i].kind === 'file') {
162
- files[i] = await files[i].getFile();
163
- files[i].handle = handle
164
- } else if (files[i].kind === 'directory') {
165
- files[i].handle = handle
166
- }
167
-
168
- if (!files[i].src)
169
- await readFile(files[i])
170
- // if (!files[i].src)
171
- // files[i].src = files[i]
172
-
173
- // if (!files[i].src.name)
174
- // files[i].src = files[i]
175
-
176
- if (!files[i].size)
177
- files[i].size = handle.size
178
-
179
- files[i].directory = handle.directory || '/'
180
- files[i].path = handle.path || '/'
181
- files[i].pathname = handle.pathname || '/' + handle.name
182
- files[i]['content-type'] = files[i].type
183
- files[i].input = input
184
- files[i].id = await getFileId(files[i])
185
- if (selected.has(files[i].id)) {
186
- console.log('Duplicate file has been selected. This could be in error as the browser does not provide a clear way of checking duplictaes')
187
- }
188
-
189
- if (!multiple) {
190
- for (let [id] of selected) {
191
- Files.delete(id);
192
- }
193
- selected.clear();
194
- }
195
-
196
- selected.set(files[i].id, files[i])
197
- Files.set(files[i].id, files[i])
198
- }
199
-
200
- if (selected.size) {
201
- inputs.set(input, selected);
202
- console.log("Files selected:", selected);
203
-
204
- if (input.renderValue)
205
- input.renderValue(Array.from(selected.values()));
206
-
207
- const isImport = input.getAttribute('import')
208
- const isRealtime = input.getAttribute('realtime')
209
- if (isRealtime && isRealtime !== 'false') {
210
- if (isImport || isImport == "") {
211
- Import(input)
212
- } else if (input.save)
213
- input.save()
214
- }
215
- }
216
- } catch (error) {
217
- if (error.name !== 'AbortError') {
218
- console.error("Error selecting directory:", error);
219
- }
220
- }
221
-
111
+ try {
112
+ let input = event.currentTarget;
113
+ let multiple = input.multiple;
114
+
115
+ // If 'multiple' is not explicitly set, check the attribute.
116
+ if (multiple !== true && multiple !== false) {
117
+ multiple = input.getAttribute("multiple");
118
+ multiple = multiple !== null && multiple !== "false";
119
+ input.multiple = multiple;
120
+ }
121
+
122
+ let selected = inputs.get(input) || new Map();
123
+ let files = input.files;
124
+ input = input.fileElement || input;
125
+ if (!files || !files.length) {
126
+ event.preventDefault();
127
+ if (input.hasAttribute("directory")) {
128
+ let handle = await window.showDirectoryPicker();
129
+ let file = {
130
+ name: handle.name,
131
+ directory: "/",
132
+ path: "/" + handle.name,
133
+ type: "text/directory",
134
+ "content-type": "text/directory"
135
+ };
136
+ file.input = input;
137
+ file.id = await getFileId(file);
138
+ if (selected.has(file.id)) {
139
+ console.log(
140
+ "Duplicate file has been selected. This could be in error as the browser does not provide a clear way of checking duplictaes"
141
+ );
142
+ }
143
+
144
+ file.handle = handle;
145
+
146
+ if (!multiple) {
147
+ for (let [id] of selected) {
148
+ Files.delete(id);
149
+ }
150
+ selected.clear();
151
+ }
152
+
153
+ selected.set(file.id, file);
154
+ Files.set(file.id, file);
155
+
156
+ files = await getDirectoryHandles(handle, handle.name);
157
+ } else {
158
+ files = await window.showOpenFilePicker({ multiple });
159
+ }
160
+ }
161
+
162
+ for (let i = 0; i < files.length; i++) {
163
+ const handle = files[i];
164
+ if (files[i].kind === "file") {
165
+ files[i] = await files[i].getFile();
166
+ files[i].handle = handle;
167
+ } else if (files[i].kind === "directory") {
168
+ files[i].handle = handle;
169
+ }
170
+
171
+ if (!files[i].src) await readFile(files[i]);
172
+ // if (!files[i].src)
173
+ // files[i].src = files[i]
174
+
175
+ // if (!files[i].src.name)
176
+ // files[i].src = files[i]
177
+
178
+ if (!files[i].size) files[i].size = handle.size;
179
+
180
+ files[i].directory = handle.directory || "/";
181
+ files[i].path = handle.path || "/";
182
+ files[i].pathname = handle.pathname || "/" + handle.name;
183
+ files[i]["content-type"] = files[i].type;
184
+ files[i].input = input;
185
+ files[i].id = await getFileId(files[i]);
186
+ if (selected.has(files[i].id)) {
187
+ console.log(
188
+ "Duplicate file has been selected. This could be in error as the browser does not provide a clear way of checking duplictaes"
189
+ );
190
+ }
191
+
192
+ if (!multiple) {
193
+ for (let [id] of selected) {
194
+ Files.delete(id);
195
+ }
196
+ selected.clear();
197
+ }
198
+
199
+ selected.set(files[i].id, files[i]);
200
+ Files.set(files[i].id, files[i]);
201
+ }
202
+
203
+ if (selected.size) {
204
+ inputs.set(input, selected);
205
+ // console.log("Files selected:", selected);
206
+
207
+ if (input.renderValue)
208
+ input.renderValue(Array.from(selected.values()));
209
+
210
+ const isImport = input.getAttribute("import");
211
+ const isRealtime = input.getAttribute("realtime");
212
+ if (isRealtime && isRealtime !== "false") {
213
+ if (isImport || isImport == "") {
214
+ Import(input);
215
+ } else if (input.save) input.save();
216
+ }
217
+ }
218
+ } catch (error) {
219
+ if (error.name !== "AbortError") {
220
+ console.error("Error selecting directory:", error);
221
+ }
222
+ }
222
223
  }
223
224
 
224
225
  async function getDirectoryHandles(handle, name) {
225
- let handles = [];
226
- for await (const entry of handle.values()) {
227
- entry.directory = name
228
- entry.path = '/' + name + '/'
229
- entry.pathname = '/' + name + '/' + entry.name
230
- if (!entry.webkitRelativePath)
231
- entry.webkitRelativePath = name
232
-
233
- if (entry.kind === 'file') {
234
- handles.push(entry);
235
- } else if (entry.kind === 'directory') {
236
- entry.type = 'text/directory'
237
- handles.push(entry);
238
- const entries = await getDirectoryHandles(entry, name + '/' + entry.name);
239
- handles = handles.concat(entries);
240
- }
241
- }
242
- return handles;
226
+ let handles = [];
227
+ for await (const entry of handle.values()) {
228
+ entry.directory = name;
229
+ entry.path = "/" + name + "/";
230
+ entry.pathname = "/" + name + "/" + entry.name;
231
+ if (!entry.webkitRelativePath) entry.webkitRelativePath = name;
232
+
233
+ if (entry.kind === "file") {
234
+ handles.push(entry);
235
+ } else if (entry.kind === "directory") {
236
+ entry.type = "text/directory";
237
+ handles.push(entry);
238
+ const entries = await getDirectoryHandles(
239
+ entry,
240
+ name + "/" + entry.name
241
+ );
242
+ handles = handles.concat(entries);
243
+ }
244
+ }
245
+ return handles;
243
246
  }
244
247
 
245
248
  async function getFileId(file) {
246
-
247
- if (file.id = file.pathname) {
248
- return file.id;
249
- } else {
250
- file.id = `${file.name}${file.size}${file.type}${file.lastModified}`;
251
- return file.id;
252
- }
249
+ if ((file.id = file.pathname)) {
250
+ return file.id;
251
+ } else {
252
+ file.id = `${file.name}${file.size}${file.type}${file.lastModified}`;
253
+ return file.id;
254
+ }
253
255
  }
254
256
 
255
257
  async function getFiles(fileInputs, readAs) {
256
- const files = [];
257
-
258
- if (!Array.isArray(fileInputs))
259
- fileInputs = [fileInputs]
260
-
261
- for (let input of fileInputs) {
262
- const selected = inputs.get(input)
263
- if (selected) {
264
- for (let file of Array.from(selected.values())) {
265
- if (!file.src) {
266
- // if (readAs === 'blob')
267
- file.src = file
268
- // else
269
- // await readFile(file, readAs)
270
- }
271
-
272
- let fileObject = { ...file }
273
- fileObject.size = file.size
274
- await getCustomData(fileObject)
275
-
276
- files.push(fileObject)
277
- }
278
- }
279
- }
280
-
281
- return files
258
+ const files = [];
259
+
260
+ if (!Array.isArray(fileInputs)) fileInputs = [fileInputs];
261
+
262
+ for (let input of fileInputs) {
263
+ const selected = inputs.get(input);
264
+ if (selected) {
265
+ for (let file of Array.from(selected.values())) {
266
+ if (!file.src) {
267
+ // if (readAs === 'blob')
268
+ file.src = file;
269
+ // else
270
+ // await readFile(file, readAs)
271
+ }
272
+
273
+ let fileObject = { ...file };
274
+ fileObject.size = file.size;
275
+ await getCustomData(fileObject);
276
+
277
+ files.push(fileObject);
278
+ }
279
+ }
280
+ }
281
+
282
+ return files;
282
283
  }
283
284
 
284
285
  async function getCustomData(file) {
285
- // TODO: Consider potential replacment of file_id, perhaps supporting selector
286
- let form = document.querySelector(`[file_id="${file.id}"]`);
287
- if (form) {
288
- let elements = form.querySelectorAll('[file]');
289
- for (let i = 0; i < elements.length; i++) {
290
- let name = elements[i].getAttribute('file')
291
- if (name) {
292
- file[name] = await elements[i].getValue()
293
- }
294
- }
295
- }
296
-
297
- delete file.input;
298
-
299
- return file;
286
+ if (!file.id) file.id = file.pathname;
287
+ // TODO: Consider potential replacment of file_id, perhaps supporting selector
288
+ let form = document.querySelector(`[file_id="${file.id}"]`);
289
+ if (form) {
290
+ let elements = form.querySelectorAll("[file]");
291
+ for (let i = 0; i < elements.length; i++) {
292
+ let name = elements[i].getAttribute("file");
293
+ if (name) {
294
+ file[name] = await elements[i].getValue();
295
+ }
296
+ }
297
+ }
298
+
299
+ delete file.input;
300
+
301
+ return file;
300
302
  }
301
303
 
302
304
  // This function reads the file and returns its src
303
305
  function readFile(file, readAs) {
304
- return new Promise((resolve) => {
305
- const fileType = file.type.split('/');
306
-
307
- if (fileType[1] === 'directory') {
308
- return resolve(file)
309
- } else if (readAs) {
310
- if (readAs === 'blob')
311
- return resolve(file)
312
- } else if (fileType[0] === 'image') {
313
- readAs = 'readAsDataURL';
314
- } else if (fileType[0] === 'video') {
315
- readAs = 'readAsDataURL';
316
- } else if (fileType[0] === 'audio') {
317
- readAs = 'readAsDataURL';
318
- } else if (fileType[1] === 'pdf') {
319
- readAs = 'readAsDataURL';
320
- } else if (['doc', 'msword', 'docx', 'xlsx', 'pptx'].includes(fileType[1])) {
321
- readAs = 'readAsBinaryString';
322
- } else {
323
- readAs = 'readAsText';
324
- }
325
-
326
- const reader = new FileReader();
327
- reader[readAs](file);
328
-
329
- reader.onload = () => {
330
- file.src = reader.result;
331
- if (['doc', 'msword', 'docx', 'xlsx', 'pptx'].includes(fileType)) {
332
- file.src = btoa(file.src);
333
- }
334
-
335
- resolve(file);
336
- };
337
- });
306
+ return new Promise((resolve) => {
307
+ const fileType = file.type.split("/");
308
+
309
+ if (fileType[1] === "directory") {
310
+ return resolve(file);
311
+ } else if (readAs) {
312
+ if (readAs === "blob") return resolve(file);
313
+ } else if (fileType[0] === "image") {
314
+ readAs = "readAsDataURL";
315
+ } else if (fileType[0] === "video") {
316
+ readAs = "readAsDataURL";
317
+ } else if (fileType[0] === "audio") {
318
+ readAs = "readAsDataURL";
319
+ } else if (fileType[1] === "pdf") {
320
+ readAs = "readAsDataURL";
321
+ } else if (
322
+ ["doc", "msword", "docx", "xlsx", "pptx"].includes(fileType[1])
323
+ ) {
324
+ readAs = "readAsBinaryString";
325
+ } else {
326
+ readAs = "readAsText";
327
+ }
328
+
329
+ const reader = new FileReader();
330
+ reader[readAs](file);
331
+
332
+ reader.onload = () => {
333
+ file.src = reader.result;
334
+ if (["doc", "msword", "docx", "xlsx", "pptx"].includes(fileType)) {
335
+ file.src = btoa(file.src);
336
+ }
337
+
338
+ resolve(file);
339
+ };
340
+ });
338
341
  }
339
342
 
340
343
  function setFiles(element, files) {
341
- if (!files || typeof files !== 'object')
342
- return
343
- if (!Array.isArray(files))
344
- files = [files]
345
- else if (!files.length)
346
- return
347
-
348
- let selected = inputs.get(element) || new Map()
349
- for (let i = 0; i < files.length; i++) {
350
- if (!files[i].id)
351
- files[i].id = files[i].pathname
352
- files[i].input = element
353
- selected.set(files[i].id, files[i])
354
- Files.set(files[i].id, files[i])
355
- }
356
- inputs.set(element, selected);
357
- if (element.renderValue)
358
- render({ source: element, data: Array.from(selected.values()) })
344
+ if (!files || typeof files !== "object") return;
345
+ if (!Array.isArray(files)) files = [files];
346
+ else if (!files.length) return;
347
+
348
+ let selected = inputs.get(element) || new Map();
349
+
350
+ if (!element.multiple) {
351
+ for (let key of selected.keys()) {
352
+ selected.delete(key); // Remove the entry from the selected map
353
+ Files.delete(key); // Remove the corresponding entry from the Files map
354
+ }
355
+ }
356
+ for (let i = 0; i < files.length; i++) {
357
+ if (!files[i].id) files[i].id = files[i].pathname;
358
+ files[i].input = element;
359
+ selected.set(files[i].id, files[i]);
360
+ Files.set(files[i].id, files[i]);
361
+ }
362
+
363
+ inputs.set(element, selected);
364
+ if (element.renderValue)
365
+ render({
366
+ source: element,
367
+ data: Array.from(selected.values())
368
+ });
359
369
  }
360
370
 
361
371
  // TODO: Could this benifit from media processing to save results locally
362
372
  async function save(element, action, data) {
363
- try {
364
- if (!data)
365
- data = []
366
-
367
- if (!Array.isArray(element))
368
- element = [element]
369
-
370
- for (let i = 0; i < element.length; i++) {
371
- const inputs = []
372
- if (element[i].type === 'file')
373
- inputs.push(element[i])
374
- else if (element[i].tagName === 'form') {
375
- let fileInputs = element[i].querySelectorAll('input[type="file"]')
376
- inputs.push(...fileInputs)
377
- } else {
378
- const form = element[i].closest('form')
379
- if (form)
380
- inputs.push(...form.querySelectorAll('input[type="file"]'))
381
- }
382
-
383
- for (let input of inputs) {
384
- let files = await getFiles(input)
385
-
386
- for (let i = 0; i < files.length; i++) {
387
- if (!files[i].src) continue
388
-
389
- if (files[i].handle && action !== 'download') {
390
- if (action === 'saveAs') {
391
- if (files[i].kind === 'file') {
392
- const options = {
393
- suggestedName: files[i].name,
394
- types: [
395
- {
396
- description: 'Text Files',
397
- }
398
- ],
399
- };
400
- files[i].handle = await window.showSaveFilePicker(options);
401
- } else if (files[i].kind === 'directory') {
402
- // Create a new subdirectory
403
- files[i].handle = await files[i].handle.getDirectoryHandle('new_directory', { create: true });
404
- return
405
- }
406
- }
407
-
408
- if (files[i].handle.kind === 'directory') continue
409
-
410
- const writable = await files[i].handle.createWritable();
411
- await writable.write(files[i].src);
412
- await writable.close();
413
-
414
- } else {
415
- const blob = new Blob([files[i].src], { type: files[i].type });
416
-
417
- // Create a temporary <a> element to trigger the file download
418
- const downloadLink = document.createElement('a');
419
- downloadLink.href = URL.createObjectURL(blob);
420
- downloadLink.download = files[i].name;
421
-
422
- // Trigger the download
423
- downloadLink.click();
424
- }
425
-
426
- }
427
- }
428
-
429
- let queryElements = queryElements({ element: element[i], prefix: action })
430
- if (queryElements) {
431
- save(queryElements, action, data)
432
- }
433
- }
434
- return data
435
-
436
- } catch (error) {
437
- if (error.name !== 'AbortError') {
438
- console.error("Error selecting files:", error);
439
- }
440
- }
373
+ try {
374
+ if (!data) data = [];
375
+
376
+ if (!Array.isArray(element)) element = [element];
377
+
378
+ for (let i = 0; i < element.length; i++) {
379
+ const inputs = [];
380
+ if (element[i].type === "file") inputs.push(element[i]);
381
+ else if (element[i].tagName === "form") {
382
+ let fileInputs =
383
+ element[i].querySelectorAll('input[type="file"]');
384
+ inputs.push(...fileInputs);
385
+ } else {
386
+ const form = element[i].closest("form");
387
+ if (form)
388
+ inputs.push(...form.querySelectorAll('input[type="file"]'));
389
+ }
390
+
391
+ for (let input of inputs) {
392
+ let files = await getFiles(input);
393
+
394
+ for (let i = 0; i < files.length; i++) {
395
+ if (!files[i].src) continue;
396
+
397
+ if (files[i].handle && action !== "download") {
398
+ if (action === "saveAs") {
399
+ if (files[i].kind === "file") {
400
+ const options = {
401
+ suggestedName: files[i].name,
402
+ types: [
403
+ {
404
+ description: "Text Files"
405
+ }
406
+ ]
407
+ };
408
+ files[i].handle =
409
+ await window.showSaveFilePicker(options);
410
+ } else if (files[i].kind === "directory") {
411
+ // Create a new subdirectory
412
+ files[i].handle = await files[
413
+ i
414
+ ].handle.getDirectoryHandle("new_directory", {
415
+ create: true
416
+ });
417
+ return;
418
+ }
419
+ }
420
+
421
+ if (files[i].handle.kind === "directory") continue;
422
+
423
+ const writable = await files[i].handle.createWritable();
424
+ await writable.write(files[i].src);
425
+ await writable.close();
426
+ } else {
427
+ const blob = new Blob([files[i].src], {
428
+ type: files[i].type
429
+ });
430
+
431
+ // Create a temporary <a> element to trigger the file download
432
+ const downloadLink = document.createElement("a");
433
+ downloadLink.href = URL.createObjectURL(blob);
434
+ downloadLink.download = files[i].name;
435
+
436
+ // Trigger the download
437
+ downloadLink.click();
438
+ }
439
+ }
440
+ }
441
+
442
+ let queryElements = queryElements({
443
+ element: element[i],
444
+ prefix: action
445
+ });
446
+ if (queryElements) {
447
+ save(queryElements, action, data);
448
+ }
449
+ }
450
+ return data;
451
+ } catch (error) {
452
+ if (error.name !== "AbortError") {
453
+ console.error("Error selecting files:", error);
454
+ }
455
+ }
441
456
  }
442
457
 
443
458
  async function upload(element, data) {
444
- if (!data)
445
- data = []
446
-
447
- if (!Array.isArray(element))
448
- element = [element]
449
-
450
- for (let i = 0; i < element.length; i++) {
451
- const fileInputs = []
452
- if (element[i].type === 'file')
453
- fileInputs.push(element[i])
454
- else if (element[i].tagName === 'form') {
455
- fileInputs.push(...element[i].querySelectorAll('input[type="file"]'))
456
- } else {
457
- const form = element[i].closest('form')
458
- if (form)
459
- fileInputs.push(...form.querySelectorAll('input[type="file"]'))
460
- }
461
-
462
- for (let input of fileInputs) {
463
- let Data = Elements.getObject(input);
464
- let object = input.getAttribute('object') || ''
465
- let key = input.getAttribute('key')
466
-
467
- Data.broadcastBrowser = false
468
- Data.method = 'object.update'
469
- if (!Data.array)
470
- Data.array = 'files'
471
-
472
- let path = input.getAttribute('path')
473
- let directory = '/'
474
-
475
- if (path) {
476
- directory = path.split('/');
477
- directory = directory[directory.length - 1];
478
- if (!path.endsWith('/'))
479
- path += '/'
480
- } else
481
- path = directory = '/'
482
-
483
- if (!Data.host)
484
- Data.host = ['*']
485
-
486
- if (!Data.public)
487
- Data.public = true
488
-
489
- if (input.getFilter) {
490
- Data.$filter = await input.getFilter()
491
- if (!Data.$filter.query)
492
- Data.$filter.query = {}
493
- } else
494
- Data.$filter = {
495
- query: {}
496
- }
497
-
498
-
499
- // let files = await getFiles(input, 'blob')
500
- let files
501
- const selected = inputs.get(input)
502
- if (selected) {
503
- files = Array.from(selected.values())
504
- }
505
-
506
- let segmentSize = 10 * 1024 * 1024
507
- for (let i = 0; i < files.length; i++) {
508
- files[i].path = path
509
- files[i].pathname = path + files[i].name
510
- files[i].directory = directory
511
-
512
- // let fileObject = { ...file }
513
- // fileObject.size = file.size
514
- // await getCustomData(fileObject)
515
-
516
-
517
- if (input.processFile && files[i].size > segmentSize) {
518
- // let test = await input.processFile(files[i], null, segmentSize, null, null, null, input);
519
- let { playlist, segments } = await input.processFile(files[i], null, segmentSize);
520
-
521
- // Create a video element
522
- const videoElement = document.createElement('video');
523
- videoElement.setAttribute('controls', ''); // Add controls so you can play/pause
524
- videoElement.style.width = '100%';
525
- document.body.appendChild(videoElement);
526
-
527
- const mediaSource = new MediaSource();
528
- videoElement.src = URL.createObjectURL(mediaSource);
529
-
530
- mediaSource.addEventListener('sourceopen', () => {
531
- const sourceBuffer = mediaSource.addSourceBuffer('video/mp4; codecs="avc1.42E01E"');
532
-
533
- sourceBuffer.addEventListener('updateend', () => {
534
- console.log('Append operation completed.');
535
- try {
536
- console.log('Buffered ranges:', sourceBuffer.buffered);
537
- // Append next segment here if applicable
538
- } catch (e) {
539
- console.error('Error accessing buffered property:', e);
540
- }
541
- });
542
-
543
- function appendSegment(index) {
544
- if (index >= segments.length) {
545
- console.log('All segments have been appended.');
546
- return;
547
- }
548
-
549
- if (!sourceBuffer.updating) {
550
- segments[index].src.arrayBuffer().then(arrayBuffer => {
551
- console.log(`Appending segment ${index}`);
552
- sourceBuffer.appendBuffer(arrayBuffer);
553
- // Next segment will be appended on 'updateend' event
554
- }).catch(error => {
555
- console.error(`Error reading segment[${index}] as ArrayBuffer:`, error);
556
- });
557
- }
558
- }
559
-
560
- // Append the first segment to start
561
- appendSegment(0);
562
- });
563
-
564
-
565
- // mediaSource.addEventListener('sourceopen', () => {
566
- // const sourceBuffer = mediaSource.addSourceBuffer('video/mp4; codecs="avc1.42E01E"'); // avc1.4D401E, avc1.4D401F, avc1.4D4028, avc1.4D4020, avc1.4D4029, avc1.4D402A
567
-
568
- // // Append the first segment to start
569
- // if (!sourceBuffer.updating) {
570
-
571
- // segments[0].src.arrayBuffer().then(arrayBuffer => {
572
- // sourceBuffer.appendBuffer(arrayBuffer);
573
-
574
- // // Wait for 3 seconds before logging the sourceBuffer state
575
- // setTimeout(() => {
576
- // console.log(sourceBuffer);
577
- // }, 3000); // 3000 milliseconds = 3 seconds
578
-
579
- // sourceBuffer.addEventListener('updateend', () => {
580
- // console.log('Append operation completed.');
581
- // try {
582
- // console.log('Buffered ranges:', sourceBuffer.buffered);
583
- // } catch (e) {
584
- // console.error('Error accessing buffered property:', e);
585
- // }
586
- // // Proceed with additional operations here
587
- // });
588
-
589
- // }).catch(error => {
590
- // console.error('Error reading segment[0] as ArrayBuffer:', error);
591
- // });
592
-
593
-
594
- // // segments[0].src.arrayBuffer().then(arrayBuffer => {
595
- // // sourceBuffer.appendBuffer(arrayBuffer);
596
- // // })
597
-
598
- // // let segmentLength = 0
599
- // // sourceBuffer.addEventListener('updateend', () => {
600
- // // segmentLength += 1
601
- // // if (segments[segmentLength])
602
- // // segments[segmentLength].src.arrayBuffer().then(arrayBuffer => {
603
- // // console.log(sourceBuffer)
604
- // // // sourceBuffer.appendBuffer(arrayBuffer);
605
- // // })
606
- // // });
607
- // }
608
- // });
609
-
610
- }
611
-
612
- // files[i].src = playlist
613
- // for (let j = 0; j < segments.length; j++) {
614
- // segments[j].path = path
615
- // segments[j].pathname = path + segments[j].name
616
- // segments[j].directory = directory
617
- // segments[j] = { ...segments[j], ...await readFile(segments[j].src) }
618
- // segments[j].public = true
619
- // segments[j].host = ['*']
620
-
621
- // playlist.segments[j].src = segments[j].pathname
622
- // Data.$filter.query.pathname = segments[j].pathname
623
- // Crud.send({
624
- // ...Data,
625
- // object: segments[j],
626
- // upsert: true
627
- // });
628
- // }
629
-
630
- // } else {
631
- // files[i] = { ...files[i], ...await readFile(files[i].src) }
632
- // }
633
-
634
- // if (!key) {
635
- // Data.object = { ...files[i] }
636
- // } else {
637
- // Data.object = { [key]: { ...files[i] } }
638
- // }
639
-
640
- // if (object) {
641
- // Data.object._id = object // test
642
- // }
643
-
644
- // delete Data.object.input
645
- // Data.$filter.query.pathname = files[i].pathname
646
- // let response = await Crud.send({
647
- // ...Data,
648
- // upsert: true
649
- // });
650
-
651
- // console.log(response, 'tes')
652
- // if (response && (!object || object !== response.object)) {
653
- // Elements.setTypeValue(element, response);
654
- // }
655
-
656
- }
657
- }
658
-
659
- let queriedElements = queryElements({ element: element[i], prefix: 'upload' })
660
- if (queriedElements) {
661
- upload(queriedElements, data)
662
- }
663
- }
664
- return data
459
+ if (!data) data = [];
460
+
461
+ if (!Array.isArray(element)) element = [element];
462
+
463
+ for (let i = 0; i < element.length; i++) {
464
+ const fileInputs = [];
465
+ if (element[i].type === "file") fileInputs.push(element[i]);
466
+ else if (element[i].tagName === "form") {
467
+ fileInputs.push(
468
+ ...element[i].querySelectorAll('input[type="file"]')
469
+ );
470
+ } else {
471
+ const form = element[i].closest("form");
472
+ if (form)
473
+ fileInputs.push(...form.querySelectorAll('input[type="file"]'));
474
+ }
475
+
476
+ for (let input of fileInputs) {
477
+ let Data = Elements.getObject(input);
478
+ let object = input.getAttribute("object") || "";
479
+ let key = input.getAttribute("key");
480
+
481
+ Data.broadcastBrowser = false;
482
+ Data.method = "object.update";
483
+ if (!Data.array) Data.array = "files";
484
+
485
+ let path = input.getAttribute("path");
486
+ let directory = "/";
487
+
488
+ if (path) {
489
+ directory = path.split("/");
490
+ directory = directory[directory.length - 1];
491
+ if (!path.endsWith("/")) path += "/";
492
+ } else path = directory = "/";
493
+
494
+ if (!Data.host) Data.host = ["*"];
495
+
496
+ if (!Data.public) Data.public = true;
497
+
498
+ if (input.getFilter) {
499
+ Data.$filter = await input.getFilter();
500
+ if (!Data.$filter.query) Data.$filter.query = {};
501
+ } else
502
+ Data.$filter = {
503
+ query: {}
504
+ };
505
+
506
+ // let files = await getFiles(input, 'blob')
507
+ let files;
508
+ const selected = inputs.get(input);
509
+ if (selected) {
510
+ files = Array.from(selected.values());
511
+ }
512
+
513
+ let segmentSize = 10 * 1024 * 1024;
514
+ for (let i = 0; i < files.length; i++) {
515
+ files[i].path = path;
516
+ files[i].pathname = path + files[i].name;
517
+ files[i].directory = directory;
518
+
519
+ // let fileObject = { ...file }
520
+ // fileObject.size = file.size
521
+ // await getCustomData(fileObject)
522
+
523
+ if (input.processFile && files[i].size > segmentSize) {
524
+ // let test = await input.processFile(files[i], null, segmentSize, null, null, null, input);
525
+ let { playlist, segments } = await input.processFile(
526
+ files[i],
527
+ null,
528
+ segmentSize
529
+ );
530
+
531
+ // Create a video element
532
+ const videoElement = document.createElement("video");
533
+ videoElement.setAttribute("controls", ""); // Add controls so you can play/pause
534
+ videoElement.style.width = "100%";
535
+ document.body.appendChild(videoElement);
536
+
537
+ const mediaSource = new MediaSource();
538
+ videoElement.src = URL.createObjectURL(mediaSource);
539
+
540
+ mediaSource.addEventListener("sourceopen", () => {
541
+ const sourceBuffer = mediaSource.addSourceBuffer(
542
+ 'video/mp4; codecs="avc1.42E01E"'
543
+ );
544
+
545
+ sourceBuffer.addEventListener("updateend", () => {
546
+ console.log("Append operation completed.");
547
+ try {
548
+ console.log(
549
+ "Buffered ranges:",
550
+ sourceBuffer.buffered
551
+ );
552
+ // Append next segment here if applicable
553
+ } catch (e) {
554
+ console.error(
555
+ "Error accessing buffered property:",
556
+ e
557
+ );
558
+ }
559
+ });
560
+
561
+ function appendSegment(index) {
562
+ if (index >= segments.length) {
563
+ console.log("All segments have been appended.");
564
+ return;
565
+ }
566
+
567
+ if (!sourceBuffer.updating) {
568
+ segments[index].src
569
+ .arrayBuffer()
570
+ .then((arrayBuffer) => {
571
+ console.log(
572
+ `Appending segment ${index}`
573
+ );
574
+ sourceBuffer.appendBuffer(arrayBuffer);
575
+ // Next segment will be appended on 'updateend' event
576
+ })
577
+ .catch((error) => {
578
+ console.error(
579
+ `Error reading segment[${index}] as ArrayBuffer:`,
580
+ error
581
+ );
582
+ });
583
+ }
584
+ }
585
+
586
+ // Append the first segment to start
587
+ appendSegment(0);
588
+ });
589
+
590
+ // mediaSource.addEventListener('sourceopen', () => {
591
+ // const sourceBuffer = mediaSource.addSourceBuffer('video/mp4; codecs="avc1.42E01E"'); // avc1.4D401E, avc1.4D401F, avc1.4D4028, avc1.4D4020, avc1.4D4029, avc1.4D402A
592
+
593
+ // // Append the first segment to start
594
+ // if (!sourceBuffer.updating) {
595
+
596
+ // segments[0].src.arrayBuffer().then(arrayBuffer => {
597
+ // sourceBuffer.appendBuffer(arrayBuffer);
598
+
599
+ // // Wait for 3 seconds before logging the sourceBuffer state
600
+ // setTimeout(() => {
601
+ // console.log(sourceBuffer);
602
+ // }, 3000); // 3000 milliseconds = 3 seconds
603
+
604
+ // sourceBuffer.addEventListener('updateend', () => {
605
+ // console.log('Append operation completed.');
606
+ // try {
607
+ // console.log('Buffered ranges:', sourceBuffer.buffered);
608
+ // } catch (e) {
609
+ // console.error('Error accessing buffered property:', e);
610
+ // }
611
+ // // Proceed with additional operations here
612
+ // });
613
+
614
+ // }).catch(error => {
615
+ // console.error('Error reading segment[0] as ArrayBuffer:', error);
616
+ // });
617
+
618
+ // // segments[0].src.arrayBuffer().then(arrayBuffer => {
619
+ // // sourceBuffer.appendBuffer(arrayBuffer);
620
+ // // })
621
+
622
+ // // let segmentLength = 0
623
+ // // sourceBuffer.addEventListener('updateend', () => {
624
+ // // segmentLength += 1
625
+ // // if (segments[segmentLength])
626
+ // // segments[segmentLength].src.arrayBuffer().then(arrayBuffer => {
627
+ // // console.log(sourceBuffer)
628
+ // // // sourceBuffer.appendBuffer(arrayBuffer);
629
+ // // })
630
+ // // });
631
+ // }
632
+ // });
633
+ }
634
+
635
+ // files[i].src = playlist
636
+ // for (let j = 0; j < segments.length; j++) {
637
+ // segments[j].path = path
638
+ // segments[j].pathname = path + segments[j].name
639
+ // segments[j].directory = directory
640
+ // segments[j] = { ...segments[j], ...await readFile(segments[j].src) }
641
+ // segments[j].public = true
642
+ // segments[j].host = ['*']
643
+
644
+ // playlist.segments[j].src = segments[j].pathname
645
+ // Data.$filter.query.pathname = segments[j].pathname
646
+ // Crud.send({
647
+ // ...Data,
648
+ // object: segments[j],
649
+ // upsert: true
650
+ // });
651
+ // }
652
+
653
+ // } else {
654
+ // files[i] = { ...files[i], ...await readFile(files[i].src) }
655
+ // }
656
+
657
+ // if (!key) {
658
+ // Data.object = { ...files[i] }
659
+ // } else {
660
+ // Data.object = { [key]: { ...files[i] } }
661
+ // }
662
+
663
+ // if (object) {
664
+ // Data.object._id = object // test
665
+ // }
666
+
667
+ // delete Data.object.input
668
+ // Data.$filter.query.pathname = files[i].pathname
669
+ // let response = await Crud.send({
670
+ // ...Data,
671
+ // upsert: true
672
+ // });
673
+
674
+ // console.log(response, 'tes')
675
+ // if (response && (!object || object !== response.object)) {
676
+ // Elements.setTypeValue(element, response);
677
+ // }
678
+ }
679
+ }
680
+
681
+ let queriedElements = queryElements({
682
+ element: element[i],
683
+ prefix: "upload"
684
+ });
685
+ if (queriedElements) {
686
+ upload(queriedElements, data);
687
+ }
688
+ }
689
+ return data;
665
690
  }
666
691
 
667
692
  async function Import(element, data) {
668
- if (!data)
669
- data = []
670
-
671
- if (!Array.isArray(element))
672
- element = [element]
673
-
674
- for (let i = 0; i < element.length; i++) {
675
- const inputs = []
676
- if (element[i].type === 'file')
677
- inputs.push(element[i])
678
- else if (element[i].tagName === 'form') {
679
- let fileInputs = element[i].querySelectorAll('input[type="file"]')
680
- inputs.push(...fileInputs)
681
- } else {
682
- const form = element[i].closest('form')
683
- if (form)
684
- inputs.push(...form.querySelectorAll('input[type="file"]'))
685
- }
686
-
687
- if (inputs.length) {
688
- let Data = await getFiles(inputs)
689
- Data.reduce((result, { src }) => {
690
- try {
691
- const parsedSrc = JSON.parse(src);
692
- if (Array.isArray(parsedSrc))
693
- data.push(...parsedSrc);
694
- else
695
- data.push(parsedSrc);
696
- } catch (error) {
697
- console.error(`Error parsing JSON: ${error}`);
698
- }
699
- return result;
700
- }, []);
701
-
702
- }
703
-
704
- if (element[i].type !== 'file') {
705
- let Data = Elements.getObject(element[i]);
706
- if (Data.type) {
707
- if (element[i].getFilter)
708
- Data.$filter = await element[i].getFilter()
709
-
710
- if (Data.type === 'key')
711
- Data.type = 'object'
712
-
713
- data.push(Data)
714
- }
715
- }
716
-
717
- if (data.length) {
718
- for (let i = 0; i < data.length; i++) {
719
- // TODO: if _id exist use update method
720
- data[i].method = data[i].type + '.create'
721
- data[i] = await Crud.send(data[i])
722
- }
723
- }
724
-
725
- let queriedElements = queryElements({ element: element[i], prefix: 'import' })
726
- if (queriedElements) {
727
- Import(queriedElements, data)
728
- }
729
- }
730
- return data
693
+ if (!data) data = [];
694
+
695
+ if (!Array.isArray(element)) element = [element];
696
+
697
+ for (let i = 0; i < element.length; i++) {
698
+ const inputs = [];
699
+ if (element[i].type === "file") inputs.push(element[i]);
700
+ else if (element[i].tagName === "form") {
701
+ let fileInputs = element[i].querySelectorAll('input[type="file"]');
702
+ inputs.push(...fileInputs);
703
+ } else {
704
+ const form = element[i].closest("form");
705
+ if (form)
706
+ inputs.push(...form.querySelectorAll('input[type="file"]'));
707
+ }
708
+
709
+ if (inputs.length) {
710
+ let Data = await getFiles(inputs);
711
+ Data.reduce((result, { src }) => {
712
+ try {
713
+ const parsedSrc = JSON.parse(src);
714
+ if (Array.isArray(parsedSrc)) data.push(...parsedSrc);
715
+ else data.push(parsedSrc);
716
+ } catch (error) {
717
+ console.error(`Error parsing JSON: ${error}`);
718
+ }
719
+ return result;
720
+ }, []);
721
+ }
722
+
723
+ if (element[i].type !== "file") {
724
+ let Data = Elements.getObject(element[i]);
725
+ if (Data.type) {
726
+ if (element[i].getFilter)
727
+ Data.$filter = await element[i].getFilter();
728
+
729
+ if (Data.type === "key") Data.type = "object";
730
+
731
+ data.push(Data);
732
+ }
733
+ }
734
+
735
+ if (data.length) {
736
+ for (let i = 0; i < data.length; i++) {
737
+ // TODO: if _id exist use update method
738
+ data[i].method = data[i].type + ".create";
739
+ data[i] = await Crud.send(data[i]);
740
+ }
741
+ }
742
+
743
+ let queriedElements = queryElements({
744
+ element: element[i],
745
+ prefix: "import"
746
+ });
747
+ if (queriedElements) {
748
+ Import(queriedElements, data);
749
+ }
750
+ }
751
+ return data;
731
752
  }
732
753
 
754
+ // TODO: Export selected rows or entire table or entire array
733
755
  async function Export(element, data) {
734
- if (!data)
735
- data = []
736
-
737
- if (!Array.isArray(element))
738
- element = [element]
739
-
740
- for (let i = 0; i < element.length; i++) {
741
- const inputs = []
742
- if (element[i].type === 'file')
743
- inputs.push(element[i])
744
- else if (element[i].tagName === 'form') {
745
- let fileInputs = element[i].querySelectorAll('input[type="file"]')
746
- inputs.push(...fileInputs)
747
- } else {
748
- const form = element[i].closest('form')
749
- if (form)
750
- inputs.push(...form.querySelectorAll('input[type="file"]'))
751
- }
752
-
753
- if (inputs.length)
754
- data.push(...getFiles(inputs))
755
-
756
- let Data = Elements.getObject(element[i]);
757
- if (Data.type) {
758
- if (element[i].getFilter)
759
- Data.$filter = await element[i].getFilter()
760
-
761
- if (Data.type === 'key')
762
- Data.type = 'object'
763
- Data.method = Data.type + '.read'
764
- Data = await Crud.send(Data)
765
- data.push(...Data[Data.type])
766
-
767
- }
768
-
769
- let queriedElements = queryElements({ element: element[i], prefix: 'export' })
770
- if (queriedElements) {
771
- Export(queriedElements, data)
772
- }
773
-
774
- }
775
-
776
- if (data.length)
777
- exportFile(data);
778
-
779
- return data
756
+ if (!data) data = [];
757
+
758
+ if (!Array.isArray(element)) element = [element];
759
+
760
+ for (let i = 0; i < element.length; i++) {
761
+ const inputs = [];
762
+ if (element[i].type === "file") inputs.push(element[i]);
763
+ else if (element[i].tagName === "form") {
764
+ let fileInputs = element[i].querySelectorAll('input[type="file"]');
765
+ inputs.push(...fileInputs);
766
+ } else {
767
+ const form = element[i].closest("form");
768
+ if (form)
769
+ inputs.push(...form.querySelectorAll('input[type="file"]'));
770
+ }
771
+
772
+ if (inputs.length) data.push(...getFiles(inputs));
773
+
774
+ let Data = Elements.getObject(element[i]);
775
+ if (Data.type) {
776
+ if (element[i].getFilter)
777
+ Data.$filter = await element[i].getFilter();
778
+
779
+ if (Data.type === "key") Data.type = "object";
780
+ Data.method = Data.type + ".read";
781
+ Data = await Crud.send(Data);
782
+ data.push(...Data[Data.type]);
783
+ }
784
+
785
+ let queriedElements = queryElements({
786
+ element: element[i],
787
+ prefix: "export"
788
+ });
789
+ if (queriedElements) {
790
+ Export(queriedElements, data);
791
+ }
792
+ }
793
+
794
+ if (data.length) exportFile(data);
795
+
796
+ return data;
780
797
  }
781
798
 
782
799
  async function exportFile(data) {
783
- let name = data.type || 'download';
784
- let exportData = JSON.stringify(data, null, 2);
785
- let blob = new Blob([exportData], { type: "application/json" });
786
- let url = URL.createObjectURL(blob);
800
+ let name = data.type || "download";
801
+ let exportData = JSON.stringify(data, null, 2);
802
+ let blob = new Blob([exportData], { type: "application/json" });
803
+ let url = URL.createObjectURL(blob);
787
804
 
788
- let link = document.createElement("a");
805
+ let link = document.createElement("a");
789
806
 
790
- link.href = url;
791
- link.download = name;
807
+ link.href = url;
808
+ link.download = name;
792
809
 
793
- document.body.appendChild(link);
810
+ document.body.appendChild(link);
794
811
 
795
- link.dispatchEvent(
796
- new MouseEvent('click', {
797
- bubbles: true,
798
- cancelable: true,
799
- view: window
800
- })
801
- );
812
+ link.dispatchEvent(
813
+ new MouseEvent("click", {
814
+ bubbles: true,
815
+ cancelable: true,
816
+ view: window
817
+ })
818
+ );
802
819
 
803
- URL.revokeObjectURL(url);
804
- link.remove();
820
+ URL.revokeObjectURL(url);
821
+ link.remove();
805
822
  }
806
823
 
807
824
  // TODO: handled by import? if value is a valid url get file by url?
808
825
  async function importURL(action) {
809
- try {
810
- let element = action.element
811
- let url = element.getAttribute('url')
812
- if (!url) {
813
- element = action.form.querySelector('[import-url]')
814
- if (!element)
815
- return
816
- url = element.getValue()
817
- if (!url)
818
- return
819
-
820
- }
821
-
822
- const urlObject = new URL(url);
823
- const filename = urlObject.pathname.split('/').pop();
824
-
825
- const file = {
826
- src: url,
827
- name: filename,
828
- directory: '/',
829
- path: '/',
830
- pathname: '/' + filename
831
- };
832
-
833
- await getCustomData(file)
834
-
835
- let data = await Crud.socket.send({
836
- method: 'importUrl',
837
- file,
838
- broadcast: false,
839
- broadcastClient: false
840
- })
841
-
842
- let queriedElements = queryElements({ element, prefix: 'import-url' })
843
- if (queriedElements) {
844
- for (let queriedElement of queriedElements)
845
- queriedElement.setValue(data.file)
846
-
847
- }
848
-
849
- document.dispatchEvent(new CustomEvent(action.name, {
850
- detail: {}
851
- }));
852
-
853
- } catch (error) {
854
- console.error('Error importing file from URL:', error);
855
- throw error;
856
- }
826
+ try {
827
+ let element = action.element;
828
+ let url = element.getAttribute("url");
829
+ if (!url) {
830
+ element = action.form.querySelector("[import-url]");
831
+ if (!element) return;
832
+ url = element.getValue();
833
+ if (!url) return;
834
+ }
835
+
836
+ const urlObject = new URL(url);
837
+ const filename = urlObject.pathname.split("/").pop();
838
+
839
+ const file = {
840
+ src: url,
841
+ name: filename,
842
+ directory: "/",
843
+ path: "/",
844
+ pathname: "/" + filename
845
+ };
846
+
847
+ await getCustomData(file);
848
+
849
+ let data = await Crud.socket.send({
850
+ method: "importUrl",
851
+ file,
852
+ broadcast: false,
853
+ broadcastClient: false
854
+ });
855
+
856
+ let queriedElements = queryElements({ element, prefix: "import-url" });
857
+ if (queriedElements) {
858
+ for (let queriedElement of queriedElements)
859
+ queriedElement.setValue(data.file);
860
+ }
861
+
862
+ document.dispatchEvent(
863
+ new CustomEvent(action.name, {
864
+ detail: {}
865
+ })
866
+ );
867
+ } catch (error) {
868
+ console.error("Error importing file from URL:", error);
869
+ throw error;
870
+ }
857
871
  }
858
872
 
859
873
  async function fileRenderAction(action) {
860
- const element = action.element
861
-
862
- let file_id = element.getAttribute('file_id');
863
- if (!file_id) {
864
- const closestElement = element.closest('[file_id]');
865
- if (closestElement)
866
- file_id = closestElement.getAttribute('file_id');
867
- }
868
-
869
- let input = Files.get(file_id).input
870
-
871
- if (!file_id || !input) return
872
-
873
- let file = inputs.get(input).get(file_id)
874
- if (!file) return
875
-
876
- if (action.name === 'createFile') {
877
- let name = element.getAttribute('value')
878
- create(file, 'file', name)
879
- } else if (action.name === 'deleteFile')
880
- Delete(file)
881
- else if (action.name === 'createDirectory') {
882
- let name = element.getAttribute('value')
883
- create(file, 'directory', name)
884
- } else if (action.name === 'deleteDirectory')
885
- Delete(file)
886
-
887
- document.dispatchEvent(new CustomEvent(action.name, {
888
- detail: {}
889
- }));
890
-
874
+ const element = action.element;
875
+
876
+ let file_id = element.getAttribute("file_id");
877
+ if (!file_id) {
878
+ const closestElement = element.closest("[file_id]");
879
+ if (closestElement) file_id = closestElement.getAttribute("file_id");
880
+ }
881
+
882
+ let input = Files.get(file_id).input;
883
+
884
+ if (!file_id || !input) return;
885
+
886
+ let file = inputs.get(input).get(file_id);
887
+ if (!file) return;
888
+
889
+ if (action.name === "createFile") {
890
+ let name = element.getAttribute("value");
891
+ create(file, "file", name);
892
+ } else if (action.name === "deleteFile") Delete(file);
893
+ else if (action.name === "createDirectory") {
894
+ let name = element.getAttribute("value");
895
+ create(file, "directory", name);
896
+ } else if (action.name === "deleteDirectory") Delete(file);
897
+
898
+ document.dispatchEvent(
899
+ new CustomEvent(action.name, {
900
+ detail: {}
901
+ })
902
+ );
891
903
  }
892
904
 
893
905
  async function create(directory, type, name, src = "") {
894
- try {
895
- if (directory.handle && directory.input) {
896
- if (!name) {
897
- const name = prompt('Enter the file name:');
898
- if (!name) {
899
- console.log('Invalid file name.');
900
- return;
901
- }
902
-
903
- }
904
-
905
- let handle, file
906
- if (type === 'directory') {
907
- handle = await directory.handle.getDirectoryHandle(name, { create: true });
908
- file = { name: handle.name, type: 'text/directory' }
909
- } else if (type === 'file') {
910
- handle = await directory.handle.getFileHandle(name, { create: true });
911
- const writable = await handle.createWritable();
912
-
913
- // Write data to the new file...
914
- await writable.write(src);
915
- await writable.close();
916
-
917
- file = handle.getFile()
918
- }
919
-
920
- if (directory.input) {
921
- file.directory = directory.name
922
- file.pathname = directory.path + '/' + file.name
923
- file.path = directory.path + '/' + file.name
924
- file.input = directory.input
925
- file.handle = handle
926
- file['content-type'] = file.type
927
-
928
- file.id = await getFileId(file)
929
- if (inputs.get(directory.input).has(file.id)) {
930
- console.log('Duplicate file has been selected. This could be in error as the browser does not provide a clear way of checking duplictaes')
931
- }
932
-
933
- inputs.get(directory.input).set(file.id, file)
934
- }
935
- }
936
- } catch (error) {
937
- console.log('Error adding file:', error);
938
- }
906
+ try {
907
+ if (directory.handle && directory.input) {
908
+ if (!name) {
909
+ const name = prompt("Enter the file name:");
910
+ if (!name) {
911
+ console.log("Invalid file name.");
912
+ return;
913
+ }
914
+ }
915
+
916
+ let handle, file;
917
+ if (type === "directory") {
918
+ handle = await directory.handle.getDirectoryHandle(name, {
919
+ create: true
920
+ });
921
+ file = { name: handle.name, type: "text/directory" };
922
+ } else if (type === "file") {
923
+ handle = await directory.handle.getFileHandle(name, {
924
+ create: true
925
+ });
926
+ const writable = await handle.createWritable();
927
+
928
+ // Write data to the new file...
929
+ await writable.write(src);
930
+ await writable.close();
931
+
932
+ file = handle.getFile();
933
+ }
934
+
935
+ if (directory.input) {
936
+ file.directory = directory.name;
937
+ file.pathname = directory.path + "/" + file.name;
938
+ file.path = directory.path + "/" + file.name;
939
+ file.input = directory.input;
940
+ file.handle = handle;
941
+ file["content-type"] = file.type;
942
+
943
+ file.id = await getFileId(file);
944
+ if (inputs.get(directory.input).has(file.id)) {
945
+ console.log(
946
+ "Duplicate file has been selected. This could be in error as the browser does not provide a clear way of checking duplictaes"
947
+ );
948
+ }
949
+
950
+ inputs.get(directory.input).set(file.id, file);
951
+ }
952
+ }
953
+ } catch (error) {
954
+ console.log("Error adding file:", error);
955
+ }
939
956
  }
940
957
 
941
958
  async function Delete(file) {
942
- try {
943
- if (file.handle) {
944
- await file.handle.remove();
945
- if (file.input && file.id)
946
- inputs.get(file.input).delete(file.id)
947
- }
948
- } catch (error) {
949
- console.log('Error deleting file:', error);
950
- }
959
+ try {
960
+ if (file.handle) {
961
+ await file.handle.remove();
962
+ if (file.input && file.id) inputs.get(file.input).delete(file.id);
963
+ }
964
+ } catch (error) {
965
+ console.log("Error deleting file:", error);
966
+ }
951
967
  }
952
968
 
953
969
  Observer.init({
954
- name: 'CoCreateFileAddedNodes',
955
- observe: ['addedNodes'],
956
- selector: '[type="file"]',
957
- callback: mutation => init(mutation.target)
958
-
970
+ name: "CoCreateFileAddedNodes",
971
+ observe: ["addedNodes"],
972
+ selector: '[type="file"]',
973
+ callback: (mutation) => init(mutation.target)
959
974
  });
960
975
 
961
976
  Observer.init({
962
- name: 'CoCreateFileAttributes',
963
- observe: ['attributes'],
964
- attributeName: ['type'],
965
- selector: '[type="file"]',
966
- callback: mutation => init(mutation.target)
977
+ name: "CoCreateFileAttributes",
978
+ observe: ["attributes"],
979
+ attributeName: ["type"],
980
+ selector: '[type="file"]',
981
+ callback: (mutation) => init(mutation.target)
967
982
  });
968
983
 
969
984
  Actions.init([
970
- {
971
- name: ["upload", "download", "saveLocally", "asveAs", "import", "export", "importUrl"],
972
- callback: (action) => {
973
- if (action.name === 'upload')
974
- upload(action.element)
975
- else if (action.name === 'saveLocally' || action.name === 'saveAs') {
976
- save(action.element)
977
- } else if (action.name === 'export') {
978
- Export(action.element)
979
- } else if (action.name === 'import') {
980
- Import(action.element)
981
- } else if (action.name === 'importUrl') {
982
- importURL(action)
983
- } else {
984
- // Something...
985
- }
986
-
987
- document.dispatchEvent(new CustomEvent(action.name, {
988
- detail: {}
989
- }));
990
-
991
- }
992
- },
993
- {
994
- name: ["createFile", "deleteFile", "createDirectory", "deleteDirectory"],
995
- callback: (action) => {
996
- fileRenderAction(action)
997
- }
998
- }
999
- ])
1000
-
1001
- init()
1002
-
1003
- export default { inputs, getFiles, create, Delete }
985
+ {
986
+ name: [
987
+ "upload",
988
+ "download",
989
+ "saveLocally",
990
+ "asveAs",
991
+ "import",
992
+ "export",
993
+ "importUrl"
994
+ ],
995
+ callback: (action) => {
996
+ if (action.name === "upload") upload(action.element);
997
+ else if (
998
+ action.name === "saveLocally" ||
999
+ action.name === "saveAs"
1000
+ ) {
1001
+ save(action.element);
1002
+ } else if (action.name === "export") {
1003
+ Export(action.element);
1004
+ } else if (action.name === "import") {
1005
+ Import(action.element);
1006
+ } else if (action.name === "importUrl") {
1007
+ importURL(action);
1008
+ } else {
1009
+ // Something...
1010
+ }
1011
+
1012
+ document.dispatchEvent(
1013
+ new CustomEvent(action.name, {
1014
+ detail: {}
1015
+ })
1016
+ );
1017
+ }
1018
+ },
1019
+ {
1020
+ name: [
1021
+ "createFile",
1022
+ "deleteFile",
1023
+ "createDirectory",
1024
+ "deleteDirectory"
1025
+ ],
1026
+ callback: (action) => {
1027
+ fileRenderAction(action);
1028
+ }
1029
+ }
1030
+ ]);
1031
+
1032
+ init();
1033
+
1034
+ export default { inputs, getFiles, create, Delete };