@cocreate/file 1.3.11 → 1.5.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/src/client.js CHANGED
@@ -1,188 +1,235 @@
1
- import observer from '@cocreate/observer';
2
- import crud from '@cocreate/crud-client';
3
- import action from '@cocreate/actions';
1
+ /********************************************************************************
2
+ * Copyright (C) 2023 CoCreate and Contributors.
3
+ *
4
+ * This program is free software: you can redistribute it and/or modify
5
+ * it under the terms of the GNU Affero General Public License as published
6
+ * by the Free Software Foundation, either version 3 of the License, or
7
+ * (at your option) any later version.
8
+ *
9
+ * This program is distributed in the hope that it will be useful,
10
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
11
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12
+ * GNU Affero General Public License for more details.
13
+ *
14
+ * You should have received a copy of the GNU Affero General Public License
15
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
16
+ ********************************************************************************/
17
+
18
+ // Commercial Licensing Information:
19
+ // For commercial use of this software without the copyleft provisions of the AGPLv3,
20
+ // you must obtain a commercial license from CoCreate LLC.
21
+ // For details, visit <https://cocreate.app/licenses/> or contact us at sales@cocreate.app.
22
+
23
+ import Observer from '@cocreate/Observer';
24
+ import Crud from '@cocreate/crud-client';
25
+ import Elements from '@cocreate/elements';
26
+ import Actions from '@cocreate/Actions';
4
27
  import render from '@cocreate/render';
28
+ import { queryElements } from '@cocreate/utils';
5
29
  import '@cocreate/element-prototype';
6
30
 
7
- let inputs = new Map();
31
+ const inputs = new Map();
32
+ const Files = new Map();
8
33
 
9
34
  function init(elements) {
10
35
  // Returns an array of elements.
11
36
  if (!elements)
12
37
  elements = document.querySelectorAll('[type="file"]')
13
38
 
14
- // If elements is an array of elements returns an array of elements.
39
+ // If elements is an not array of elements returns an array of elements.
15
40
  else if (!Array.isArray(elements))
16
41
  elements = [elements]
17
42
  for (let i = 0; i < elements.length; i++) {
18
43
  if (elements[i].tagName !== 'INPUT') {
19
44
  // TODO: create input and append to div if input dos not exist
45
+ // check if input exist
46
+ let input = document.createElement("input");
47
+ input.type = "file";
48
+ input.setAttribute('hidden', '')
49
+ elements[i].appendChild(input);
20
50
  }
21
- elements[i].getValue = async () => await getSelectedFiles([elements[i]], true)
51
+
52
+ elements[i].getValue = async () => await getFiles([elements[i]])
53
+ elements[i].getFiles = async () => await getFiles([elements[i]])
22
54
 
23
55
  // elements[i].setValue = (value) => pickr.setColor(value);
56
+
24
57
  if (elements[i].hasAttribute('directory')) {
25
58
  if (window.showDirectoryPicker)
26
- elements[i].addEventListener("click", selectDirectory);
59
+ elements[i].addEventListener("click", fileEvent);
27
60
  else if ('webkitdirectory' in elements[i]) {
28
61
  elements[i].webkitdirectory = true
29
- elements[i].addEventListener("change", handleFileInputChange)
62
+ elements[i].addEventListener("change", fileEvent)
30
63
  } else
31
64
  console.error("Directory selection not supported in this browser.");
32
65
  } else if (window.showOpenFilePicker)
33
- elements[i].addEventListener("click", selectFile);
66
+ elements[i].addEventListener("click", fileEvent);
34
67
  else
35
- elements[i].addEventListener("change", handleFileInputChange);
68
+ elements[i].addEventListener("change", fileEvent);
36
69
  }
37
70
  }
38
71
 
