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.
- package/CHANGELOG.md +23 -5
- package/README.md +19 -16
- package/agents.md +6 -0
- package/app/langs/en/buttons.json +17 -2
- package/app/langs/en/messages.json +36 -1
- package/app/langs/ru/buttons.json +17 -2
- package/app/langs/ru/messages.json +69 -34
- package/app/modules/module-fn.js +15 -9
- package/app/modules/vgfilepreview/index.js +3 -0
- package/app/modules/vgfilepreview/js/i18n.js +56 -0
- package/app/modules/vgfilepreview/js/renderers/image-modal.js +145 -0
- package/app/modules/vgfilepreview/js/renderers/image.js +92 -0
- package/app/modules/vgfilepreview/js/renderers/index.js +19 -0
- package/app/modules/vgfilepreview/js/renderers/office-modal.js +168 -0
- package/app/modules/vgfilepreview/js/renderers/office.js +79 -0
- package/app/modules/vgfilepreview/js/renderers/pdf-modal.js +260 -0
- package/app/modules/vgfilepreview/js/renderers/pdf.js +76 -0
- package/app/modules/vgfilepreview/js/renderers/playlist.js +71 -0
- package/app/modules/vgfilepreview/js/renderers/text-modal.js +343 -0
- package/app/modules/vgfilepreview/js/renderers/text.js +83 -0
- package/app/modules/vgfilepreview/js/renderers/video-modal.js +272 -0
- package/app/modules/vgfilepreview/js/renderers/video.js +80 -0
- package/app/modules/vgfilepreview/js/renderers/zip-modal.js +522 -0
- package/app/modules/vgfilepreview/js/renderers/zip.js +89 -0
- package/app/modules/vgfilepreview/js/vgfilepreview.js +594 -0
- package/app/modules/vgfilepreview/readme.md +68 -0
- package/app/modules/vgfilepreview/scss/_variables.scss +113 -0
- package/app/modules/vgfilepreview/scss/vgfilepreview.scss +460 -0
- package/app/modules/vgfiles/js/base.js +463 -175
- package/app/modules/vgfiles/js/droppable.js +260 -260
- package/app/modules/vgfiles/js/render.js +153 -153
- package/app/modules/vgfiles/js/vgfiles.js +41 -29
- package/app/modules/vgfiles/readme.md +116 -217
- package/app/modules/vgfiles/scss/_variables.scss +18 -10
- package/app/modules/vgfiles/scss/vgfiles.scss +153 -59
- package/app/modules/vgformsender/js/vgformsender.js +13 -13
- package/app/modules/vgmodal/js/vgmodal.js +12 -0
- package/app/modules/vgnav/js/vgnav.js +135 -135
- package/app/modules/vgnav/readme.md +67 -67
- package/app/modules/vgnestable/README.md +307 -307
- package/app/modules/vgnestable/scss/_variables.scss +60 -60
- package/app/modules/vgnestable/scss/vgnestable.scss +163 -163
- package/app/modules/vgselect/js/vgselect.js +39 -39
- package/app/modules/vgselect/scss/vgselect.scss +22 -22
- package/app/modules/vgspy/readme.md +28 -28
- package/app/utils/js/components/audio-metadata.js +240 -0
- package/app/utils/js/components/file-icon.js +109 -0
- package/app/utils/js/components/file-preview.js +304 -0
- package/app/utils/js/components/sanitize.js +150 -150
- package/build/vgapp.css +1 -1
- package/build/vgapp.css.map +1 -1
- package/build/vgapp.js.map +1 -1
- package/index.js +1 -0
- package/index.scss +9 -6
- 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.
|
|
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)
|
|
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
|
-
|
|
780
|
-
|
|
781
|
-
|
|
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;
|