vgapp 1.0.4 → 1.0.5

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.
@@ -52,10 +52,10 @@ class VGFiles extends VGFilesBase {
52
52
  retryAttempts: 1,
53
53
  retryDelay: 1000,
54
54
  },
55
- removes: {
56
- all: { route: '', alert: true, toast: true },
57
- single: { route: '', alert: true, toast: true }
58
- },
55
+ removes: {
56
+ all: { route: '', alert: true, toast: true, confirm: null },
57
+ single: { route: '', alert: true, toast: true, confirm: null }
58
+ },
59
59
  sortable: {
60
60
  enabled: false,
61
61
  route: '',
@@ -525,8 +525,8 @@ class VGFiles extends VGFilesBase {
525
525
  });
526
526
  }
527
527
 
528
- reload(button) {
529
- if (!this._params.ajax || !this._params.uploads.route) return;
528
+ reload(button) {
529
+ if (!this._params.ajax || !this._params.uploads.route) return;
530
530
 
531
531
  const dataButton = Manipulator.get(button, 'data');
532
532
  const fileData = {
@@ -556,10 +556,85 @@ class VGFiles extends VGFilesBase {
556
556
  this._triggerCallback('onReload', payload);
557
557
  this._triggerEvent('reload', payload);
558
558
 
559
- this.upload(fileToRetry);
560
- }
561
-
562
- removeFile(button) {
559
+ this.upload(fileToRetry);
560
+ }
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
+
637
+ removeFile(button) {
563
638
  const name = normalizeData(Manipulator.get(button, 'data-name'));
564
639
  const size = normalizeData(Manipulator.get(button, 'data-size'));
565
640
  const id = normalizeData(Manipulator.get(button, 'data-id'));
@@ -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'
@@ -614,35 +691,31 @@ class VGFiles extends VGFilesBase {
614
691
  }
615
692
  };
616
693
 
617
- 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
- });
636
-
637
- EventHandler.one(button, 'vg.alert.accept', (event) => {
638
- _completeRemoveFile(event.vgalert.data);
639
- });
640
- } else {
641
- this._params.ajax = paramsAjax;
642
- this._route((status, data) => {
643
- _completeRemoveFile(data);
644
- });
645
- }
694
+ if (this._params.removes.single.alert) {
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
+ }
708
+
709
+ this._runAjaxRequest(paramsAjax, (status, data) => {
710
+ _completeRemoveFile(data);
711
+ });
712
+ })
713
+ .catch(() => {});
714
+ } else {
715
+ this._runAjaxRequest(paramsAjax, (status, data) => {
716
+ _completeRemoveFile(data);
717
+ });
718
+ }
646
719
  } else {
647
720
  this._files = this._files.filter(f => !(f.name === name && f.size === size));
648
721
  this._updateStatsAfterRemove();
@@ -859,37 +932,37 @@ EventHandler.on(document, `click.${NAME_KEY}.data.api`, SELECTOR_DATA_DISMISS_AL
859
932
  instance.clear(true, true);
860
933
  };
861
934
 
862
- 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
- });
881
-
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
- });
888
- } else {
889
- instance._route(paramsAjax, (status, data) => {
890
- if (instance._params.removes.all.toast && data?.response?.message) {
891
- VGToast.run(data.response.message);
892
- }
935
+ if (instance._params.removes.all.alert) {
936
+ const message = {
937
+ title: lang_messages(instance._params.lang, NAME)['title'],
938
+ description: lang_messages(instance._params.lang, NAME)['descriptions']
939
+ };
940
+
941
+ instance._confirmRemove('all', e.target, paramsAjax, message)
942
+ .then((result) => {
943
+ if (!result.accepted) return;
944
+
945
+ if (result.data) {
946
+ if (instance._params.removes.all.toast) {
947
+ VGToast.run(result.data?.response?.message);
948
+ }
949
+ _completeClearAll();
950
+ return;
951
+ }
952
+
953
+ instance._runAjaxRequest(paramsAjax, (status, data) => {
954
+ if (instance._params.removes.all.toast && data?.response?.message) {
955
+ VGToast.run(data.response.message);
956
+ }
957
+ _completeClearAll();
958
+ });
959
+ })
960
+ .catch(() => {});
961
+ } else {
962
+ instance._runAjaxRequest(paramsAjax, (status, data) => {
963
+ if (instance._params.removes.all.toast && data?.response?.message) {
964
+ VGToast.run(data.response.message);
965
+ }
893
966
  _completeClearAll();
894
967
  });
895
968
  }
@@ -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
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "vgapp",
3
- "version": "1.0.4",
3
+ "version": "1.0.5",
4
4
  "description": "",
5
5
  "author": {
6
6
  "name": "Vegas Studio",