vgapp 1.1.2 → 1.1.4

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.
Files changed (55) hide show
  1. package/CHANGELOG.md +23 -5
  2. package/README.md +19 -16
  3. package/agents.md +6 -0
  4. package/app/langs/en/buttons.json +17 -2
  5. package/app/langs/en/messages.json +36 -1
  6. package/app/langs/ru/buttons.json +17 -2
  7. package/app/langs/ru/messages.json +69 -34
  8. package/app/modules/module-fn.js +15 -9
  9. package/app/modules/vgfilepreview/index.js +3 -0
  10. package/app/modules/vgfilepreview/js/i18n.js +56 -0
  11. package/app/modules/vgfilepreview/js/renderers/image-modal.js +145 -0
  12. package/app/modules/vgfilepreview/js/renderers/image.js +92 -0
  13. package/app/modules/vgfilepreview/js/renderers/index.js +19 -0
  14. package/app/modules/vgfilepreview/js/renderers/office-modal.js +168 -0
  15. package/app/modules/vgfilepreview/js/renderers/office.js +79 -0
  16. package/app/modules/vgfilepreview/js/renderers/pdf-modal.js +260 -0
  17. package/app/modules/vgfilepreview/js/renderers/pdf.js +76 -0
  18. package/app/modules/vgfilepreview/js/renderers/playlist.js +71 -0
  19. package/app/modules/vgfilepreview/js/renderers/text-modal.js +343 -0
  20. package/app/modules/vgfilepreview/js/renderers/text.js +83 -0
  21. package/app/modules/vgfilepreview/js/renderers/video-modal.js +272 -0
  22. package/app/modules/vgfilepreview/js/renderers/video.js +80 -0
  23. package/app/modules/vgfilepreview/js/renderers/zip-modal.js +522 -0
  24. package/app/modules/vgfilepreview/js/renderers/zip.js +89 -0
  25. package/app/modules/vgfilepreview/js/vgfilepreview.js +594 -0
  26. package/app/modules/vgfilepreview/readme.md +68 -0
  27. package/app/modules/vgfilepreview/scss/_variables.scss +113 -0
  28. package/app/modules/vgfilepreview/scss/vgfilepreview.scss +460 -0
  29. package/app/modules/vgfiles/js/base.js +463 -175
  30. package/app/modules/vgfiles/js/droppable.js +260 -260
  31. package/app/modules/vgfiles/js/render.js +153 -153
  32. package/app/modules/vgfiles/js/vgfiles.js +41 -29
  33. package/app/modules/vgfiles/readme.md +116 -217
  34. package/app/modules/vgfiles/scss/_variables.scss +18 -10
  35. package/app/modules/vgfiles/scss/vgfiles.scss +153 -59
  36. package/app/modules/vgformsender/js/vgformsender.js +13 -13
  37. package/app/modules/vgmodal/js/vgmodal.js +12 -0
  38. package/app/modules/vgnav/js/vgnav.js +135 -135
  39. package/app/modules/vgnav/readme.md +67 -67
  40. package/app/modules/vgnestable/README.md +307 -307
  41. package/app/modules/vgnestable/scss/_variables.scss +60 -60
  42. package/app/modules/vgnestable/scss/vgnestable.scss +163 -163
  43. package/app/modules/vgselect/js/vgselect.js +39 -39
  44. package/app/modules/vgselect/scss/vgselect.scss +22 -22
  45. package/app/modules/vgspy/readme.md +28 -28
  46. package/app/utils/js/components/audio-metadata.js +240 -0
  47. package/app/utils/js/components/file-icon.js +109 -0
  48. package/app/utils/js/components/file-preview.js +304 -0
  49. package/app/utils/js/components/sanitize.js +150 -150
  50. package/build/vgapp.css +1 -1
  51. package/build/vgapp.css.map +1 -1
  52. package/build/vgapp.js.map +1 -1
  53. package/index.js +1 -0
  54. package/index.scss +9 -6
  55. package/package.json +1 -1
