vgapp 1.3.0 → 1.3.1

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 (88) hide show
  1. package/README.md +133 -133
  2. package/app/langs/en/buttons.json +17 -17
  3. package/app/langs/en/messages.json +36 -36
  4. package/app/langs/ru/buttons.json +17 -17
  5. package/app/langs/ru/messages.json +36 -36
  6. package/app/modules/base-module.js +111 -111
  7. package/app/modules/vgalert/readme.md +105 -105
  8. package/app/modules/vgdynamictable/index.js +5 -5
  9. package/app/modules/vgdynamictable/js/editable.js +19 -19
  10. package/app/modules/vgdynamictable/js/filters.js +21 -21
  11. package/app/modules/vgdynamictable/js/fixed.js +179 -179
  12. package/app/modules/vgdynamictable/js/pagination.js +1 -1
  13. package/app/modules/vgdynamictable/js/search.js +12 -12
  14. package/app/modules/vgdynamictable/js/sortable.js +71 -71
  15. package/app/modules/vgdynamictable/js/summary-footer.js +28 -28
  16. package/app/modules/vgdynamictable/js/table-remote.js +79 -79
  17. package/app/modules/vgdynamictable/js/table-url-state.js +31 -31
  18. package/app/modules/vgdynamictable/js/utils/common.js +48 -48
  19. package/app/modules/vgdynamictable/js/vgdynamictable.js +268 -268
  20. package/app/modules/vgdynamictable/readme.md +250 -250
  21. package/app/modules/vgdynamictable/scss/_skeleton.scss +6 -6
  22. package/app/modules/vgdynamictable/scss/_sortable.scss +24 -24
  23. package/app/modules/vgdynamictable/scss/_table.scss +4 -4
  24. package/app/modules/vgdynamictable/scss/_variables.scss +79 -79
  25. package/app/modules/vgdynamictable/scss/vgdynamictable.scss +27 -27
  26. package/app/modules/vgfilepreview/js/i18n.js +56 -56
  27. package/app/modules/vgfilepreview/js/renderers/image-modal.js +145 -145
  28. package/app/modules/vgfilepreview/js/renderers/image.js +92 -92
  29. package/app/modules/vgfilepreview/js/renderers/index.js +19 -19
  30. package/app/modules/vgfilepreview/js/renderers/office-modal.js +168 -168
  31. package/app/modules/vgfilepreview/js/renderers/office.js +79 -79
  32. package/app/modules/vgfilepreview/js/renderers/pdf-modal.js +260 -260
  33. package/app/modules/vgfilepreview/js/renderers/pdf.js +76 -76
  34. package/app/modules/vgfilepreview/js/renderers/playlist.js +71 -71
  35. package/app/modules/vgfilepreview/js/renderers/text-modal.js +343 -343
  36. package/app/modules/vgfilepreview/js/renderers/text.js +83 -83
  37. package/app/modules/vgfilepreview/js/renderers/video-modal.js +272 -272
  38. package/app/modules/vgfilepreview/js/renderers/video.js +80 -80
  39. package/app/modules/vgfilepreview/js/renderers/zip-modal.js +522 -522
  40. package/app/modules/vgfilepreview/js/renderers/zip.js +89 -89
  41. package/app/modules/vgfilepreview/js/vgfilepreview.js +7 -7
  42. package/app/modules/vgfilepreview/readme.md +68 -68
  43. package/app/modules/vgfilepreview/scss/_variables.scss +113 -113
  44. package/app/modules/vgfilepreview/scss/vgfilepreview.scss +464 -464
  45. package/app/modules/vgfiles/js/base.js +26 -26
  46. package/app/modules/vgfiles/js/droppable.js +260 -260
  47. package/app/modules/vgfiles/js/render.js +153 -153
  48. package/app/modules/vgfiles/js/vgfiles.js +104 -104
  49. package/app/modules/vgfiles/readme.md +123 -123
  50. package/app/modules/vgfiles/scss/_variables.scss +18 -18
  51. package/app/modules/vgfiles/scss/vgfiles.scss +148 -148
  52. package/app/modules/vgformsender/js/hideshowpass.js +16 -16
  53. package/app/modules/vgformsender/scss/vgformsender.scss +34 -34
  54. package/app/modules/vgmodal/js/vgmodal.drag.js +332 -332
  55. package/app/modules/vgmodal/js/vgmodal.js +188 -188
  56. package/app/modules/vgmodal/js/vgmodal.resize.js +27 -27
  57. package/app/modules/vgmodal/scss/vgmodal.scss +14 -14
  58. package/app/modules/vgnav/js/vgnav.js +135 -135
  59. package/app/modules/vgnav/readme.md +67 -67
  60. package/app/modules/vgnestable/README.md +307 -307
  61. package/app/modules/vgnestable/scss/_variables.scss +60 -60
  62. package/app/modules/vgnestable/scss/vgnestable.scss +163 -163
  63. package/app/modules/vgrangeslider/js/skins.js +222 -222
  64. package/app/modules/vgrangeslider/js/vgrangeslider.js +704 -704
  65. package/app/modules/vgrangeslider/readme.md +523 -523
  66. package/app/modules/vgrangeslider/scss/_variables.scss +53 -53
  67. package/app/modules/vgrangeslider/scss/vgrangeslider.scss +240 -240
  68. package/app/modules/vgselect/js/vgselect.js +39 -39
  69. package/app/modules/vgselect/scss/vgselect.scss +22 -22
  70. package/app/modules/vgspy/readme.md +28 -28
  71. package/app/modules/vgtoast/readme.md +18 -18
  72. package/app/modules/vgtoast/scss/vgtoast.scss +48 -48
  73. package/app/modules/vgtooltip/js/vgtooltip.js +89 -89
  74. package/app/modules/vgtooltip/readme.md +181 -181
  75. package/app/utils/js/components/ajax.js +117 -117
  76. package/app/utils/js/components/audio-metadata.js +240 -240
  77. package/app/utils/js/components/backdrop.js +17 -17
  78. package/app/utils/js/components/file-icon.js +109 -109
  79. package/app/utils/js/components/file-preview.js +304 -304
  80. package/app/utils/js/components/sanitize.js +150 -150
  81. package/app/utils/js/components/video-metadata.js +140 -140
  82. package/app/vgapp.js +130 -107
  83. package/build/vgapp.css +2 -2
  84. package/build/vgapp.js +2 -2
  85. package/build/vgapp.js.LICENSE.txt +1 -1
  86. package/build/vgapp.js.map +1 -1
  87. package/index.js +14 -14
  88. package/package.json +1 -1
