vgapp 1.1.7 → 1.1.9

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 (58) hide show
  1. package/CHANGELOG.md +11 -11
  2. package/README.md +48 -48
  3. package/app/langs/en/buttons.json +17 -17
  4. package/app/langs/en/messages.json +36 -36
  5. package/app/langs/ru/buttons.json +17 -17
  6. package/app/langs/ru/messages.json +36 -36
  7. package/app/modules/vgfilepreview/js/i18n.js +56 -56
  8. package/app/modules/vgfilepreview/js/renderers/image-modal.js +145 -145
  9. package/app/modules/vgfilepreview/js/renderers/image.js +92 -92
  10. package/app/modules/vgfilepreview/js/renderers/index.js +19 -19
  11. package/app/modules/vgfilepreview/js/renderers/office-modal.js +168 -168
  12. package/app/modules/vgfilepreview/js/renderers/office.js +79 -79
  13. package/app/modules/vgfilepreview/js/renderers/pdf-modal.js +260 -260
  14. package/app/modules/vgfilepreview/js/renderers/pdf.js +76 -76
  15. package/app/modules/vgfilepreview/js/renderers/playlist.js +71 -71
  16. package/app/modules/vgfilepreview/js/renderers/text-modal.js +343 -343
  17. package/app/modules/vgfilepreview/js/renderers/text.js +83 -83
  18. package/app/modules/vgfilepreview/js/renderers/video-modal.js +272 -272
  19. package/app/modules/vgfilepreview/js/renderers/video.js +80 -80
  20. package/app/modules/vgfilepreview/js/renderers/zip-modal.js +522 -522
  21. package/app/modules/vgfilepreview/js/renderers/zip.js +89 -89
  22. package/app/modules/vgfilepreview/js/vgfilepreview.js +7 -7
  23. package/app/modules/vgfilepreview/readme.md +68 -68
  24. package/app/modules/vgfilepreview/scss/_variables.scss +113 -113
  25. package/app/modules/vgfilepreview/scss/vgfilepreview.scss +464 -464
  26. package/app/modules/vgfiles/js/base.js +26 -26
  27. package/app/modules/vgfiles/js/droppable.js +260 -260
  28. package/app/modules/vgfiles/js/render.js +153 -153
  29. package/app/modules/vgfiles/js/vgfiles.js +41 -41
  30. package/app/modules/vgfiles/readme.md +123 -123
  31. package/app/modules/vgfiles/scss/_variables.scss +18 -18
  32. package/app/modules/vgfiles/scss/vgfiles.scss +148 -148
  33. package/app/modules/vgformsender/js/vgformsender.js +122 -32
  34. package/app/modules/vgmodal/js/vgmodal.drag.js +332 -332
  35. package/app/modules/vgmodal/js/vgmodal.js +33 -33
  36. package/app/modules/vgmodal/js/vgmodal.resize.js +435 -435
  37. package/app/modules/vgnav/js/vgnav.js +135 -135
  38. package/app/modules/vgnav/readme.md +67 -67
  39. package/app/modules/vgnestable/README.md +307 -307
  40. package/app/modules/vgnestable/scss/_variables.scss +60 -60
  41. package/app/modules/vgnestable/scss/vgnestable.scss +163 -163
  42. package/app/modules/vgrollup/js/vgrollup.js +14 -9
  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/modules/vgtoast/js/vgtoast.js +121 -76
  47. package/app/modules/vgtoast/readme.md +12 -1
  48. package/app/modules/vgtoast/scss/vgtoast.scss +42 -1
  49. package/app/utils/js/components/audio-metadata.js +240 -240
  50. package/app/utils/js/components/file-icon.js +109 -109
  51. package/app/utils/js/components/file-preview.js +304 -304
  52. package/app/utils/js/components/sanitize.js +150 -150
  53. package/app/utils/js/components/video-metadata.js +140 -140
  54. package/build/vgapp.css +1 -1
  55. package/build/vgapp.css.map +1 -1
  56. package/build/vgapp.js.map +1 -1
  57. package/index.scss +9 -9
  58. package/package.json +1 -1