@@ -1,154 +1,154 @@
1
- import { isElement, normalizeData } from "../../../utils/js/functions";
2
- import Params from "../../../utils/js/components/params";
3
- import Selectors from "../../../utils/js/dom/selectors";
4
- import { Manipulator } from "../../../utils/js/dom/manipulator";
5
-
6
- class VGFilesTemplateRender {
7
- constructor(vgFilesInstance, element, params = {}) {
8
- this.module = vgFilesInstance;
9
- this.element = isElement(element) ? element : null;
10
-
11
- if (!this.element) {
12
- console.error('Invalid element provided:', element);
13
- return;
14
- }
15
-
16
- this._params = new Params(params, element).get();
17
- this._nodes = {
18
- info: this.module._nodes.info,
19
- drop: this.module._nodes.drop
20
- };
21
-
22
- this.bufferTemplate = '';
23
- this.parsedFiles = [];
24
- }
25
-
26
- init() {
27
- const $targetNode = this._nodes.info || this._nodes.drop;
28
- if (!$targetNode) return false;
29
-
30
- const area = this._nodes.info ? 'info' : 'drop';
31
- return this._nativeRenderFiles(area, $targetNode);
32
- }
33
-
34
- _nativeRenderFiles(area, $node) {
35
- const $list = Selectors.find(`.vg-files-${area}--list`, $node);
36
- if (!$list) return false;
37
-
38
- const $items = Array.from($list.children).filter(li => li.tagName === 'LI');
39
- if ($items.length === 0) return false;
40
-
41
- this._setTemplateInBuffer($items);
42
- if (!this.bufferTemplate) return false;
43
-
44
- this.parsedFiles = $items
45
- .map(li => {
46
- const rawData = Manipulator.get(li, 'data-file');
47
- if (!rawData) return null;
48
-
49
- return this._parseDataFile(rawData);
50
- })
51
- .filter(Boolean);
52
-
53
- return true;
54
- }
55
-
56
- _parseDataFile(rawData) {
57
- const dataFile = normalizeData(rawData);
58
- if (!dataFile || typeof dataFile !== 'object' || Array.isArray(dataFile)) return null;
59
-
60
- const binaryMeta = this._extractBinaryMeta(dataFile);
61
- const name = this._toStringOrNull(dataFile.name);
62
- const id = this._toStringOrNull(dataFile.id);
63
- const src = this._toStringOrNull(dataFile.src);
64
- const type = this._toStringOrNull(dataFile.type) || binaryMeta.type || 'application/octet-stream';
65
- const size = this._toNumberOrNull(dataFile.size) ?? binaryMeta.size ?? 0;
66
- const lastModified = this._toNumberOrNull(dataFile.lastModified ?? dataFile['last-modified']) ?? binaryMeta.lastModified ?? Date.now();
67
-
68
- const result = {
69
- id,
70
- name,
71
- size,
72
- type,
73
- src,
74
- lastModified
75
- };
76
-
77
- if (dataFile.image !== undefined && dataFile.image !== null && dataFile.image !== '') {
78
- result.image = dataFile.image;
79
- }
80
-
81
- const requiredKeys = ['id', 'name', 'size', 'type', 'src'];
82
- const isValid = requiredKeys.every((key) => {
83
- const value = result[key];
84
- if (key === 'size') return Number.isFinite(value);
85
- return value !== undefined && value !== null && value !== '';
86
- });
87
-
88
- if (!isValid) return null;
89
-
90
- const customData = {};
91
- const reserved = new Set(['id', 'name', 'size', 'type', 'src', 'image', 'lastModified', 'last-modified']);
92
-
93
- Object.entries(dataFile).forEach(([key, value]) => {
94
- if (reserved.has(key)) return;
95
- if (value === undefined || value === null || value === '') return;
96
- customData[key] = value;
97
- });
98
-
99
- if (Object.keys(customData).length) {
100
- result.customData = customData;
101
- }
102
-
103
- return result;
104
- }
105
-
106
- _extractBinaryMeta(dataFile) {
107
- const binary = dataFile.file || dataFile.blob || dataFile.originFile || null;
108
- if (!(binary instanceof Blob)) return {};
109
-
110
- const size = this._toNumberOrNull(binary.size);
111
- const type = this._toStringOrNull(binary.type);
112
- const lastModified = (binary instanceof File)
113
- ? this._toNumberOrNull(binary.lastModified)
114
- : null;
115
-
116
- return {
117
- size: size ?? null,
118
- type: type || null,
119
- lastModified: lastModified ?? null
120
- };
121
- }
122
-
123
- _toStringOrNull(value) {
124
- if (value === undefined || value === null) return null;
125
- const normalized = String(value).trim();
126
- return normalized ? normalized : null;
127
- }
128
-
129
- _toNumberOrNull(value) {
130
- if (value === undefined || value === null || value === '') return null;
131
- const normalized = Number(value);
132
- return Number.isFinite(normalized) ? normalized : null;
133
- }
134
-
135
- _setTemplateInBuffer($items) {
136
- if (this.bufferTemplate || $items.length === 0) return;
137
-
138
- const firstItem = $items[0];
139
-
140
- if (!Manipulator.has(firstItem, 'data-file')) {
141
- this.bufferTemplate = firstItem.outerHTML;
142
- firstItem.remove();
143
- } else {
144
- this.bufferTemplate = firstItem.outerHTML;
145
- }
146
- }
147
-
148
- dispose() {
149
- this.bufferTemplate = '';
150
- this.parsedFiles = [];
151
- }
152
- }
153
-
1
+ import { isElement, normalizeData } from "../../../utils/js/functions";
2
+ import Params from "../../../utils/js/components/params";
3
+ import Selectors from "../../../utils/js/dom/selectors";
4
+ import { Manipulator } from "../../../utils/js/dom/manipulator";
5
+
6
+ class VGFilesTemplateRender {
7
+ constructor(vgFilesInstance, element, params = {}) {
8
+ this.module = vgFilesInstance;
9
+ this.element = isElement(element) ? element : null;
10
+
11
+ if (!this.element) {
12
+ console.error('Invalid element provided:', element);
13
+ return;
14
+ }
15
+
16
+ this._params = new Params(params, element).get();
17
+ this._nodes = {
18
+ info: this.module._nodes.info,
19
+ drop: this.module._nodes.drop
20
+ };
21
+
22
+ this.bufferTemplate = '';
23
+ this.parsedFiles = [];
24
+ }
25
+
26
+ init() {
27
+ const $targetNode = this._nodes.info || this._nodes.drop;
28
+ if (!$targetNode) return false;
29
+
30
+ const area = this._nodes.info ? 'info' : 'drop';
31
+ return this._nativeRenderFiles(area, $targetNode);
32
+ }
33
+
34
+ _nativeRenderFiles(area, $node) {
35
+ const $list = Selectors.find(`.vg-files-${area}--list`, $node);
36
+ if (!$list) return false;
37
+
38
+ const $items = Array.from($list.children).filter(li => li.tagName === 'LI');
39
+ if ($items.length === 0) return false;
40
+
41
+ this._setTemplateInBuffer($items);
42
+ if (!this.bufferTemplate) return false;
43
+
44
+ this.parsedFiles = $items
45
+ .map(li => {
46
+ const rawData = Manipulator.get(li, 'data-file');
47
+ if (!rawData) return null;
48
+
49
+ return this._parseDataFile(rawData);
50
+ })
51
+ .filter(Boolean);
52
+
53
+ return true;
54
+ }
55
+
56
+ _parseDataFile(rawData) {
57
+ const dataFile = normalizeData(rawData);
58
+ if (!dataFile || typeof dataFile !== 'object' || Array.isArray(dataFile)) return null;
59
+
60
+ const binaryMeta = this._extractBinaryMeta(dataFile);
61
+ const name = this._toStringOrNull(dataFile.name);
62
+ const id = this._toStringOrNull(dataFile.id);
63
+ const src = this._toStringOrNull(dataFile.src);
64
+ const type = this._toStringOrNull(dataFile.type) || binaryMeta.type || 'application/octet-stream';
65
+ const size = this._toNumberOrNull(dataFile.size) ?? binaryMeta.size ?? 0;
66
+ const lastModified = this._toNumberOrNull(dataFile.lastModified ?? dataFile['last-modified']) ?? binaryMeta.lastModified ?? Date.now();
67
+
68
+ const result = {
69
+ id,
70
+ name,
71
+ size,
72
+ type,
73
+ src,
74
+ lastModified
75
+ };
76
+
77
+ if (dataFile.image !== undefined && dataFile.image !== null && dataFile.image !== '') {
78
+ result.image = dataFile.image;
79
+ }
80
+
81
+ const requiredKeys = ['id', 'name', 'size', 'type', 'src'];
82
+ const isValid = requiredKeys.every((key) => {
83
+ const value = result[key];
84
+ if (key === 'size') return Number.isFinite(value);
85
+ return value !== undefined && value !== null && value !== '';
86
+ });
87
+
88
+ if (!isValid) return null;
89
+
90
+ const customData = {};
91
+ const reserved = new Set(['id', 'name', 'size', 'type', 'src', 'image', 'lastModified', 'last-modified']);
92
+
93
+ Object.entries(dataFile).forEach(([key, value]) => {
94
+ if (reserved.has(key)) return;
95
+ if (value === undefined || value === null || value === '') return;
96
+ customData[key] = value;
97
+ });
98
+
99
+ if (Object.keys(customData).length) {
100
+ result.customData = customData;
101
+ }
102
+
103
+ return result;
104
+ }
105
+
106
+ _extractBinaryMeta(dataFile) {
107
+ const binary = dataFile.file || dataFile.blob || dataFile.originFile || null;
108
+ if (!(binary instanceof Blob)) return {};
109
+
110
+ const size = this._toNumberOrNull(binary.size);
111
+ const type = this._toStringOrNull(binary.type);
112
+ const lastModified = (binary instanceof File)
113
+ ? this._toNumberOrNull(binary.lastModified)
114
+ : null;
115
+
116
+ return {
117
+ size: size ?? null,
118
+ type: type || null,
119
+ lastModified: lastModified ?? null
120
+ };
121
+ }
122
+
123
+ _toStringOrNull(value) {
124
+ if (value === undefined || value === null) return null;
125
+ const normalized = String(value).trim();
126
+ return normalized ? normalized : null;
127
+ }
128
+
129
+ _toNumberOrNull(value) {
130
+ if (value === undefined || value === null || value === '') return null;
131
+ const normalized = Number(value);
132
+ return Number.isFinite(normalized) ? normalized : null;
133
+ }
134
+
135
+ _setTemplateInBuffer($items) {
136
+ if (this.bufferTemplate || $items.length === 0) return;
137
+
138
+ const firstItem = $items[0];
139
+
140
+ if (!Manipulator.has(firstItem, 'data-file')) {
141
+ this.bufferTemplate = firstItem.outerHTML;
142
+ firstItem.remove();
143
+ } else {
144
+ this.bufferTemplate = firstItem.outerHTML;
145
+ }
146
+ }
147
+
148
+ dispose() {
149
+ this.bufferTemplate = '';
150
+ this.parsedFiles = [];
151
+ }
152
+ }
153
+
154
154
  export default VGFilesTemplateRender;