@@ -528,10 +528,10 @@ class VGFilesBase extends BaseModule {
528
528
  return;
529
529
  }
530
530
 
531
- if (existingNode) {
532
- VGFilePreview.stopActiveInlineAudioIfDetached([existingNode]);
533
- existingNode.remove();
534
- }
531
+ if (existingNode) {
532
+ VGFilePreview.stopActiveInlineAudioIfDetached([existingNode]);
533
+ existingNode.remove();
534
+ }
535
535
 
536
536
  const nextNode = this._createInfoListItem(file, i, $itemsTemplate, $itemsTemplateClasses, fileKey, signature);
537
537
  nextNodes.push(nextNode);
@@ -935,28 +935,28 @@ class VGFilesBase extends BaseModule {
935
935
  Selectors.findAll('[data-vg-files="generated"]', this._element).forEach(el => el.remove());
936
936
  }
937
937
 
938
- clear(resetInput = true) {
939
- const detachedNodes = [];
940
- if (this._nodes.info) {
941
- const $infoList = Selectors.find(`.${this._getClass('info-list')}`, this._element);
942
- if ($infoList?.children?.length) {
943
- detachedNodes.push(...Array.from($infoList.children));
944
- }
945
- }
946
- if (this._nodes.drop) {
947
- const $dropList = Selectors.find(`.${this._getClass('drop-list')}`, this._element);
948
- if ($dropList?.children?.length) {
949
- detachedNodes.push(...Array.from($dropList.children));
950
- }
951
- }
952
- if (detachedNodes.length) {
953
- VGFilePreview.stopActiveInlineAudioIfDetached(detachedNodes);
954
- }
955
-
956
- this._revokeUrls();
957
- if (resetInput) {
958
- this._resetFileInput();
959
- }
938
+ clear(resetInput = true) {
939
+ const detachedNodes = [];
940
+ if (this._nodes.info) {
941
+ const $infoList = Selectors.find(`.${this._getClass('info-list')}`, this._element);
942
+ if ($infoList?.children?.length) {
943
+ detachedNodes.push(...Array.from($infoList.children));
944
+ }
945
+ }
946
+ if (this._nodes.drop) {
947
+ const $dropList = Selectors.find(`.${this._getClass('drop-list')}`, this._element);
948
+ if ($dropList?.children?.length) {
949
+ detachedNodes.push(...Array.from($dropList.children));
950
+ }
951
+ }
952
+ if (detachedNodes.length) {
953
+ VGFilePreview.stopActiveInlineAudioIfDetached(detachedNodes);
954
+ }
955
+
956
+ this._revokeUrls();
957
+ if (resetInput) {
958
+ this._resetFileInput();
959
+ }
960
960
  this._cleanupFakeInputs();
961
961
  this._cleanupErrors();
962
962
  this._files = [];
@@ -13,11 +13,11 @@ const CLASS_NAME_DROP_HOVER = 'drop-hover';
13
13
  const NAME = 'drop-and-drop';
14
14
  const NAME_KEY = 'vg.drop-and-drop';
15
15
 
16
- class VGFilesDroppable extends BaseModule {
17
- /**
18
- * @param {HTMLElement} element
19
- * @param {Object} params
20
- */
16
+ class VGFilesDroppable extends BaseModule {
17
+ /**
18
+ * @param {HTMLElement} element
19
+ * @param {Object} params
20
+ */
21
21
  constructor(element, params = {}) {
22
22
  super(element, params);
23
23
  this._element = element;
@@ -31,15 +31,15 @@ class VGFilesDroppable extends BaseModule {
31
31
  static get NAME() { return NAME; }
32
32
  static get NAME_KEY() { return NAME_KEY; }
33
33
 
34
- _init() {
35
- VGFilesDroppable._instances.add(this);
36
- if (this._params?.smartdrop) {
37
- VGFilesDroppable._smartInstances.add(this);
38
- this._bindGlobalEvents();
39
- }
40
- this._findInput();
41
- this._setupEvents();
42
- }
34
+ _init() {
35
+ VGFilesDroppable._instances.add(this);
36
+ if (this._params?.smartdrop) {
37
+ VGFilesDroppable._smartInstances.add(this);
38
+ this._bindGlobalEvents();
39
+ }
40
+ this._findInput();
41
+ this._setupEvents();
42
+ }
43
43
 
44
44
  /**
45
45
  * Поиск связанного input[type="file"] внутри или рядом с drop-зоной
@@ -58,8 +58,8 @@ class VGFilesDroppable extends BaseModule {
58
58
  /**
59
59
  * Настройка событий перетаскивания
60
60
  */
61
- _setupEvents() {
62
- if (!isElement(this._element)) return;
61
+ _setupEvents() {
62
+ if (!isElement(this._element)) return;
63
63
 
64
64
  const isSortableDrag = (e) => {
65
65
  // 1) если sortable реально активен — на элементе есть класс dragging
@@ -69,76 +69,76 @@ class VGFilesDroppable extends BaseModule {
69
69
  let plain = '';
70
70
  try { plain = e.dataTransfer?.getData?.('text/plain') || ''; } catch (_) {}
71
71
  return plain === 'vgsortable';
72
- };
72
+ };
73
73
 
74
- EventHandler.on(this._element, 'dragover', (e) => {
75
- e.preventDefault();
76
- e.stopPropagation();
74
+ EventHandler.on(this._element, 'dragover', (e) => {
75
+ e.preventDefault();
76
+ e.stopPropagation();
77
77
 
78
78
  // ✅ Сортировка: НЕ подсвечиваем dropzone
79
- if (isSortableDrag(e)) {
80
- Classes.remove(this._element, [CLASS_NAME_DROP_ACTIVE, CLASS_NAME_DROP_HOVER]);
81
- VGFilesDroppable._setDropMessageTitleState(this._element, false);
82
- e.dataTransfer.dropEffect = 'none';
83
- return;
84
- }
79
+ if (isSortableDrag(e)) {
80
+ Classes.remove(this._element, [CLASS_NAME_DROP_ACTIVE, CLASS_NAME_DROP_HOVER]);
81
+ VGFilesDroppable._setDropMessageTitleState(this._element, false);
82
+ e.dataTransfer.dropEffect = 'none';
83
+ return;
84
+ }
85
85
 
86
86
  if (!Classes.has(this._element, CLASS_NAME_DROP_ACTIVE)) {
87
87
  Classes.add(this._element, CLASS_NAME_DROP_HOVER);
88
88
  }
89
89
  });
90
90
 
91
- EventHandler.on(this._element, 'dragenter', (e) => {
92
- e.preventDefault();
93
- e.stopPropagation();
91
+ EventHandler.on(this._element, 'dragenter', (e) => {
92
+ e.preventDefault();
93
+ e.stopPropagation();
94
94
 
95
95
  // ✅ Сортировка: НЕ подсвечиваем dropzone
96
- if (isSortableDrag(e)) {
97
- Classes.remove(this._element, [CLASS_NAME_DROP_ACTIVE, CLASS_NAME_DROP_HOVER]);
98
- VGFilesDroppable._setDropMessageTitleState(this._element, false);
99
- return;
100
- }
101
-
102
- Classes.add(this._element, [CLASS_NAME_DROP_ACTIVE, CLASS_NAME_DROP_HOVER]);
103
- VGFilesDroppable._setDropMessageTitleState(this._element, true);
104
- });
96
+ if (isSortableDrag(e)) {
97
+ Classes.remove(this._element, [CLASS_NAME_DROP_ACTIVE, CLASS_NAME_DROP_HOVER]);
98
+ VGFilesDroppable._setDropMessageTitleState(this._element, false);
99
+ return;
100
+ }
101
+
102
+ Classes.add(this._element, [CLASS_NAME_DROP_ACTIVE, CLASS_NAME_DROP_HOVER]);
103
+ VGFilesDroppable._setDropMessageTitleState(this._element, true);
104
+ });
105
105
 
106
106
  EventHandler.on(this._element, 'dragleave', (e) => {
107
107
  e.preventDefault();
108
108
  e.stopPropagation();
109
109
 
110
110
  // ✅ Сортировка: гарантированно без подсветки
111
- if (isSortableDrag(e)) {
112
- Classes.remove(this._element, [CLASS_NAME_DROP_ACTIVE, CLASS_NAME_DROP_HOVER]);
113
- VGFilesDroppable._setDropMessageTitleState(this._element, false);
114
- return;
115
- }
111
+ if (isSortableDrag(e)) {
112
+ Classes.remove(this._element, [CLASS_NAME_DROP_ACTIVE, CLASS_NAME_DROP_HOVER]);
113
+ VGFilesDroppable._setDropMessageTitleState(this._element, false);
114
+ return;
115
+ }
116
116
 
117
117
  if (e.target === this._element || e.target.closest('.' + CLASS_NAME_DROP) === this._element) {
118
118
  Classes.remove(this._element, CLASS_NAME_DROP_HOVER);
119
119
  setTimeout(() => {
120
- if (!this._element.matches(':hover')) {
121
- Classes.remove(this._element, CLASS_NAME_DROP_ACTIVE);
122
- VGFilesDroppable._setDropMessageTitleState(this._element, false);
123
- }
124
- }, 50);
125
- }
126
- });
127
-
128
- EventHandler.on(this._element, 'drop', (e) => {
129
- e.preventDefault();
130
- e.stopPropagation();
131
-
132
- Classes.remove(this._element, [CLASS_NAME_DROP_ACTIVE, CLASS_NAME_DROP_HOVER]);
133
- VGFilesDroppable._setDropMessageTitleState(this._element, false);
120
+ if (!this._element.matches(':hover')) {
121
+ Classes.remove(this._element, CLASS_NAME_DROP_ACTIVE);
122
+ VGFilesDroppable._setDropMessageTitleState(this._element, false);
123
+ }
124
+ }, 50);
125
+ }
126
+ });
127
+
128
+ EventHandler.on(this._element, 'drop', (e) => {
129
+ e.preventDefault();
130
+ e.stopPropagation();
131
+
132
+ Classes.remove(this._element, [CLASS_NAME_DROP_ACTIVE, CLASS_NAME_DROP_HOVER]);
133
+ VGFilesDroppable._setDropMessageTitleState(this._element, false);
134
134
 
135
135
  // ✅ сортировка: не трогаем input
136
- if (isSortableDrag(e)) {
137
- return;
138
- }
139
-
140
- const files = e.dataTransfer?.files;
141
- if (!files || !files.length) return;
136
+ if (isSortableDrag(e)) {
137
+ return;
138
+ }
139
+
140
+ const files = e.dataTransfer?.files;
141
+ if (!files || !files.length) return;
142
142
 
143
143
  this._files = files;
144
144
 
@@ -146,209 +146,209 @@ class VGFilesDroppable extends BaseModule {
146
146
  this._input.files = files;
147
147
  EventHandler.trigger(this._input, 'change');
148
148
  }
149
- });
150
- }
151
-
152
- _bindGlobalEvents() {
153
- if (VGFilesDroppable._isGlobalEventsBound) return;
154
-
155
- VGFilesDroppable._globalHandlers = {
156
- dragenter: (e) => this._updateSuggestedDrop(e),
157
- dragover: (e) => this._updateSuggestedDrop(e),
158
- dragleave: (e) => {
159
- if (!this._isFileDrag(e)) return;
160
- if (e.relatedTarget === null || e.target === document || e.target === document.documentElement) {
161
- VGFilesDroppable._clearSuggestedDrop();
162
- }
163
- },
164
- drop: (e) => {
165
- if (!this._isFileDrag(e)) {
166
- VGFilesDroppable._clearSuggestedDrop();
167
- return;
168
- }
169
-
170
- const activeDrop = VGFilesDroppable._activeSuggestedDrop;
171
- if (activeDrop) {
172
- const instance = Array.from(VGFilesDroppable._smartInstances).find(i => i._element === activeDrop);
173
- const files = e.dataTransfer?.files;
174
-
175
- if (instance && files && files.length && isElement(instance._input)) {
176
- e.preventDefault();
177
- e.stopPropagation();
178
- instance._files = files;
179
- instance._input.files = files;
180
- EventHandler.trigger(instance._input, 'change');
181
- }
182
- }
183
-
184
- VGFilesDroppable._clearSuggestedDrop();
185
- },
186
- dragend: () => VGFilesDroppable._clearSuggestedDrop(),
187
- };
188
-
189
- EventHandler.on(document, 'dragenter', VGFilesDroppable._globalHandlers.dragenter);
190
- EventHandler.on(document, 'dragover', VGFilesDroppable._globalHandlers.dragover);
191
- EventHandler.on(document, 'dragleave', VGFilesDroppable._globalHandlers.dragleave);
192
- EventHandler.on(document, 'drop', VGFilesDroppable._globalHandlers.drop);
193
- EventHandler.on(document, 'dragend', VGFilesDroppable._globalHandlers.dragend);
194
-
195
- EventHandler.on(window, 'dragenter', VGFilesDroppable._globalHandlers.dragenter);
196
- EventHandler.on(window, 'dragover', VGFilesDroppable._globalHandlers.dragover);
197
- EventHandler.on(window, 'dragleave', VGFilesDroppable._globalHandlers.dragleave);
198
- EventHandler.on(window, 'drop', VGFilesDroppable._globalHandlers.drop);
199
- EventHandler.on(window, 'dragend', VGFilesDroppable._globalHandlers.dragend);
200
-
201
- VGFilesDroppable._isGlobalEventsBound = true;
202
- }
203
-
204
- _updateSuggestedDrop(e) {
205
- if (!this._isFileDrag(e)) {
206
- VGFilesDroppable._clearSuggestedDrop();
207
- return;
208
- }
209
-
210
- const visibleDrops = this._getVisibleDropZonesInViewport();
211
-
212
- if (visibleDrops.length === 1) {
213
- const [dropZone] = visibleDrops;
214
- if (VGFilesDroppable._activeSuggestedDrop !== dropZone) {
215
- VGFilesDroppable._clearSuggestedDrop();
216
- Classes.add(dropZone, CLASS_NAME_DROP_ACTIVE);
217
- VGFilesDroppable._setDropMessageTitleState(dropZone, true);
218
- VGFilesDroppable._activeSuggestedDrop = dropZone;
219
- }
220
-
221
- if (e.dataTransfer) e.dataTransfer.dropEffect = 'copy';
222
- e.preventDefault();
223
- return;
224
- }
225
-
226
- VGFilesDroppable._clearSuggestedDrop();
227
- }
228
-
229
- _isFileDrag(e) {
230
- try {
231
- const dt = e?.dataTransfer;
232
- if (!dt) return false;
233
-
234
- if (dt.files && dt.files.length > 0) return true;
235
-
236
- if (dt.items && dt.items.length > 0) {
237
- return Array.from(dt.items).some(item => item.kind === 'file');
238
- }
239
-
240
- if (dt.types) {
241
- return Array.from(dt.types).includes('Files');
242
- }
243
-
244
- return false;
245
- } catch (_) {
246
- return false;
247
- }
248
- }
249
-
250
- _getVisibleDropZonesInViewport() {
251
- const dropZones = Array.from(Selectors.findAll(`.${CLASS_NAME_DROP}`) || []);
252
- return dropZones.filter((el) => this._isVisibleInViewport(el));
253
- }
254
-
255
- _isVisibleInViewport(el) {
256
- if (!isElement(el) || !el.isConnected) return false;
257
-
258
- const style = window.getComputedStyle(el);
259
- if (style.display === 'none' || style.visibility === 'hidden' || style.opacity === '0') {
260
- return false;
261
- }
262
-
263
- const rect = el.getBoundingClientRect();
264
- if (!rect.width || !rect.height) return false;
265
-
266
- const inViewport =
267
- rect.bottom > 0 &&
268
- rect.right > 0 &&
269
- rect.top < window.innerHeight &&
270
- rect.left < window.innerWidth;
271
-
272
- return inViewport;
273
- }
274
-
275
- static _clearSuggestedDrop() {
276
- if (!VGFilesDroppable._activeSuggestedDrop) return;
277
-
278
- VGFilesDroppable._setDropMessageTitleState(VGFilesDroppable._activeSuggestedDrop, false);
279
- Classes.remove(VGFilesDroppable._activeSuggestedDrop, CLASS_NAME_DROP_ACTIVE);
280
- VGFilesDroppable._activeSuggestedDrop = null;
281
- }
282
-
283
- static _setDropMessageTitleState(dropElement, isActive) {
284
- if (!isElement(dropElement)) return;
285
-
286
- const title = Selectors.find('.vg-files-drop-message .title', dropElement);
287
- if (!title) return;
288
-
289
- const originalText = (title.getAttribute('data-drop-original-text') || '').trim() || (title.textContent || '').trim();
290
- title.setAttribute('data-drop-original-text', originalText);
291
-
292
- const activeText = (dropElement.getAttribute('data-drop-active-text') || '').trim();
293
- if (isActive && activeText) {
294
- title.textContent = activeText;
295
- return;
296
- }
297
-
298
- title.textContent = originalText;
299
- }
300
-
301
- static _unbindGlobalEvents() {
302
- if (!VGFilesDroppable._isGlobalEventsBound) return;
303
-
304
- const handlers = VGFilesDroppable._globalHandlers || {};
305
-
306
- EventHandler.off(document, 'dragenter', handlers.dragenter);
307
- EventHandler.off(document, 'dragover', handlers.dragover);
308
- EventHandler.off(document, 'dragleave', handlers.dragleave);
309
- EventHandler.off(document, 'drop', handlers.drop);
310
- EventHandler.off(document, 'dragend', handlers.dragend);
311
-
312
- EventHandler.off(window, 'dragenter', handlers.dragenter);
313
- EventHandler.off(window, 'dragover', handlers.dragover);
314
- EventHandler.off(window, 'dragleave', handlers.dragleave);
315
- EventHandler.off(window, 'drop', handlers.drop);
316
- EventHandler.off(window, 'dragend', handlers.dragend);
317
-
318
- VGFilesDroppable._isGlobalEventsBound = false;
319
- VGFilesDroppable._globalHandlers = null;
320
- VGFilesDroppable._clearSuggestedDrop();
321
- }
149
+ });
150
+ }
151
+
152
+ _bindGlobalEvents() {
153
+ if (VGFilesDroppable._isGlobalEventsBound) return;
154
+
155
+ VGFilesDroppable._globalHandlers = {
156
+ dragenter: (e) => this._updateSuggestedDrop(e),
157
+ dragover: (e) => this._updateSuggestedDrop(e),
158
+ dragleave: (e) => {
159
+ if (!this._isFileDrag(e)) return;
160
+ if (e.relatedTarget === null || e.target === document || e.target === document.documentElement) {
161
+ VGFilesDroppable._clearSuggestedDrop();
162
+ }
163
+ },
164
+ drop: (e) => {
165
+ if (!this._isFileDrag(e)) {
166
+ VGFilesDroppable._clearSuggestedDrop();
167
+ return;
168
+ }
169
+
170
+ const activeDrop = VGFilesDroppable._activeSuggestedDrop;
171
+ if (activeDrop) {
172
+ const instance = Array.from(VGFilesDroppable._smartInstances).find(i => i._element === activeDrop);
173
+ const files = e.dataTransfer?.files;
174
+
175
+ if (instance && files && files.length && isElement(instance._input)) {
176
+ e.preventDefault();
177
+ e.stopPropagation();
178
+ instance._files = files;
179
+ instance._input.files = files;
180
+ EventHandler.trigger(instance._input, 'change');
181
+ }
182
+ }
183
+
184
+ VGFilesDroppable._clearSuggestedDrop();
185
+ },
186
+ dragend: () => VGFilesDroppable._clearSuggestedDrop(),
187
+ };
188
+
189
+ EventHandler.on(document, 'dragenter', VGFilesDroppable._globalHandlers.dragenter);
190
+ EventHandler.on(document, 'dragover', VGFilesDroppable._globalHandlers.dragover);
191
+ EventHandler.on(document, 'dragleave', VGFilesDroppable._globalHandlers.dragleave);
192
+ EventHandler.on(document, 'drop', VGFilesDroppable._globalHandlers.drop);
193
+ EventHandler.on(document, 'dragend', VGFilesDroppable._globalHandlers.dragend);
194
+
195
+ EventHandler.on(window, 'dragenter', VGFilesDroppable._globalHandlers.dragenter);
196
+ EventHandler.on(window, 'dragover', VGFilesDroppable._globalHandlers.dragover);
197
+ EventHandler.on(window, 'dragleave', VGFilesDroppable._globalHandlers.dragleave);
198
+ EventHandler.on(window, 'drop', VGFilesDroppable._globalHandlers.drop);
199
+ EventHandler.on(window, 'dragend', VGFilesDroppable._globalHandlers.dragend);
200
+
201
+ VGFilesDroppable._isGlobalEventsBound = true;
202
+ }
203
+
204
+ _updateSuggestedDrop(e) {
205
+ if (!this._isFileDrag(e)) {
206
+ VGFilesDroppable._clearSuggestedDrop();
207
+ return;
208
+ }
209
+
210
+ const visibleDrops = this._getVisibleDropZonesInViewport();
211
+
212
+ if (visibleDrops.length === 1) {
213
+ const [dropZone] = visibleDrops;
214
+ if (VGFilesDroppable._activeSuggestedDrop !== dropZone) {
215
+ VGFilesDroppable._clearSuggestedDrop();
216
+ Classes.add(dropZone, CLASS_NAME_DROP_ACTIVE);
217
+ VGFilesDroppable._setDropMessageTitleState(dropZone, true);
218
+ VGFilesDroppable._activeSuggestedDrop = dropZone;
219
+ }
220
+
221
+ if (e.dataTransfer) e.dataTransfer.dropEffect = 'copy';
222
+ e.preventDefault();
223
+ return;
224
+ }
225
+
226
+ VGFilesDroppable._clearSuggestedDrop();
227
+ }
228
+
229
+ _isFileDrag(e) {
230
+ try {
231
+ const dt = e?.dataTransfer;
232
+ if (!dt) return false;
233
+
234
+ if (dt.files && dt.files.length > 0) return true;
235
+
236
+ if (dt.items && dt.items.length > 0) {
237
+ return Array.from(dt.items).some(item => item.kind === 'file');
238
+ }
239
+
240
+ if (dt.types) {
241
+ return Array.from(dt.types).includes('Files');
242
+ }
243
+
244
+ return false;
245
+ } catch (_) {
246
+ return false;
247
+ }
248
+ }
249
+
250
+ _getVisibleDropZonesInViewport() {
251
+ const dropZones = Array.from(Selectors.findAll(`.${CLASS_NAME_DROP}`) || []);
252
+ return dropZones.filter((el) => this._isVisibleInViewport(el));
253
+ }
254
+
255
+ _isVisibleInViewport(el) {
256
+ if (!isElement(el) || !el.isConnected) return false;
257
+
258
+ const style = window.getComputedStyle(el);
259
+ if (style.display === 'none' || style.visibility === 'hidden' || style.opacity === '0') {
260
+ return false;
261
+ }
262
+
263
+ const rect = el.getBoundingClientRect();
264
+ if (!rect.width || !rect.height) return false;
265
+
266
+ const inViewport =
267
+ rect.bottom > 0 &&
268
+ rect.right > 0 &&
269
+ rect.top < window.innerHeight &&
270
+ rect.left < window.innerWidth;
271
+
272
+ return inViewport;
273
+ }
274
+
275
+ static _clearSuggestedDrop() {
276
+ if (!VGFilesDroppable._activeSuggestedDrop) return;
277
+
278
+ VGFilesDroppable._setDropMessageTitleState(VGFilesDroppable._activeSuggestedDrop, false);
279
+ Classes.remove(VGFilesDroppable._activeSuggestedDrop, CLASS_NAME_DROP_ACTIVE);
280
+ VGFilesDroppable._activeSuggestedDrop = null;
281
+ }
282
+
283
+ static _setDropMessageTitleState(dropElement, isActive) {
284
+ if (!isElement(dropElement)) return;
285
+
286
+ const title = Selectors.find('.vg-files-drop-message .title', dropElement);
287
+ if (!title) return;
288
+
289
+ const originalText = (title.getAttribute('data-drop-original-text') || '').trim() || (title.textContent || '').trim();
290
+ title.setAttribute('data-drop-original-text', originalText);
291
+
292
+ const activeText = (dropElement.getAttribute('data-drop-active-text') || '').trim();
293
+ if (isActive && activeText) {
294
+ title.textContent = activeText;
295
+ return;
296
+ }
297
+
298
+ title.textContent = originalText;
299
+ }
300
+
301
+ static _unbindGlobalEvents() {
302
+ if (!VGFilesDroppable._isGlobalEventsBound) return;
303
+
304
+ const handlers = VGFilesDroppable._globalHandlers || {};
305
+
306
+ EventHandler.off(document, 'dragenter', handlers.dragenter);
307
+ EventHandler.off(document, 'dragover', handlers.dragover);
308
+ EventHandler.off(document, 'dragleave', handlers.dragleave);
309
+ EventHandler.off(document, 'drop', handlers.drop);
310
+ EventHandler.off(document, 'dragend', handlers.dragend);
311
+
312
+ EventHandler.off(window, 'dragenter', handlers.dragenter);
313
+ EventHandler.off(window, 'dragover', handlers.dragover);
314
+ EventHandler.off(window, 'dragleave', handlers.dragleave);
315
+ EventHandler.off(window, 'drop', handlers.drop);
316
+ EventHandler.off(window, 'dragend', handlers.dragend);
317
+
318
+ VGFilesDroppable._isGlobalEventsBound = false;
319
+ VGFilesDroppable._globalHandlers = null;
320
+ VGFilesDroppable._clearSuggestedDrop();
321
+ }
322
322
 
323
323
  getFiles() {
324
324
  return this._files;
325
325
  }
326
326
 
327
- dispose() {
328
- EventHandler.off(this._element, 'dragover');
329
- EventHandler.off(this._element, 'dragenter');
330
- EventHandler.off(this._element, 'dragleave');
331
- EventHandler.off(this._element, 'drop');
332
-
333
- VGFilesDroppable._instances.delete(this);
334
- VGFilesDroppable._smartInstances.delete(this);
335
- if (!VGFilesDroppable._smartInstances.size) {
336
- VGFilesDroppable._unbindGlobalEvents();
337
- }
338
-
339
- this._input = null;
340
- this._files = null;
341
- }
327
+ dispose() {
328
+ EventHandler.off(this._element, 'dragover');
329
+ EventHandler.off(this._element, 'dragenter');
330
+ EventHandler.off(this._element, 'dragleave');
331
+ EventHandler.off(this._element, 'drop');
332
+
333
+ VGFilesDroppable._instances.delete(this);
334
+ VGFilesDroppable._smartInstances.delete(this);
335
+ if (!VGFilesDroppable._smartInstances.size) {
336
+ VGFilesDroppable._unbindGlobalEvents();
337
+ }
338
+
339
+ this._input = null;
340
+ this._files = null;
341
+ }
342
342
 
343
343
  init() {
344
344
  return this;
345
345
  }
346
- }
347
-
348
- VGFilesDroppable._instances = new Set();
349
- VGFilesDroppable._smartInstances = new Set();
350
- VGFilesDroppable._isGlobalEventsBound = false;
351
- VGFilesDroppable._activeSuggestedDrop = null;
352
- VGFilesDroppable._globalHandlers = null;
353
-
354
- export default VGFilesDroppable;
346
+ }
347
+
348
+ VGFilesDroppable._instances = new Set();
349
+ VGFilesDroppable._smartInstances = new Set();
350
+ VGFilesDroppable._isGlobalEventsBound = false;
351
+ VGFilesDroppable._activeSuggestedDrop = null;
352
+ VGFilesDroppable._globalHandlers = null;
353
+
354
+ export default VGFilesDroppable;