@@ -70,27 +70,27 @@ $files-map: (
70
70
  info-radius: 4px,
71
71
  info-list-max-height: 360px,
72
72
 
73
- info-gap: 8px,
74
- info-padding: 8px,
75
- info-border-bottom-color: var(--vg-secondary-bg),
76
- info-hover-bg: rgba(var(--vg-secondary-bg-rgb), .4),
77
- info-audio-progress-track: rgba(var(--vg-secondary-bg-rgb), .3),
78
- info-audio-progress-fill: #000,
79
- info-audio-progress-opacity: .33,
80
- info-audio-row-min-height: 64px,
81
- info-audio-image-size: 48px,
82
-
83
- info-image-radius: 4px,
73
+ info-gap: 8px,
74
+ info-padding: 8px,
75
+ info-border-bottom-color: var(--vg-secondary-bg),
76
+ info-hover-bg: rgba(var(--vg-secondary-bg-rgb), .4),
77
+ info-audio-progress-track: rgba(var(--vg-secondary-bg-rgb), .3),
78
+ info-audio-progress-fill: #000,
79
+ info-audio-progress-opacity: .33,
80
+ info-audio-row-min-height: 64px,
81
+ info-audio-image-size: 48px,
82
+
83
+ info-image-radius: 4px,
84
84
  info-iteration-font-size: 16px,
85
85
  info-name-font-size: 16px,
86
86
  info-size-font-size: 14px,
87
87
 
88
- info-remove-icon-size: 16px,
89
- info-row-remove-size: 22px,
90
- info-row-remove-icon-size: 10px,
91
- info-failing-actions-gap: 6px,
92
- info-failing-actions-margin-start: 8px,
93
- drop-failing-actions-gap: 6px,
88
+ info-remove-icon-size: 16px,
89
+ info-row-remove-size: 22px,
90
+ info-row-remove-icon-size: 10px,
91
+ info-failing-actions-gap: 6px,
92
+ info-failing-actions-margin-start: 8px,
93
+ drop-failing-actions-gap: 6px,
94
94
 
95
95
  // legacy (оставлено для совместимости со старым API темы)
96
96
  info-mb: 10px,
@@ -112,4 +112,4 @@ $files-map: (
112
112
  info-list-span-me: 6px,
113
113
  info-list-button-fs: 12px,
114
114
  info-list-button-color: #999999,
115
- );
115
+ );
@@ -261,15 +261,15 @@
261
261
  }
262
262
  }
263
263
 
