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
@@ -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;