@@ -482,14 +482,14 @@ class VGFiles extends VGFilesBase {
482
482
  if (li) {
483
483
  this._setButtonElement(file);
484
484
 
485
- const fileRemove = Selectors.find('.file-remove', li);
486
- if (fileRemove) {
487
- fileRemove.innerHTML = '';
488
- fileRemove.appendChild(this._setButtonElement(file, true, 'failing'));
489
- Classes.add(li, CLASS_NAME_FAILING);
490
- }
491
- }
492
- }
485
+ const fileRemove = Selectors.find('.file-remove', li);
486
+ if (fileRemove) {
487
+ fileRemove.innerHTML = '';
488
+ fileRemove.appendChild(this._setFailingButtons(file));
489
+ Classes.add(li, CLASS_NAME_FAILING);
490
+ }
491
+ }
492
+ }
493
493
 
494
494
  const payload = { file: uploadData.file };
495
495
 
@@ -677,8 +677,15 @@ class VGFiles extends VGFilesBase {
677
677
  }
678
678
  });
679
679
 
680
- if (this._params.ajax && this._params.removes.single.route) {
681
- if (!id) return;
680
+ if (this._params.ajax && this._params.removes.single.route) {
681
+ if (!id) {
682
+ this._files = this._files.filter(f => !(f.name === name && f.size === size));
683
+ this._updateStatsAfterRemove();
684
+ this._files.length ? this.build() : this.clear(true);
685
+ emitRemove();
686
+ this._resetFileInput();
687
+ return;
688
+ }
682
689
 
683
690
  const routeBase = this._params.removes.single.route;
684
691
  const routeSeparator = routeBase.includes('?') ? '&' : '?';
@@ -768,31 +775,36 @@ class VGFiles extends VGFilesBase {
768
775
  return Selectors.find(`button[data-name="${file.name}"][data-size="${file.size}"]`, this._element);
769
776
  }
770
777
 
771
- _setButtonElement(file, isAjax = false, status = '') {
772
- let icon = getSVG('trash'), action = 'data-vg-dismiss';
773
- if (!this._params.info) icon = getSVG('cross');
774
- if (isAjax) {
775
- icon = getSVG('spinner');
776
- if (status === 'completed') icon = getSVG('check');
777
- else action = 'data-vg-reload';
778
- }
779
- if (this._failingUploadedKeys.has(this._getFileKey(file))) {
780
- icon = getSVG('spinner');
781
- action = 'data-vg-reload';
782
- }
783
-
784
- return this._tpl.button([
785
- this._tpl.i({}, icon, { isHTML: true })
786
- ], 'button', this._buildFileDataAttributes(file, {
778
+ _setButtonElement(file, isAjax = false, status = '') {
779
+ let icon = getSVG('trash'), action = 'data-vg-dismiss';
780
+ if (!this._params.info) icon = getSVG('cross');
781
+ if (isAjax) {
782
+ icon = getSVG('spinner');
783
+ if (status === 'completed') icon = getSVG('check');
784
+ else action = 'data-vg-reload';
785
+ }
786
+
787
+ return this._tpl.button([
788
+ this._tpl.i({}, icon, { isHTML: true })
789
+ ], 'button', this._buildFileDataAttributes(file, {
787
790
  type: 'button',
788
791
  [action]: 'file',
789
792
  'data-name': file.name,
790
793
  'data-size': file.size ?? 0,
791
794
  'data-type': file.type || '',
792
795
  'data-last-modified': file.lastModified || '',
793
- 'data-id': file.id || ''
794
- }));
795
- }
796
+ 'data-id': file.id || ''
797
+ }));
798
+ }
799
+
800
+ _setFailingButtons(file) {
801
+ const wrapper = this._tpl.div({ class: 'file-failing-actions' }, [
802
+ this._setButtonElement(file, true, 'failing'),
803
+ this._setButtonElement(file)
804
+ ]);
805
+
806
+ return wrapper;
807
+ }
796
808
 
797
809
  _renderStat() {
798
810
  if (!this._nodes.stat) return;