264
- .file {
265
- --vg-button-color: var(--vg-secondary);
266
- display: flex;
267
- align-items: center;
268
- gap: var(--vg-files-info-gap);
269
- padding: var(--vg-files-info-padding);
270
- border-bottom: 1px solid var(--vg-files-info-border-bottom-color);
271
- transition: all .2s ease-in-out;
272
- position: relative;
264
+ .file {
265
+ --vg-button-color: var(--vg-secondary);
266
+ display: flex;
267
+ align-items: center;
268
+ gap: var(--vg-files-info-gap);
269
+ padding: var(--vg-files-info-padding);
270
+ border-bottom: 1px solid var(--vg-files-info-border-bottom-color);
271
+ transition: all .2s ease-in-out;
272
+ position: relative;
273
273
 
274
274
  @include vgfiles-sortable();
275
275
  @include vgfiles-state();
@@ -278,45 +278,45 @@
278
278
  border-bottom: none;
279
279
  }
280
280
 
281
- &:hover {
282
- background-color: var(--vg-files-info-hover-bg);
283
- }
284
-
285
- &[data-vg-filepreview-renderer="audio"] {
286
- --vg-filepreview-audio-inline-progress: 0%;
287
- position: relative;
288
- overflow: hidden;
289
- isolation: isolate;
290
- min-height: var(--vg-files-info-audio-row-min-height);
291
- background-color: var(--vg-files-info-audio-progress-track);
292
-
293
- &::before {
294
- content: '';
295
- position: absolute;
296
- inset: 0 auto 0 0;
297
- width: var(--vg-filepreview-audio-inline-progress);
298
- background: var(--vg-files-info-audio-progress-fill);
299
- opacity: var(--vg-files-info-audio-progress-opacity);
300
- pointer-events: none;
301
- z-index: 0;
302
- transition: width .12s linear;
303
- }
304
-
305
- > * {
306
- position: relative;
307
- z-index: 1;
308
- }
309
-
310
- .file-image {
311
- flex: 0 0 var(--vg-files-info-audio-image-size);
312
- width: var(--vg-files-info-audio-image-size);
313
- height: var(--vg-files-info-audio-image-size);
314
- }
315
- }
316
-
317
- > * {
318
- transition: all .2s ease-in-out;
319
- }
281
+ &:hover {
282
+ background-color: var(--vg-files-info-hover-bg);
283
+ }
284
+
285
+ &[data-vg-filepreview-renderer="audio"] {
286
+ --vg-filepreview-audio-inline-progress: 0%;
287
+ position: relative;
288
+ overflow: hidden;
289
+ isolation: isolate;
290
+ min-height: var(--vg-files-info-audio-row-min-height);
291
+ background-color: var(--vg-files-info-audio-progress-track);
292
+
293
+ &::before {
294
+ content: '';
295
+ position: absolute;
296
+ inset: 0 auto 0 0;
297
+ width: var(--vg-filepreview-audio-inline-progress);
298
+ background: var(--vg-files-info-audio-progress-fill);
299
+ opacity: var(--vg-files-info-audio-progress-opacity);
300
+ pointer-events: none;
301
+ z-index: 0;
302
+ transition: width .12s linear;
303
+ }
304
+
305
+ > * {
306
+ position: relative;
307
+ z-index: 1;
308
+ }
309
+
310
+ .file-image {
311
+ flex: 0 0 var(--vg-files-info-audio-image-size);
312
+ width: var(--vg-files-info-audio-image-size);
313
+ height: var(--vg-files-info-audio-image-size);
314
+ }
315
+ }
316
+
317
+ > * {
318
+ transition: all .2s ease-in-out;
319
+ }
320
320
 
321
321
  &-image {
322
322
  flex: 0 0 var(--vg-files-image-width);
@@ -362,63 +362,63 @@
362
362
  display: none;
363
363
  }
364
364
 
365
- .name {
366
- display: block;
367
- overflow: hidden;
368
- text-overflow: ellipsis;
369
- white-space: nowrap;
370
- font-size: var(--vg-files-info-name-font-size);
371
-
372
- &.vg-filepreview-audio-inline {
373
- display: inline-flex;
374
- gap: var(--vg-filepreview-audio-inline-gap);
375
- align-items: center;
376
- }
377
-
378
- &.is-preview-action {
379
- cursor: pointer;
380
- }
381
- }
382
-
383
- .size {
384
- color: var(--vg-secondary);
385
- font-size: var(--vg-files-info-size-font-size);
386
- white-space: nowrap;
387
- margin-left: auto;
388
- }
389
-
390
- .download {
391
- margin-left: 8px;
392
-
393
- .vg-filepreview-download-trigger {
394
- padding: 0;
395
- background: transparent;
396
- color: var(--vg-secondary);
397
- border-radius: 0;
398
- font-size: var(--vg-files-info-size-font-size);
399
- font-weight: 500;
400
- gap: 4px;
401
-
402
- &:hover {
403
- color: var(--vg-body-color);
404
- }
405
-
406
- &__icon svg {
407
- width: 14px;
408
- height: 14px;
409
- }
410
-
411
- &__text {
412
- display: none;
413
- }
414
- }
415
- }
416
- }
417
-
418
- &-remove {
419
- flex: 0 0 var(--vg-files-remove-width);
420
- width: var(--vg-files-remove-width);
421
- margin-left: auto;
365
+ .name {
366
+ display: block;
367
+ overflow: hidden;
368
+ text-overflow: ellipsis;
369
+ white-space: nowrap;
370
+ font-size: var(--vg-files-info-name-font-size);
371
+
372
+ &.vg-filepreview-audio-inline {
373
+ display: inline-flex;
374
+ gap: var(--vg-filepreview-audio-inline-gap);
375
+ align-items: center;
376
+ }
377
+
378
+ &.is-preview-action {
379
+ cursor: pointer;
380
+ }
381
+ }
382
+
383
+ .size {
384
+ color: var(--vg-secondary);
385
+ font-size: var(--vg-files-info-size-font-size);
386
+ white-space: nowrap;
387
+ margin-left: auto;
388
+ }
389
+
390
+ .download {
391
+ margin-left: 8px;
392
+
393
+ .vg-filepreview-download-trigger {
394
+ padding: 0;
395
+ background: transparent;
396
+ color: var(--vg-secondary);
397
+ border-radius: 0;
398
+ font-size: var(--vg-files-info-size-font-size);
399
+ font-weight: 500;
400
+ gap: 4px;
401
+
402
+ &:hover {
403
+ color: var(--vg-body-color);
404
+ }
405
+
406
+ &__icon svg {
407
+ width: 14px;
408
+ height: 14px;
409
+ }
410
+
411
+ &__text {
412
+ display: none;
413
+ }
414
+ }
415
+ }
416
+ }
417
+
418
+ &-remove {
419
+ flex: 0 0 var(--vg-files-remove-width);
420
+ width: var(--vg-files-remove-width);
421
+ margin-left: auto;
422
422
 
423
423
  button {
424
424
  width: var(--vg-files-remove-width);
@@ -451,21 +451,21 @@
451
451
  fill: var(--vg-button-color);
452
452
  }
453
453
  }
