vgapp 1.0.4 → 1.0.6

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.
@@ -53,8 +53,8 @@ class VGFiles extends VGFilesBase {
53
53
  retryDelay: 1000,
54
54
  },
55
55
  removes: {
56
- all: { route: '', alert: true, toast: true },
57
- single: { route: '', alert: true, toast: true }
56
+ all: { route: '', alert: true, toast: true, confirm: null },
57
+ single: { route: '', alert: true, toast: true, confirm: null }
58
58
  },
59
59
  sortable: {
60
60
  enabled: false,
@@ -559,6 +559,81 @@ class VGFiles extends VGFilesBase {
559
559
  this.upload(fileToRetry);
560
560
  }
561
561
 
562
+ _runAjaxRequest(paramsAjax, callback) {
563
+ const previousAjax = this._params.ajax;
564
+ this._params.ajax = paramsAjax;
565
+
566
+ this._route((status, data) => {
567
+ this._params.ajax = previousAjax;
568
+ callback(status, data);
569
+ });
570
+ }
571
+
572
+ _normalizeConfirmResult(result) {
573
+ if (result === true) return { accepted: true, data: null };
574
+ if (result === false || result == null) return { accepted: false, data: null };
575
+
576
+ if (typeof result === 'object') {
577
+ if (typeof result.accepted === 'boolean') {
578
+ return { accepted: result.accepted, data: result.data ?? null };
579
+ }
580
+ if (Object.prototype.hasOwnProperty.call(result, 'data')) {
581
+ return { accepted: true, data: result.data ?? null };
582
+ }
583
+ }
584
+
585
+ return { accepted: Boolean(result), data: null };
586
+ }
587
+
588
+ _runDefaultRemoveConfirm(trigger, params) {
589
+ return new Promise((resolve) => {
590
+ VGAlert.confirm(trigger, {
591
+ lang: params.lang,
592
+ ajax: params.ajax,
593
+ buttons: params.buttons,
594
+ message: params.message
595
+ });
596
+
597
+ EventHandler.one(trigger, 'vg.alert.accept', (event) => {
598
+ resolve({ accepted: true, data: event?.vgalert?.data ?? null });
599
+ });
600
+
601
+ EventHandler.one(trigger, 'vg.alert.reject', () => {
602
+ resolve({ accepted: false, data: null });
603
+ });
604
+ });
605
+ }
606
+
607
+ _confirmRemove(type, trigger, ajax, message) {
608
+ const buttons = {
609
+ agree: {
610
+ text: lang_buttons(this._params.lang, NAME)['agree'],
611
+ class: ["btn-danger"],
612
+ },
613
+ cancel: {
614
+ text: lang_buttons(this._params.lang, NAME)['cancel'],
615
+ class: ["btn-outline-danger"],
616
+ },
617
+ };
618
+
619
+ const confirmParams = {
620
+ type,
621
+ trigger,
622
+ lang: this._params.lang,
623
+ ajax,
624
+ buttons,
625
+ message
626
+ };
627
+
628
+ const customConfirm = this._params?.removes?.[type]?.confirm;
629
+ if (typeof customConfirm === 'function') {
630
+ return Promise.resolve(customConfirm(confirmParams, this))
631
+ .then((result) => this._normalizeConfirmResult(result));
632
+ }
633
+
634
+ return this._runDefaultRemoveConfirm(trigger, confirmParams);
635
+ }
636
+
562
637
  removeFile(button) {
563
638
  const name = normalizeData(Manipulator.get(button, 'data-name'));
564
639
  const size = normalizeData(Manipulator.get(button, 'data-size'));
@@ -593,7 +668,9 @@ class VGFiles extends VGFilesBase {
593
668
  if (this._params.ajax && this._params.removes.single.route) {
594
669
  if (!id) return;
595
670
 
596
- const route = this._params.removes.single.route + '/' + encodeURIComponent(id);
671
+ const routeBase = this._params.removes.single.route;
672
+ const routeSeparator = routeBase.includes('?') ? '&' : '?';
673
+ const route = `${routeBase}${routeSeparator}id=${encodeURIComponent(id)}`;
597
674
  const paramsAjax = {
598
675
  route: route,
599
676
  method: 'delete'
@@ -615,31 +692,27 @@ class VGFiles extends VGFilesBase {
615
692
  };
616
693
 
617
694
  if (this._params.removes.single.alert) {
618
- VGAlert.confirm(button, {
619
- lang: this._params.lang,
620
- ajax: paramsAjax,
621
- buttons: {
622
- agree: {
623
- text: lang_buttons(this._params.lang, NAME)['agree'],
624
- class: ["btn-danger"],
625
- },
626
- cancel: {
627
- text: lang_buttons(this._params.lang, NAME)['cancel'],
628
- class: ["btn-outline-danger"],
629
- },
630
- },
631
- message: {
632
- title: lang_messages(this._params.lang, NAME)['title'],
633
- description: lang_messages(this._params.lang, NAME)['description']
634
- }
635
- });
695
+ const message = {
696
+ title: lang_messages(this._params.lang, NAME)['title'],
697
+ description: lang_messages(this._params.lang, NAME)['description']
698
+ };
699
+
700
+ this._confirmRemove('single', button, paramsAjax, message)
701
+ .then((result) => {
702
+ if (!result.accepted) return;
703
+
704
+ if (result.data) {
705
+ _completeRemoveFile(result.data);
706
+ return;
707
+ }
636
708
 
637
- EventHandler.one(button, 'vg.alert.accept', (event) => {
638
- _completeRemoveFile(event.vgalert.data);
639
- });
709
+ this._runAjaxRequest(paramsAjax, (status, data) => {
710
+ _completeRemoveFile(data);
711
+ });
712
+ })
713
+ .catch(() => {});
640
714
  } else {
641
- this._params.ajax = paramsAjax;
642
- this._route((status, data) => {
715
+ this._runAjaxRequest(paramsAjax, (status, data) => {
643
716
  _completeRemoveFile(data);
644
717
  });
645
718
  }
@@ -812,7 +885,14 @@ class VGFiles extends VGFilesBase {
812
885
  this._sortable = null;
813
886
 
814
887
  this.clear();
815
- if (this._uploader) this._uploader.destroy();
888
+ if (this._uploader) {
889
+ if (typeof this._uploader.destroy === 'function') {
890
+ this._uploader.destroy();
891
+ } else {
892
+ if (typeof this._uploader.clear === 'function') this._uploader.clear();
893
+ if (typeof this._uploader.offAll === 'function') this._uploader.offAll();
894
+ }
895
+ }
816
896
  super.dispose();
817
897
  }
818
898
  }
@@ -860,33 +940,33 @@ EventHandler.on(document, `click.${NAME_KEY}.data.api`, SELECTOR_DATA_DISMISS_AL
860
940
  };
861
941
 
862
942
  if (instance._params.removes.all.alert) {
863
- VGAlert.confirm(e.target, {
864
- lang: instance._params.lang,
865
- ajax: paramsAjax,
866
- buttons: {
867
- agree: {
868
- text: lang_buttons(instance._params.lang, NAME)['agree'],
869
- class: ["btn-danger"],
870
- },
871
- cancel: {
872
- text: lang_buttons(instance._params.lang, NAME)['cancel'],
873
- class: ["btn-outline-danger"],
874
- },
875
- },
876
- message: {
877
- title: lang_messages(instance._params.lang, NAME)['title'],
878
- description: lang_messages(instance._params.lang, NAME)['descriptions']
879
- }
880
- });
943
+ const message = {
944
+ title: lang_messages(instance._params.lang, NAME)['title'],
945
+ description: lang_messages(instance._params.lang, NAME)['descriptions']
946
+ };
881
947
 
882
- EventHandler.one(e.target, 'vg.alert.accept', (event) => {
883
- if (instance._params.removes.all.toast) {
884
- VGToast.run(event.vgalert.data?.response?.message);
885
- }
886
- _completeClearAll();
887
- });
948
+ instance._confirmRemove('all', e.target, paramsAjax, message)
949
+ .then((result) => {
950
+ if (!result.accepted) return;
951
+
952
+ if (result.data) {
953
+ if (instance._params.removes.all.toast) {
954
+ VGToast.run(result.data?.response?.message);
955
+ }
956
+ _completeClearAll();
957
+ return;
958
+ }
959
+
960
+ instance._runAjaxRequest(paramsAjax, (status, data) => {
961
+ if (instance._params.removes.all.toast && data?.response?.message) {
962
+ VGToast.run(data.response.message);
963
+ }
964
+ _completeClearAll();
965
+ });
966
+ })
967
+ .catch(() => {});
888
968
  } else {
889
- instance._route(paramsAjax, (status, data) => {
969
+ instance._runAjaxRequest(paramsAjax, (status, data) => {
890
970
  if (instance._params.removes.all.toast && data?.response?.message) {
891
971
  VGToast.run(data.response.message);
892
972
  }
@@ -62,9 +62,13 @@ const files = new VGFiles(document.querySelector('.vg-files'), {
62
62
  | `uploads.retryAttempts` | `number` | `1` | Кол-во попыток повтора при ошибке |
63
63
  | `uploads.retryDelay` | `number` | `1000` | Задержка между попытками (мс) |
64
64
  | `removes.single.route` | `string` | `''` | URL для удаления одного файла |
65
- | `removes.all.route` | `string` | `''` | URL для удаления всех файлов |
66
- | `removes.single.alert` | `boolean` | `true` | Показывать подтверждение при удалении |
67
- | `removes.single.toast` | `boolean` | `true` | Показывать уведомление после удаления |
65
+ | `removes.all.route` | `string` | `''` | URL для удаления всех файлов |
66
+ | `removes.all.alert` | `boolean` | `true` | Показывать подтверждение при удалении всех файлов |
67
+ | `removes.all.toast` | `boolean` | `true` | Показывать уведомление после удаления всех файлов |
68
+ | `removes.all.confirm` | `function \| null` | `null` | Кастомный confirm-обработчик для удаления всех файлов |
69
+ | `removes.single.alert` | `boolean` | `true` | Показывать подтверждение при удалении |
70
+ | `removes.single.toast` | `boolean` | `true` | Показывать уведомление после удаления |
71
+ | `removes.single.confirm` | `function \| null` | `null` | Кастомный confirm-обработчик для удаления одного файла |
68
72
  | `sortable.enabled` | `boolean` | `false` | Включить сортировку |
69
73
  | `sortable.route` | `string` | `''` | URL для сохранения порядка файлов |
70
74
  | `callbacks` | `object` | `null` | Колбэки на события (см. ниже) |
@@ -116,7 +120,34 @@ const files = new VGFiles(document.querySelector('.vg-files'), {
116
120
  - **Удаление одного файла**: кнопка с `data-vg-dismiss="file"` → вызов `removeFile()`.
117
121
  - **Очистка всех**: кнопка с `data-vg-dismiss="vg-files"` → `clear()`.
118
122
 
119
- Поддержка подтверждения через `VGAlert` и уведомлений через `VGToast`.
123
+ Поддержка подтверждения через `VGAlert` и уведомлений через `VGToast`.
124
+
125
+ ### Кастомный confirm для удаления
126
+
127
+ Если задан `removes.single.confirm` или `removes.all.confirm`, модуль вызовет вашу функцию вместо дефолтного `VGAlert`.
128
+
129
+ ```js
130
+ new VGFiles(document.querySelector('.vg-files'), {
131
+ ajax: true,
132
+ removes: {
133
+ single: {
134
+ route: '/api/file/remove',
135
+ alert: true,
136
+ confirm: async ({ message }) => {
137
+ const accepted = window.confirm(`${message.title}\n${message.description}`);
138
+ return { accepted };
139
+ }
140
+ }
141
+ }
142
+ });
143
+ ```
144
+
145
+ Контракт функции confirm:
146
+ - Вход: объект `{ type, trigger, lang, ajax, buttons, message }`.
147
+ - Выход:
148
+ `true` или `{ accepted: true }` — подтвердить;
149
+ `false` или `{ accepted: false }` — отменить;
150
+ `{ accepted: true, data }` — подтвердить и передать готовый ответ удаления (если запрос уже выполнен внутри confirm).
120
151
 
121
152
  ---
122
153
 
@@ -351,6 +351,7 @@ class VGModal extends BaseModule {
351
351
  for (const elm of elements) {
352
352
  switch (elm.tagName) {
353
353
  case 'INPUT': elm.value = item.value; break;
354
+ case 'FORM': elm.action = item.value; break;
354
355
  case 'IMG': Manipulator.set(elm, 'src', item.value); break;
355
356
  default: elm.innerHTML = item.value;
356
357
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "vgapp",
3
- "version": "1.0.4",
3
+ "version": "1.0.6",
4
4
  "description": "",
5
5
  "author": {
6
6
  "name": "Vegas Studio",