72
+ async function fileEvent(event) {
73
+ try {
74
+ const input = event.target;
75
+ let selected = inputs.get(input) || new Map()
76
+ let files = input.files;
77
+ if (!files.length) {
78
+ event.preventDefault()
79
+ const multiple = input.multiple
80
+ if (input.hasAttribute('directory')) {
81
+ let handle = await window.showDirectoryPicker();
82
+ let file = {
83
+ name: handle.name,
84
+ directory: '/',
85
+ path: '/' + handle.name,
86
+ type: 'text/directory',
87
+ 'content-type': 'text/directory'
88
+ }
89
+ file.input = input
90
+ file.id = await getFileId(file)
91
+ if (selected.has(file.id)) {
92
+ console.log('Duplicate file has been selected. This could be in error as the browser does not provide a clear way of checking duplictaes')
93
+ }
39
94
 
40
- function handleFileInputChange(event) {
41
- const input = event.target;
42
- const files = input.files;
43
- let selected = inputs.get(input) || []
44
- selected.push(...files)
45
- inputs.set(input, selected);
46
- console.log("Files selected:", files);
47
- renderFiles(input)
48
- }
95
+ file.handle = handle
96
+ selected.set(file.id, file)
97
+ Files.set(file.id, file)
49
98
 
50
- async function selectFile(event) {
51
- event.preventDefault()
52
- const input = event.target;
53
- let selected = inputs.get(input) || []
54
- try {
55
- const multiple = input.multiple
56
- const selectedFiles = await window.showOpenFilePicker({ multiple });
99
+ files = await getDirectoryHandles(handle, handle.name)
100
+ } else {
101
+ files = await window.showOpenFilePicker({ multiple });
102
+ }
103
+ }
57
104
 
58
- for (const handle of selectedFiles) {
59
- selected.push(handle)
105
+ for (let i = 0; i < files.length; i++) {
106
+ const handle = files[i]
107
+ if (files[i].kind === 'file') {
108
+ files[i] = await files[i].getFile();
109
+ files[i].handle = handle
110
+ } else if (files[i].kind === 'directory') {
111
+ files[i].handle = handle
112
+ }
113
+
114
+ if (!files[i].src)
115
+ files[i] = await readFile(files[i])
116
+
117
+ files[i].directory = handle.directory || '/'
118
+ files[i].parentDirectory = handle.parentDirectory || ''
119
+ files[i].path = handle.path || '/' + handle.name
120
+ files[i]['content-type'] = files[i].type
121
+ files[i].input = input
122
+ files[i].id = await getFileId(files[i])
123
+ if (selected.has(files[i].id)) {
124
+ console.log('Duplicate file has been selected. This could be in error as the browser does not provide a clear way of checking duplictaes')
125
+ }
126
+
127
+ selected.set(files[i].id, files[i])
128
+ Files.set(files[i].id, files[i])
60
129
  }
61
130
 
62
- if (selected.length) {
131
+ if (selected.size) {
63
132
  inputs.set(input, selected);
64
133
  console.log("Files selected:", selected);
65
- renderFiles(input)
66
- }
67
134
 
135
+ if (!input.renderValue)
136
+ input.renderValue(selected.values())
137
+ // render.render({
138
+ // source: input,
139
+ // data
140
+ // });
141
+
142
+ const isImport = input.getAttribute('import')
143
+ const isRealtime = input.getAttribute('realtime')
144
+ if (isRealtime !== 'false' && (isImport || isImport == "")) {
145
+ Import(input)
146
+ }
147
+
148
+ }
68
149
  } catch (error) {
69
150
  if (error.name !== 'AbortError') {
70
- console.error("Error selecting files:", error);
151
+ console.error("Error selecting directory:", error);
71
152
  }
72
153
  }
73
- }
74
154
 
75
- async function selectDirectory(event) {
76
- event.preventDefault()
77
- const input = event.target;
78
- let selected = inputs.get(input) || []
155
+ }
79
156
 
80
- try {
81
- const handle = await window.showDirectoryPicker();
82
- selected.push(handle)
157
+ async function getDirectoryHandles(handle, name) {
158
+ let handles = [];
159
+ for await (const entry of handle.values()) {
160
+ entry.directory = '/' + name
161
+ entry.parentDirectory = name.split("/").pop();
162
+ entry.path = '/' + name + '/' + entry.name
163
+ if (!entry.webkitRelativePath)
164
+ entry.webkitRelativePath = name
83
165
 
84
- if (selected.length) {
85
- inputs.set(input, selected);
86
- console.log("Directory selected:", selected);
87
- renderFiles(input)
88
- }
89
- } catch (error) {
90
- if (error.name !== 'AbortError') {
91
- console.error("Error selecting directory:", error);
166
+ if (entry.kind === 'file') {
167
+ handles.push(entry);
168
+ } else if (entry.kind === 'directory') {
169
+ entry.type = 'text/directory'
170
+ handles.push(entry);
171
+ const entries = await getDirectoryHandles(entry, name + '/' + entry.name);
172
+ handles = handles.concat(entries);
92
173
  }
93
174
  }
175
+ return handles;
94
176
  }
95
177
 
96
- async function getNewFileHandle() {
97
- // const options = {
98
- // types: [
99
- // {
100
- // description: 'Text Files',
101
- // accept: {
102
- // 'text/plain': ['.txt'],
103
- // },
104
- // },
105
- // ],
106
- // };
107
- const handle = await window.showSaveFilePicker(options);
108
- return handle;
178
+ async function getFileId(file) {
179
+
180
+ if (file.id = file.path || file.webkitRelativePath) {
181
+ return file.id;
182
+ } else {
183
+ const { name, size, type, lastModified } = file;
184
+ const key = `${name}${size}${type}${lastModified}`;
185
+
186
+ file.id = key
187
+ return key;
188
+ }
109
189
  }
110
190
 
111
- async function getSelectedFiles(fileInputs, isObject) {
191
+ async function getFiles(fileInputs) {
112
192
  const files = [];
113
193
 
114
194
  if (!Array.isArray(fileInputs))
115
195
  fileInputs = [fileInputs]
116
196
 
117
197
  for (let input of fileInputs) {
118
- const selected = inputs.get(input) || []
119
-
120
- for (let i = 0; i < selected.length; i++) {
121
- let file
122
- if (selected[i] instanceof FileSystemDirectoryHandle) {
123
- // The object is an instance of FileSystemFileHandle
124
- const handles = await getSelectedDirectoryFiles(selected[i], selected[i].name)
125
- for (let handle of handles) {
126
- if (handle.kind === 'file')
127
- file = await handle.getFile();
128
- else if (handle.kind === 'directory')
129
- file = { ...handle, name: handle.name }
130
- else continue
131
-
132
- if (isObject)
133
- file = await readFile(file)
134
-
135
- files.push(file)
136
- }
137
- } else {
138
- if (selected[i] instanceof FileSystemFileHandle) {
139
- // The object is an instance of FileSystemFileHandle
140
- file = await selected[i].getFile();
141
- } else {
142
- // The object is not an instance of FileSystemFileHandle
143
- console.log("It's not a FileSystemFileHandle object");
144
- file = selected[i]
145
- }
146
-
147
- if (isObject)
198
+ const selected = inputs.get(input)
199
+ if (selected) {
200
+ for (let file of selected.values()) {
201
+ if (!file.src)
148
202
  file = await readFile(file)
149
203
 
204
+ file = getCustomData({ ...file })
150
205
  files.push(file)
151
206
  }
152
-
153
207
  }
154
208
  }
155
209
 
156
210
  return files
157
211
  }
158
212
 
159
- async function getSelectedDirectoryFiles(handle, name) {
160
- let files = [];
161
- for await (const entry of handle.values()) {
162
- entry.directory = '/' + name
163
- entry.parentDirectory = name.split("/").pop();
164
- entry.path = '/' + name + '/' + entry.name
165
- if (!entry.webkitRelativePath)
166
- entry.webkitRelativePath = name
167
-
168
- if (entry.kind === 'file') {
169
- files.push(entry);
170
- } else if (entry.kind === 'directory') {
171
- entry.type = 'text/directory'
172
- files.push(entry);
173
- const entries = await getSelectedDirectoryFiles(entry, name + '/' + entry.name);
174
- files = files.concat(entries);
213
+ // gets file custom data
214
+ function getCustomData(file) {
215
+ let form = document.querySelector(`[file_id="${file.id}"]`);
216
+ if (form) {
217
+ let elements = form.querySelectorAll('[file]');
218
+ for (let i = 0; i < elements.length; i++) {
219
+ let name = elements[i].getAttribute('file')
220
+ if (name) {
221
+ file[name] = elements[i].getValue()
222
+ }
175
223
  }
176
224
  }
177
- return files;
225
+ return file;
178
226
  }
179
227
 
228
+
180
229
  // This function reads the file and returns its src
181
230
  function readFile(file) {
182
231
  // Return a new promise that resolves the file object
183
232
  return new Promise((resolve) => {
184
- file["content-type"] = file.type
185
-
186
233
  // Split the file type into an array
187
234
  const fileType = file.type.split('/');
188
235
  let readAs;
@@ -237,60 +284,389 @@ function readFile(file) {
237
284
  });
238
285
  }
239
286
 
240
- async function fileAction(btn, params, action) {
241
- const form = btn.closest('form')
242
- let inputs = form.querySelectorAll('input[type="file"]')
243
- let fileObjects = await getSelectedFiles(Array.from(inputs), true)
287
+ async function save(element, action, data) {
288
+ try {
289
+ if (!data)
290
+ data = []
291
+
292
+ if (!Array.isArray(element))
293
+ element = [element]
294
+
295
+ for (let i = 0; i < element.length; i++) {
296
+ const inputs = []
297
+ if (element[i].type === 'file')
298
+ inputs.push(element[i])
299
+ else if (element[i].tagName === 'form') {
300
+ let fileInputs = element[i].querySelectorAll('input[type="file"]')
301
+ inputs.push(...fileInputs)
302
+ } else {
303
+ const form = element[i].closest('form')
304
+ if (form)
305
+ inputs.push(...form.querySelectorAll('input[type="file"]'))
306
+ }
244
307
 
245
- console.log('fileObjects', fileObjects)
246
- document.dispatchEvent(new CustomEvent(action, {
247
- detail: {}
248
- }));
308
+ for (let input of inputs) {
309
+ let files = await getFiles(input)
310
+
311
+ for (let i = 0; i < files.length; i++) {
312
+ if (!files[i].src) continue
313
+
314
+ if (files[i].handle && action !== 'download') {
315
+ if (action === 'saveAs') {
316
+ if (files[i].kind === 'file') {
317
+ const options = {
318
+ suggestedName: files[i].name,
319
+ types: [
320
+ {
321
+ description: 'Text Files',
322
+ }
323
+ ],
324
+ };
325
+ files[i].handle = await window.showSaveFilePicker(options);
326
+ } else if (files[i].kind === 'directory') {
327
+ // Create a new subdirectory
328
+ files[i].handle = await files[i].handle.getDirectoryHandle('new_directory', { create: true });
329
+ return
330
+ }
331
+ }
332
+
333
+ if (files[i].handle.kind === 'directory') continue
334
+
335
+ const writable = await files[i].handle.createWritable();
336
+ await writable.write(files[i].src);
337
+ await writable.close();
338
+
339
+ } else {
340
+ const blob = new Blob([files[i].src], { type: files[i].type });
341
+
342
+ // Create a temporary <a> element to trigger the file download
343
+ const downloadLink = document.createElement('a');
344
+ downloadLink.href = URL.createObjectURL(blob);
345
+ downloadLink.download = files[i].name;
346
+
347
+ // Trigger the download
348
+ downloadLink.click();
349
+ }
350
+
351
+ }
352
+ }
353
+
354
+ let queryElements = queryElements({ element: element[i], prefix: action })
355
+ if (queryElements) {
356
+ save(queryElements, action, data)
357
+ }
358
+ }
359
+ return data
249
360
 
361
+ } catch (error) {
362
+ if (error.name !== 'AbortError') {
363
+ console.error("Error selecting files:", error);
364
+ }
365
+ }
250
366
  }
251
367
 
252
- // may be best to use getValue() so form so inputtype files can be can be managed in forms
253
- async function save(inputs, collection, document_id) {
254
- let files = await getSelectedFiles(inputs, true)
368
+ async function upload(element, data) {
369
+ if (!data)
370
+ data = []
371
+
372
+ if (!Array.isArray(element))
373
+ element = [element]
374
+
375
+ for (let i = 0; i < element.length; i++) {
376
+ const inputs = []
377
+ if (element[i].type === 'file')
378
+ inputs.push(element[i])
379
+ else if (element[i].tagName === 'form') {
380
+ let fileInputs = element[i].querySelectorAll('input[type="file"]')
381
+ inputs.push(...fileInputs)
382
+ } else {
383
+ const form = element[i].closest('form')
384
+ if (form)
385
+ inputs.push(...form.querySelectorAll('input[type="file"]'))
386
+ }
255
387
 
256
- let response = await crud.updateDocument({
257
- collection,
258
- document: files,
259
- upsert: true
260
- });
388
+ for (let input of inputs) {
389
+ let Data = Elements.getObject(input);
390
+ if (Data.type) {
391
+ if (input.getFilter)
392
+ Data.filter = input.getFilter()
393
+
394
+ let files = await getFiles(input)
395
+
396
+ let key = getAttribute('key')
397
+ if (Data.type === 'key')
398
+ Data.type = 'object'
399
+
400
+ if (Data.type === 'object') {
401
+ let object = input.getAttribute('object')
402
+ if (key) {
403
+ Data[Data.type] = { _id: object, [key]: files }
404
+ } else {
405
+ Data[Data.type] = files
406
+ }
407
+ }
408
+
409
+ let action = 'update' + Data.type.charAt(0).toUpperCase() + Data.type.slice(1)
410
+ if (Crud[action]) {
411
+ let response = await Crud[action](Data)({
412
+ array,
413
+ object,
414
+ upsert: true
415
+ });
416
+
417
+ data.push(response)
418
+ if (response && (!object || object !== response.object)) {
419
+ Elements.setTypeValue(element, response);
420
+ }
421
+ }
422
+ }
423
+ }
261
424
 
262
- if (response && (!document_id || document_id !== response.document_id)) {
263
- crud.setDocumentId(element, collection, response.document_id);
425
+ let queriedElements = queryElements({ element: element[i], prefix: 'upload' })
426
+ if (queriedElements) {
427
+ upload(queriedElements, data)
428
+ }
264
429
  }
430
+ return data
431
+ }
432
+
433
+ async function Import(element, data) {
434
+ if (!data)
435
+ data = []
436
+
437
+ if (!Array.isArray(element))
438
+ element = [element]
439
+
440
+ for (let i = 0; i < element.length; i++) {
441
+ const inputs = []
442
+ if (element[i].type === 'file')
443
+ inputs.push(element[i])
444
+ else if (element[i].tagName === 'form') {
445
+ let fileInputs = element[i].querySelectorAll('input[type="file"]')
446
+ inputs.push(...fileInputs)
447
+ } else {
448
+ const form = element[i].closest('form')
449
+ if (form)
450
+ inputs.push(...form.querySelectorAll('input[type="file"]'))
451
+ }
452
+
453
+ if (inputs.length) {
454
+ let Data = await getFiles(inputs)
455
+ Data.reduce((result, { src }) => {
456
+ try {
457
+ const parsedSrc = JSON.parse(src);
458
+ if (Array.isArray(parsedSrc))
459
+ data.push(...parsedSrc);
460
+ else
461
+ data.push(parsedSrc);
462
+ } catch (error) {
463
+ console.error(`Error parsing JSON: ${error}`);
464
+ }
465
+ return result;
466
+ }, []);
467
+
468
+ }
469
+
470
+ if (element[i].type !== 'file') {
471
+ let Data = Elements.getObject(element[i]);
472
+ if (Data.type) {
473
+ if (element[i].getFilter)
474
+ Data.filter = element[i].getFilter()
475
+
476
+ if (Data.type === 'key')
477
+ Data.type = 'object'
478
+
479
+ data.push(Data)
480
+ }
481
+ }
482
+
483
+ if (data.length) {
484
+ for (let i = 0; i < data.length; i++) {
485
+ let action = 'create' + data[i].type.charAt(0).toUpperCase() + data[i].type.slice(1)
486
+ if (Crud[action]) {
487
+ data[i] = await Crud[action](data[i])
488
+ }
489
+ }
490
+ }
265
491
 
266
- return response
492
+ let queriedElements = queryElements({ element: element[i], prefix: 'import' })
493
+ if (queriedElements) {
494
+ Import(queriedElements, data)
495
+ }
496
+ }
497
+ return data
267
498
  }
268
499
 
269
- async function getFiles(inputs) {
270
- let files = await getSelectedFiles(inputs)
271
- return files
500
+ async function Export(element, data) {
501
+ if (!data)
502
+ data = []
503
+
504
+ if (!Array.isArray(element))
505
+ element = [element]
506
+
507
+ for (let i = 0; i < element.length; i++) {
508
+ const inputs = []
509
+ if (element[i].type === 'file')
510
+ inputs.push(element[i])
511
+ else if (element[i].tagName === 'form') {
512
+ let fileInputs = element[i].querySelectorAll('input[type="file"]')
513
+ inputs.push(...fileInputs)
514
+ } else {
515
+ const form = element[i].closest('form')
516
+ if (form)
517
+ inputs.push(...form.querySelectorAll('input[type="file"]'))
518
+ }
519
+
520
+ if (inputs.length)
521
+ data.push(...getFiles(inputs))
522
+
523
+ let Data = Elements.getObject(element[i]);
524
+ if (Data.type) {
525
+ if (element[i].getFilter)
526
+ Data.filter = element[i].getFilter()
527
+
528
+ if (Data.type === 'key')
529
+ Data.type = 'object'
530
+ let action = 'read' + Data.type.charAt(0).toUpperCase() + Data.type.slice(1)
531
+ if (Crud[action]) {
532
+ Data = await Crud[action](Data)
533
+ data.push(...Data[Data.type])
534
+ }
535
+ }
536
+
537
+ let queriedElements = queryElements({ element: element[i], prefix: 'export' })
538
+ if (queriedElements) {
539
+ Export(queriedElements, data)
540
+ }
541
+
542
+ }
543
+
544
+ if (data.length)
545
+ exportFile(data);
546
+
547
+ return data
548
+ }
549
+
550
+ async function exportFile(data) {
551
+ let name = data.type || 'download';
552
+ let exportData = JSON.stringify(data, null, 2);
553
+ let blob = new Blob([exportData], { type: "application/json" });
554
+ let url = URL.createObjectURL(blob);
555
+
556
+ let link = document.createElement("a");
557
+
558
+ link.href = url;
559
+ link.download = name;
560
+
561
+ document.body.appendChild(link);
562
+
563
+ link.dispatchEvent(
564
+ new MouseEvent('click', {
565
+ bubbles: true,
566
+ cancelable: true,
567
+ view: window
568
+ })
569
+ );
570
+
571
+ URL.revokeObjectURL(url);
572
+ link.remove();
272
573
  }
273
574
 
274
- async function getObjects(inputs) {
275
- let objects = await getSelectedFiles(inputs, true)
276
- return objects
575
+ async function fileRenderAction(action) {
576
+ const element = action.element
577
+
578
+ let file_id = element.getAttribute('file_id');
579
+ if (!file_id) {
580
+ const closestElement = element.closest('[file_id]');
581
+ if (closestElement)
582
+ file_id = closestElement.getAttribute('file_id');
583
+ }
584
+
585
+ let input = Files.get(file_id).input
586
+
587
+ if (!file_id || !input) return
588
+
589
+ let file = inputs.get(input).get(file_id)
590
+ if (!file) return
591
+
592
+ if (action.name === 'createFile') {
593
+ let name = element.getAttribute('value')
594
+ create(file, 'file', name)
595
+ } else if (action.name === 'deleteFile')
596
+ Delete(file)
597
+ else if (action.name === 'createDirectory') {
598
+ let name = element.getAttribute('value')
599
+ create(file, 'directory', name)
600
+ } else if (action.name === 'deleteDirectory')
601
+ Delete(file)
602
+
603
+ document.dispatchEvent(new CustomEvent(action.name, {
604
+ detail: {}
605
+ }));
606
+
277
607
  }
278
608
 
279
- function renderFiles(input) {
280
- // TODO: support
281
- let template_id = input.getAttribute('template_id')
282
- if (template_id) {
283
- // if data items are handle it will not yet have all the details
284
- const data = inputs.get(input)
285
- if (data.length) return
286
- render.data({
287
- selector: `[template='${template_id}']`,
288
- data
289
- });
609
+ async function create(directory, type, name, src = "") {
610
+ try {
611
+ if (directory.handle && directory.input) {
612
+ if (!name) {
613
+ const name = prompt('Enter the file name:');
614
+ if (!name) {
615
+ console.log('Invalid file name.');
616
+ return;
617
+ }
618
+
619
+ }
620
+
621
+ let handle, file
622
+ if (type === 'directory') {
623
+ handle = await directory.handle.getDirectoryHandle(name, { create: true });
624
+ file = { name: handle.name, type: 'text/directory' }
625
+ } else if (type === 'file') {
626
+ handle = await directory.handle.getFileHandle(name, { create: true });
627
+ const writable = await handle.createWritable();
628
+
629
+ // Write data to the new file...
630
+ await writable.write(src);
631
+ await writable.close();
632
+
633
+ file = handle.getFile()
634
+ }
635
+
636
+ if (directory.input) {
637
+ file.directory = directory.path
638
+ file.parentDirectory = directory.name
639
+ file.path = directory.path + '/' + file.name
640
+ file.input = directory.input
641
+ file.handle = handle
642
+ file['content-type'] = file.type
643
+
644
+ file.id = await getFileId(file)
645
+ if (inputs.get(directory.input).has(file.id)) {
646
+ console.log('Duplicate file has been selected. This could be in error as the browser does not provide a clear way of checking duplictaes')
647
+ }
648
+
649
+ inputs.get(directory.input).set(file.id, file)
650
+ }
651
+ }
652
+ } catch (error) {
653
+ console.log('Error adding file:', error);
290
654
  }
291
655
  }
292
656
 
293
- observer.init({
657
+ async function Delete(file) {
658
+ try {
659
+ if (file.handle) {
660
+ await file.handle.remove();
661
+ if (file.input && file.id)
662
+ inputs.get(file.input).delete(file.id)
663
+ }
664
+ } catch (error) {
665
+ console.log('Error deleting file:', error);
666
+ }
667
+ }
668
+
669
+ Observer.init({
294
670
  name: 'CoCreateFileAddedNodes',
295
671
  observe: ['addedNodes'],
296
672
  target: 'input[type="file"]',
@@ -298,7 +674,7 @@ observer.init({
298
674
 
299
675
  });
300
676
 
301
- observer.init({
677
+ Observer.init({
302
678
  name: 'CoCreateFileAttributes',
303
679
  observe: ['attributes'],
304
680
  attributeName: ['type'],
@@ -306,13 +682,36 @@ observer.init({
306
682
  callback: mutation => init(mutation.target)
307
683
  });
308
684
 
309
- action.init({
310
- name: "upload",
311
- callback: (btn, params) => {
312
- fileAction(btn, params, "upload")
685
+ Actions.init([
686
+ {
687
+ name: ["upload", "download", "saveLocally", "import", "export"],
688
+ callback: (action) => {
689
+ if (action.name === 'upload')
690
+ upload(action.element)
691
+ else if (action.name === 'saveLocally' || action.name === 'saveAs') {
692
+ save(action.element)
693
+ } else if (action.name === 'export') {
694
+ Export(action.element)
695
+ } else if (action.name === 'import') {
696
+ Import(action.element)
697
+ } else {
698
+ // Something...
699
+ }
700
+
701
+ document.dispatchEvent(new CustomEvent(action.name, {
702
+ detail: {}
703
+ }));
704
+
705
+ }
706
+ },
707
+ {
708
+ name: ["createFile", "deleteFile", "createDirectory", "deleteDirectory"],
709
+ callback: (action) => {
710
+ fileRenderAction(action)
711
+ }
313
712
  }
314
- })
713
+ ])
315
714
 
316
715
  init()
317
716
 
318
- export default { getFiles, getObjects }
717
+ export default { inputs, getFiles, create, Delete }