454
- }
455
- }
456
- }
457
-
458
- &.failing {
459
- .file-remove {
460
- flex: 0 0 auto;
461
- width: auto;
462
- }
463
- }
464
-
465
- &:not(.with-image) {
466
- .file-info {
467
- .iteration {
468
- display: block;
454
+ }
455
+ }
456
+ }
457
+
458
+ &.failing {
459
+ .file-remove {
460
+ flex: 0 0 auto;
461
+ width: auto;
462
+ }
463
+ }
464
+
465
+ &:not(.with-image) {
466
+ .file-info {
467
+ .iteration {
468
+ display: block;
469
469
  }
470
470
  }
471
471
  }
@@ -512,26 +512,26 @@
512
512
  }
513
513
  }
514
514
  }
515
- }
516
- }
517
- }
518
- }
519
-
520
- .file-failing-actions {
521
- display: inline-flex;
522
- align-items: center;
523
- gap: var(--vg-files-info-failing-actions-gap);
524
- }
525
-
526
- &-info--list {
527
- .file.failing {
528
- .file-remove {
529
- margin-left: var(--vg-files-info-failing-actions-margin-start);
530
- }
531
- }
532
- }
533
-
534
- &-drop {
515
+ }
516
+ }
517
+ }
518
+ }
519
+
520
+ .file-failing-actions {
521
+ display: inline-flex;
522
+ align-items: center;
523
+ gap: var(--vg-files-info-failing-actions-gap);
524
+ }
525
+
526
+ &-info--list {
527
+ .file.failing {
528
+ .file-remove {
529
+ margin-left: var(--vg-files-info-failing-actions-margin-start);
530
+ }
531
+ }
532
+ }
533
+
534
+ &-drop {
535
535
  background-color: var(--vg-files-drop-bg);
536
536
  border: var(--vg-files-drop-border-width) var(--vg-files-drop-border-style) var(--vg-files-drop-border-color);
537
537
  cursor: pointer;
@@ -711,14 +711,14 @@
711
711
  flex-direction: column;
712
712
  gap: 8px;
713
713
 
714
- .file-remove {
715
- .file-failing-actions {
716
- gap: var(--vg-files-drop-failing-actions-gap);
717
- }
718
-
719
- button {
720
- background: var(--vg-body-bg);
721
- color: var(--vg-body-color);
714
+ .file-remove {
715
+ .file-failing-actions {
716
+ gap: var(--vg-files-drop-failing-actions-gap);
717
+ }
718
+
719
+ button {
720
+ background: var(--vg-body-bg);
721
+ color: var(--vg-body-color);
722
722
  border: none;
723
723
  cursor: pointer;
724
724
  outline: none;
@@ -32,6 +32,7 @@
32
32
  import BaseModule from "../../base-module";
33
33
  import VGModal from "../../vgmodal/js/vgmodal";
34
34
  import VGCollapse from "../../vgcollapse/js/vgcollapse";
35
+ import VGToast from "../../vgtoast/js/vgtoast";
35
36
  import VGHideShowPass from "./hideshowpass";
36
37
  import {lang_titles, lang_messages} from "../../../utils/js/components/lang";
37
38
  import Html from "../../../utils/js/components/templater";
@@ -133,7 +134,8 @@ class VGFormSender extends BaseModule {
133
134
  enabled: true,
134
135
  type: 'modal',
135
136
  errors: true,
136
- delay: 0
137
+ delay: 0,
138
+ toast: {}
137
139
  },
138
140
  ajax: {
139
141
  route: '',
@@ -510,6 +512,10 @@ class VGFormSender extends BaseModule {
510
512
  if (this._params.alert.type === 'collapse') {
511
513
  this._alertCollapse(data, status)
512
514
  }
515
+
516
+ if (this._params.alert.type === 'toast') {
517
+ this._alertToast(data, status)
518
+ }
513
519
  }
514
520
 
515
521
  /**
@@ -602,6 +608,65 @@ class VGFormSender extends BaseModule {
602
608
  }
603
609
  }
604
610
 
611
+ /**
612
+ * Показ алерта в виде toast
613
+ * @param {Object} data - Данные для отображения
614
+ * @param {string} status - Статус (success/error)
615
+ * @private
616
+ */
617
+ _alertToast(data, status) {
618
+ const response = this._prepareAlertResponse(status, data);
619
+ const toastParams = this._getToastParams(status);
620
+
621
+ if (response.title) {
622
+ VGToast.run([response.title, response.message], toastParams);
623
+ return;
624
+ }
625
+
626
+ VGToast.run(response.message, toastParams);
627
+ }
628
+
629
+ /**
630
+ * Сборка параметров toast из alert.* и alert.toast
631
+ * @param {string} status - Статус алерта
632
+ * @returns {Object}
633
+ * @private
634
+ */
635
+ _getToastParams(status) {
636
+ const theme = status === 'error' ? 'danger' : status;
637
+ const delay = this._params.alert.delay > 0 ? this._params.alert.delay : 3000;
638
+ const flatToastParams = {};
639
+ const allowedKeys = [
640
+ 'static',
641
+ 'placement',
642
+ 'autohide',
643
+ 'delay',
644
+ 'enableClickToast',
645
+ 'enableButtonClose',
646
+ 'keyboard',
647
+ 'theme',
648
+ 'type',
649
+ 'drag',
650
+ 'resize',
651
+ 'stack',
652
+ 'animation',
653
+ 'ajax'
654
+ ];
655
+
656
+ allowedKeys.forEach((key) => {
657
+ if (key in this._params.alert) {
658
+ flatToastParams[key] = this._params.alert[key];
659
+ }
660
+ });
661
+
662
+ return mergeDeepObject({
663
+ theme: theme || 'dark',
664
+ enableButtonClose: true,
665
+ autohide: this._params.alert.delay > 0,
666
+ delay: delay
667
+ }, flatToastParams, this._params.alert.toast || {});
668
+ }
669
+
605
670
  /**
606
671
  * Формирование содержимого алерта (заголовок, текст, иконка)
607
672
  * @param {HTMLElement} $element - Родительский элемент
@@ -611,15 +676,51 @@ class VGFormSender extends BaseModule {
611
676
  * @returns {HTMLElement} - DOM-элемент с контентом
612
677
  */
613
678
  setDataRelationStatus($element, status, data, type) {
614
- let response = normalizeData(data.response) || data,
615
- $alert = Selectors.find('.'+ CLASS_NAME_ALERT +'-content', $element);
679
+ let $alert = Selectors.find('.'+ CLASS_NAME_ALERT +'-content', $element);
680
+ const response = this._prepareAlertResponse(status, data);
681
+ const title = response.title
682
+ ? Html('string').h4({class: CLASS_NAME_ALERT +'-content--title'}, response.title)
683
+ : '';
684
+ const content = title + response.message;
685
+
686
+ if (!$alert) {
687
+ const elm = Html('dom');
688
+
689
+ $alert = elm.div({
690
+ class: CLASS_NAME_ALERT + '-' + type
691
+ }, [
692
+ elm.div({class: CLASS_NAME_ALERT + '-content'}, [
693
+ elm.i({class: CLASS_NAME_ALERT + '-content--icon'}, getSVG(status), {isHTML: true}),
694
+ elm.div({class: CLASS_NAME_ALERT + '-content--text'}, content, {isHTML: true})
695
+ ]),
696
+ ]);
697
+ } else {
698
+ let text = Selectors.find('.vg-modal-body', $element);
699
+ text.innerHTML = content;
700
+ }
701
+
702
+ return $alert;
703
+ }
704
+
705
+ /**
706
+ * Подготовка содержимого алерта
707
+ * @param {string} status - Статус алерта
708
+ * @param {Object|string} data - Данные ответа
709
+ * @returns {{title: string, message: string}}
710
+ * @private
711
+ */
712
+ _prepareAlertResponse(status, data) {
713
+ let response = normalizeData(data?.response) || data;
616
714
 
617
715
  if (isObject(data)) {
618
- let view = '';
716
+ if (isObject(data.response) && 'view' in data.response) {
717
+ return {
718
+ title: '',
719
+ message: data.response.view
720
+ };
721
+ }
619
722
 
620
- if ('view' in data.response) {
621
- response = data.response.view
622
- } else if (typeof response !== 'string') {
723
+ if (typeof response !== 'string') {
623
724
  if (status === 'danger') {
624
725
  response.title = ('title' in response) ? response.title : lang_titles(this._params.lang, 'errors').title;
625
726
 
@@ -646,7 +747,7 @@ class VGFormSender extends BaseModule {
646
747
  if (isObject(errors)) {
647
748
  for (const error in errors) {
648
749
  if (Array.isArray(errors[error])) {
649
- errors[error].forEach((t) => response.message.push(t))
750
+ errors[error].forEach((text) => response.message.push(text))
650
751
  } else {
651
752
  response.message.push(errors[error]);
652
753
  }
@@ -656,42 +757,31 @@ class VGFormSender extends BaseModule {
656
757
  }
657
758
 
658
759
  const elm = Html('string');
659
-
660
- view = elm.h4({class: CLASS_NAME_ALERT +'-content--title'}, response.title);
760
+ let message = '';
661
761
 
662
762
  if (Array.isArray(response.message)) {
663
- response.message.forEach(message => {
664
- view += elm.div({
763
+ response.message.forEach((text) => {
764
+ message += elm.div({
665
765
  class: CLASS_NAME_ALERT +'-content--message'
666
- }, message);
766
+ }, text);
667
767
  })
668
768
  } else {
669
- view += elm.div({
769
+ message = elm.div({
670
770
  class: CLASS_NAME_ALERT +'-content--message'
671
771
  }, response.message);
672
772
  }
673
773
 
674
- response = view;
774
+ return {
775
+ title: response.title || '',
776
+ message: message
777
+ };
675
778
  }
676
779
  }
677
780
 
678
- if (!$alert) {
679
- const elm = Html('dom');
680
-
681
- $alert = elm.div({
682
- class: CLASS_NAME_ALERT + '-' + type
683
- }, [
684
- elm.div({class: CLASS_NAME_ALERT + '-content'}, [
685
- elm.i({class: CLASS_NAME_ALERT + '-content--icon'}, getSVG(status), {isHTML: true}),
686
- elm.div({class: CLASS_NAME_ALERT + '-content--text'}, response, {isHTML: true})
687
- ]),
688
- ]);
689
- } else {
690
- let text = Selectors.find('.vg-modal-body', $element);
691
- text.innerHTML = response;
692
- }
693
-
694
- return $alert;
781
+ return {
782
+ title: '',
783
+ message: typeof response === 'string' ? response : ''
784
+ };
695
785
  }
696
786
 
697
787
  /**