mypgs 1.1.2 → 1.3.2

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 (40) hide show
  1. package/README.md +124 -11
  2. package/assets/javascript/_imports.js +25 -0
  3. package/assets/javascript/_pgs.js +37 -1
  4. package/assets/javascript/components/_accordion.js +105 -66
  5. package/assets/javascript/components/_dropdown.js +51 -5
  6. package/assets/javascript/components/_menu.js +71 -6
  7. package/assets/javascript/components/_modals.js +45 -3
  8. package/assets/javascript/components/_notifications.js +163 -0
  9. package/assets/javascript/components/_slides.js +12 -1
  10. package/assets/javascript/components/_stepTabs.js +18 -5
  11. package/assets/javascript/components/_steps.js +33 -6
  12. package/assets/javascript/functions/_formValidate.js +4 -5
  13. package/assets/javascript/index.js +8 -4
  14. package/assets/javascript/patterns/_header.js +1 -1
  15. package/assets/javascript/pgs.d.ts +51 -16
  16. package/assets/scss/components/_dropdown.scss +19 -26
  17. package/assets/scss/components/_logo.scss +1 -1
  18. package/assets/scss/components/_tooltip.scss +9 -1
  19. package/assets/scss/layout/_pageShell.scss +15 -20
  20. package/assets/scss/mixin/_mx-button.scss +12 -12
  21. package/dist/css/index.css +94 -96
  22. package/dist/css/index.css.map +1 -1
  23. package/dist/css/index.min.css +1 -1
  24. package/dist/index.d.ts +50 -16
  25. package/dist/javascript/index.js +840 -271
  26. package/dist/javascript/index.js.map +1 -1
  27. package/dist/javascript/index.min.js +1 -1
  28. package/package.json +7 -2
  29. package/pgs-html-suggestions.vsix +0 -0
  30. package/templates/components/md-button.html +13 -7
  31. package/templates/components/md-card.html +11 -9
  32. package/templates/components/md-dropdown.html +1 -1
  33. package/templates/components/md-modal.html +4 -4
  34. package/templates/components/md-stepTabs.html +3 -3
  35. package/templates/components/md-tooltip.html +1 -0
  36. package/templates/demo.css +4 -0
  37. package/templates/demo.js +2 -2
  38. package/assets/javascript/components/_exeNotifications.js +0 -85
  39. package/assets/javascript/functions/_notifications.js +0 -74
  40. package/assets/javascript/functions/_sendForm.js +0 -100
@@ -1,6 +1,54 @@
1
1
  /******/ (() => { // webpackBootstrap
2
2
  /******/ var __webpack_modules__ = ({
3
3
 
4
+ /***/ "./assets/javascript/_imports.js"
5
+ /*!***************************************!*\
6
+ !*** ./assets/javascript/_imports.js ***!
7
+ \***************************************/
8
+ (__unused_webpack_module, __webpack_exports__, __webpack_require__) {
9
+
10
+ "use strict";
11
+ __webpack_require__.r(__webpack_exports__);
12
+ /* harmony import */ var _pgs_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./_pgs.js */ "./assets/javascript/_pgs.js");
13
+ /* harmony import */ var _components_accordion_js__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./components/_accordion.js */ "./assets/javascript/components/_accordion.js");
14
+ /* harmony import */ var _components_dropdown_js__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ./components/_dropdown.js */ "./assets/javascript/components/_dropdown.js");
15
+ /* harmony import */ var _components_menu_js__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ./components/_menu.js */ "./assets/javascript/components/_menu.js");
16
+ /* harmony import */ var _components_modals_js__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! ./components/_modals.js */ "./assets/javascript/components/_modals.js");
17
+ /* harmony import */ var _components_notifications_js__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(/*! ./components/_notifications.js */ "./assets/javascript/components/_notifications.js");
18
+ /* harmony import */ var _components_slides_js__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(/*! ./components/_slides.js */ "./assets/javascript/components/_slides.js");
19
+ /* harmony import */ var _components_stepTabs_js__WEBPACK_IMPORTED_MODULE_7__ = __webpack_require__(/*! ./components/_stepTabs.js */ "./assets/javascript/components/_stepTabs.js");
20
+ /* harmony import */ var _components_steps_js__WEBPACK_IMPORTED_MODULE_8__ = __webpack_require__(/*! ./components/_steps.js */ "./assets/javascript/components/_steps.js");
21
+ /* harmony import */ var _functions_formValidate_js__WEBPACK_IMPORTED_MODULE_9__ = __webpack_require__(/*! ./functions/_formValidate.js */ "./assets/javascript/functions/_formValidate.js");
22
+ /* harmony import */ var _functions_scrollY_js__WEBPACK_IMPORTED_MODULE_10__ = __webpack_require__(/*! ./functions/_scrollY.js */ "./assets/javascript/functions/_scrollY.js");
23
+
24
+
25
+
26
+
27
+
28
+
29
+
30
+
31
+
32
+
33
+
34
+
35
+
36
+ _pgs_js__WEBPACK_IMPORTED_MODULE_0__.pgs.registerImport({
37
+ PGS_accordion: _components_accordion_js__WEBPACK_IMPORTED_MODULE_1__.PGS_accordion,
38
+ PGS_dropdown: _components_dropdown_js__WEBPACK_IMPORTED_MODULE_2__.PGS_dropdown,
39
+ PGS_menu: _components_menu_js__WEBPACK_IMPORTED_MODULE_3__.PGS_menu,
40
+ PGS_modal: _components_modals_js__WEBPACK_IMPORTED_MODULE_4__.PGS_modal,
41
+ PGS_notification: _components_notifications_js__WEBPACK_IMPORTED_MODULE_5__.PGS_notification,
42
+ PGS_slides: _components_slides_js__WEBPACK_IMPORTED_MODULE_6__.PGS_slides,
43
+ PGS_stepTabs: _components_stepTabs_js__WEBPACK_IMPORTED_MODULE_7__.PGS_stepTabs,
44
+ PGS_steps: _components_steps_js__WEBPACK_IMPORTED_MODULE_8__.PGS_steps,
45
+ PGS_formValidate: _functions_formValidate_js__WEBPACK_IMPORTED_MODULE_9__.PGS_formValidate,
46
+ PGS_scrollHorizontal: _functions_scrollY_js__WEBPACK_IMPORTED_MODULE_10__.PGS_scrollHorizontal,
47
+ });
48
+
49
+
50
+ /***/ },
51
+
4
52
  /***/ "./assets/javascript/_pgs.js"
5
53
  /*!***********************************!*\
6
54
  !*** ./assets/javascript/_pgs.js ***!
@@ -238,9 +286,45 @@ function pgs(root) {
238
286
  return api;
239
287
  }
240
288
 
241
- globalThis.pgs ??= pgs;
289
+ const PGS_IMPORTS = {};
290
+
291
+ function registerImportModule(name, module) {
292
+ const key = String(name || "").trim().replace(/^pgs[_-\s]*/i, "").toLowerCase();
293
+
294
+ if (!key) throw new TypeError("pgs.registerImport(...modules): ogni modulo deve avere name o PGS_name");
295
+
296
+ PGS_IMPORTS[key] = {
297
+ name,
298
+ module
299
+ };
300
+ }
242
301
 
302
+ pgs.registerImport = function (...modules) {
303
+ modules.flat().forEach(item => {
304
+ if (item && typeof item === "object" && !item.PGS_name && !item.name) {
305
+ Object.entries(item).forEach(([name, module]) => registerImportModule(name, module));
306
+ return;
307
+ }
308
+
309
+ registerImportModule(item?.PGS_name || item?.name, item);
310
+ });
243
311
 
312
+ return pgs;
313
+ };
314
+
315
+ pgs.import = function (...names) {
316
+ return names.flat().reduce((imports, name) => {
317
+ const key = String(name || "").trim().replace(/^pgs[_-\s]*/i, "").toLowerCase();
318
+ const item = PGS_IMPORTS[key];
319
+
320
+ if (!item) throw new Error(`pgs.import(): modulo "${name}" non registrato`);
321
+
322
+ imports[item.name] = item.module;
323
+ return imports;
324
+ }, {});
325
+ };
326
+
327
+ globalThis.pgs ??= pgs;
244
328
 
245
329
 
246
330
  /***/ },
@@ -432,85 +516,131 @@ document.addEventListener('DOMContentLoaded', () => {
432
516
  /*!****************************************************!*\
433
517
  !*** ./assets/javascript/components/_accordion.js ***!
434
518
  \****************************************************/
435
- () {
519
+ (__unused_webpack_module, __webpack_exports__, __webpack_require__) {
436
520
 
437
- //= ACCORDION
438
- const allAccordion = pgs(document).querySelectorAll("accordion")
521
+ "use strict";
522
+ __webpack_require__.r(__webpack_exports__);
523
+ /* harmony export */ __webpack_require__.d(__webpack_exports__, {
524
+ /* harmony export */ PGS_accordion: () => (/* binding */ PGS_accordion),
525
+ /* harmony export */ PGS_accordion_api: () => (/* binding */ PGS_accordion_api),
526
+ /* harmony export */ PGS_accordion_init: () => (/* binding */ PGS_accordion_init)
527
+ /* harmony export */ });
528
+ //= ACCORDION
529
+ const API = new WeakMap();
439
530
 
440
- allAccordion.forEach((accordion, index) => {
531
+ function PGS_accordion_init(root = document) {
532
+ pgs(root).querySelectorAll("accordion").forEach((accordion, index) => {
533
+ if (API.has(accordion)) return;
441
534
 
442
- const BUTTON = pgs(accordion).querySelector("accordion-button");
443
- const CONTENT = pgs(accordion).querySelector("accordion-content");
535
+ const BUTTON = pgs(accordion).querySelector("accordion-button");
536
+ const CONTENT = pgs(accordion).querySelector("accordion-content");
537
+ if (!BUTTON || !CONTENT) return;
444
538
 
445
- //== ID univoci per aria-controls / aria-labelledby
446
- const ID = index + 1;
447
- const btnId = `acc-btn-${ID}`;
448
- const panelId = `acc-panel-${ID}`;
539
+ //== ID univoci per aria-controls / aria-labelledby
540
+ const ID = index + 1;
541
+ const btnId = `acc-btn-${ID}`;
542
+ const panelId = `acc-panel-${ID}`;
543
+
544
+ //== Stato iniziale
545
+ const isOpenInit = pgs(accordion).state.contains("open");
546
+
547
+ //== Accessibilità (setup una volta)
548
+ BUTTON.setAttribute("role", "button");
549
+ BUTTON.setAttribute("tabindex", "0");
550
+ BUTTON.setAttribute("id", btnId);
551
+ BUTTON.setAttribute("aria-controls", panelId);
552
+
553
+ CONTENT.setAttribute("id", panelId);
554
+ CONTENT.setAttribute("role", "region");
555
+ CONTENT.setAttribute("aria-labelledby", btnId);
556
+
557
+ //+ Accessibility (applica stato aperto/chiuso)
558
+ function accordionAccessibility(isOpen, button, content) {
559
+ const text = (button?.textContent || "").trim().replace(/\s+/g, " ");
560
+ button.setAttribute("aria-label", `${isOpen ? "Chiudi" : "Apri"} ${text || "sezione"}`);
561
+ button.setAttribute("aria-expanded", String(isOpen));
562
+ content.hidden = !isOpen;
563
+ }
449
564
 
450
- //== Stato iniziale
451
- const isOpenInit = pgs(accordion).state.contains("open");
565
+ //+ Chiudi tutti gli altri
566
+ function closeOltherAccordion() {
567
+ for (const otherLi of pgs(document).querySelectorAll("accordion")) {
568
+ if (otherLi === accordion) continue;
452
569
 
453
- //== Accessibilità (setup una volta)
454
- BUTTON.setAttribute("role", "button");
455
- BUTTON.setAttribute("tabindex", "0");
456
- BUTTON.setAttribute("id", btnId);
457
- BUTTON.setAttribute("aria-controls", panelId);
570
+ const otherBtn = pgs(otherLi).querySelector("accordion-button");
571
+ const otherContent = pgs(otherLi).querySelector("accordion-content");
572
+ if (!otherBtn || !otherContent) continue;
458
573
 
459
- CONTENT.setAttribute("id", panelId);
460
- CONTENT.setAttribute("role", "region");
461
- CONTENT.setAttribute("aria-labelledby", btnId);
574
+ pgs(otherLi).state().remove("open");
575
+ accordionAccessibility(false, otherBtn, otherContent);
576
+ }
577
+ }
462
578
 
463
- //+ Accessibility (applica stato aperto/chiuso)
464
- function accordionAccessibility(isOpen, button, content) {
465
- const text = (button?.textContent || "").trim().replace(/\s+/g, " ");
466
- button.setAttribute("aria-label", `${isOpen ? "Chiudi" : "Apri"} ${text || "sezione"}`);
467
- button.setAttribute("aria-expanded", String(isOpen));
468
- content.hidden = !isOpen;
469
- }
579
+ //+ FN ACCORDION
580
+ function accordionFunction() {
581
+ const isOpen = pgs(accordion).state.contains("open");
582
+ const nowOpen = !isOpen;
470
583
 
471
- //+ Chiudi tutti gli altri
472
- function closeOltherAccordion() {
473
- for (const otherLi of allAccordion) {
474
- if (otherLi === accordion) continue;
584
+ pgs(accordion).state.toggle("open", nowOpen);
585
+ accordionAccessibility(nowOpen, BUTTON, CONTENT);
475
586
 
476
- const otherBtn = pgs(otherLi).querySelector("accordion-button");
477
- const otherContent = pgs(otherLi).querySelector("accordion-content");
478
- if (!otherBtn || !otherContent) continue;
587
+ closeOltherAccordion();
479
588
 
480
- pgs(otherLi).state().remove("open");
481
- accordionAccessibility(false, otherBtn, otherContent);
589
+ //== scroll to view
590
+ if (nowOpen) setTimeout(() => accordion.scrollIntoView({ block: "nearest", inline: "nearest" }), 100);
482
591
  }
483
- }
484
592
 
485
- //+ FN ACCORDION
486
- function accordionFunction() {
487
- const isOpen = pgs(accordion).state.contains("open");
488
- const nowOpen = !isOpen;
489
-
490
- pgs(accordion).state.toggle("open", nowOpen);
491
- accordionAccessibility(nowOpen, BUTTON, CONTENT);
593
+ function open() {
594
+ if (!pgs(accordion).state.contains("open")) accordionFunction();
595
+ }
492
596
 
493
- closeOltherAccordion();
597
+ function close() {
598
+ if (pgs(accordion).state.contains("open")) accordionFunction();
599
+ }
494
600
 
495
- //== scroll to view
496
- if (nowOpen) setTimeout(() => accordion.scrollIntoView({ block: "nearest", inline: "nearest" }), 100);
497
- }
601
+ // applica stato iniziale
602
+ accordionAccessibility(isOpenInit, BUTTON, CONTENT);
498
603
 
499
- // applica stato iniziale
500
- accordionAccessibility(isOpenInit, BUTTON, CONTENT);
604
+ //- Eventi
605
+ BUTTON.addEventListener("click", accordionFunction);
501
606
 
502
- //- Eventi
503
- BUTTON.addEventListener("click", accordionFunction);
607
+ //- Tastiera: Enter / Space
608
+ BUTTON.addEventListener("keydown", (e) => {
609
+ if (e.key === "Enter" || e.key === " ") {
610
+ e.preventDefault();
611
+ accordionFunction();
612
+ }
613
+ });
504
614
 
505
- //- Tastiera: Enter / Space
506
- BUTTON.addEventListener("keydown", (e) => {
507
- if (e.key === "Enter" || e.key === " ") {
508
- e.preventDefault();
509
- accordionFunction();
510
- }
615
+ API.set(accordion, {
616
+ element: accordion,
617
+ button: BUTTON,
618
+ content: CONTENT,
619
+ open,
620
+ close,
621
+ toggle: accordionFunction,
622
+ refresh: () => {
623
+ PGS_accordion_init(accordion.parentNode || document);
624
+ return API.get(accordion);
625
+ },
626
+ isOpen: () => pgs(accordion).state.contains("open"),
627
+ });
511
628
  });
629
+ }
512
630
 
513
- });
631
+ //# INIT
632
+ PGS_accordion_init();
633
+
634
+ //# API
635
+ function PGS_accordion_api(selector) {
636
+ return API.get(selector);
637
+ }
638
+
639
+ const PGS_accordion = {
640
+ PGS_name: "PGS_accordion",
641
+ init: PGS_accordion_init,
642
+ api: PGS_accordion_api
643
+ };
514
644
 
515
645
 
516
646
  /***/ },
@@ -524,11 +654,17 @@ allAccordion.forEach((accordion, index) => {
524
654
  "use strict";
525
655
  __webpack_require__.r(__webpack_exports__);
526
656
  /* harmony export */ __webpack_require__.d(__webpack_exports__, {
527
- /* harmony export */ pgs_dropdown: () => (/* binding */ pgs_dropdown)
657
+ /* harmony export */ PGS_dropdown: () => (/* binding */ PGS_dropdown),
658
+ /* harmony export */ PGS_dropdown_api: () => (/* binding */ PGS_dropdown_api),
659
+ /* harmony export */ PGS_dropdown_init: () => (/* binding */ PGS_dropdown_init)
528
660
  /* harmony export */ });
529
661
  // + dropdown (Popover API)
530
- function pgs_dropdown() {
531
- pgs(document).querySelectorAll("dropdown").forEach((DROPDOWN, index) => {
662
+ const API = new WeakMap();
663
+
664
+ function PGS_dropdown_init(root = document) {
665
+ pgs(root).querySelectorAll("dropdown").forEach((DROPDOWN, index) => {
666
+ if (API.has(DROPDOWN)) return;
667
+
532
668
  const BUTTON = pgs(DROPDOWN).querySelector("dropdown-button");
533
669
  const CONTENT = pgs(DROPDOWN).querySelector("dropdown-content");
534
670
 
@@ -562,9 +698,10 @@ function pgs_dropdown() {
562
698
  CSS.supports("position-anchor: --dropdown-anchor") &&
563
699
  CSS.supports("position-area: bottom") &&
564
700
  CSS.supports("top: anchor(bottom)");
701
+ const USE_FALLBACK_POSITIONING = pgs(DROPDOWN).contains("tooltip") || !HAS_ANCHOR_POSITIONING;
565
702
 
566
703
  const updatePopoverPosition = () => {
567
- if (HAS_ANCHOR_POSITIONING) return;
704
+ if (!USE_FALLBACK_POSITIONING) return;
568
705
 
569
706
  const buttonRect = BUTTON.getBoundingClientRect();
570
707
  const style = getComputedStyle(DROPDOWN);
@@ -599,7 +736,7 @@ function pgs_dropdown() {
599
736
  };
600
737
 
601
738
  BUTTON.addEventListener("click", e => {
602
- if (HAS_ANCHOR_POSITIONING) return;
739
+ if (!USE_FALLBACK_POSITIONING) return;
603
740
 
604
741
  e.preventDefault();
605
742
  if (CONTENT.matches(":popover-open")) {
@@ -628,112 +765,52 @@ function pgs_dropdown() {
628
765
  window.addEventListener("scroll", () => {
629
766
  if (CONTENT.matches(":popover-open")) updatePopoverPosition();
630
767
  }, true);
631
- });
632
- }
633
768
 
634
- // # INIT
635
- pgs_dropdown();
636
-
637
-
638
- /***/ },
639
-
640
- /***/ "./assets/javascript/components/_exeNotifications.js"
641
- /*!***********************************************************!*\
642
- !*** ./assets/javascript/components/_exeNotifications.js ***!
643
- \***********************************************************/
644
- (__unused_webpack_module, __webpack_exports__, __webpack_require__) {
645
-
646
- "use strict";
647
- __webpack_require__.r(__webpack_exports__);
648
- /* harmony export */ __webpack_require__.d(__webpack_exports__, {
649
- /* harmony export */ PGS_md_notification: () => (/* binding */ PGS_md_notification)
650
- /* harmony export */ });
651
- /* harmony import */ var _functions_notifications_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ../functions/_notifications.js */ "./assets/javascript/functions/_notifications.js");
652
-
653
-
654
- function escapeHtml(value) {
655
- return String(value ?? "");
656
- }
657
-
658
- function getDuration(notification) {
659
- const rawDuration = notification.duration;
660
- const duration = Number.parseInt(rawDuration, 10);
661
-
662
- return Number.isNaN(duration) ? 5000 : duration;
663
- }
664
-
665
- function getNotificationApi(notification) {
666
- const element = String(notification.element || "notification").trim();
667
-
668
- return element === "toast" ? _functions_notifications_js__WEBPACK_IMPORTED_MODULE_0__.PGS_toast : _functions_notifications_js__WEBPACK_IMPORTED_MODULE_0__.PGS_notification;
669
- }
670
-
671
- function getNotificationType(notification, api) {
672
- const type = String(notification.type || "info").trim();
673
-
674
- return typeof api[type] === "function" ? type : "info";
675
- }
676
-
677
- function getNotificationData(root) {
678
- try {
679
- return JSON.parse(root.dataset.notification || "{}");
680
- } catch (error) {
681
- console.warn("PGS notification: dati non validi", error);
682
- return {};
683
- }
684
- }
769
+ function open() {
770
+ if (CONTENT.matches(":popover-open")) return;
771
+ updatePopoverPosition();
772
+ CONTENT.showPopover();
773
+ }
685
774
 
686
- function getNotificationContent(title, content) {
687
- const safeContent = escapeHtml(content);
688
- const safeTitle = escapeHtml(title);
775
+ function close() {
776
+ if (!CONTENT.matches(":popover-open")) return;
777
+ CONTENT.hidePopover();
778
+ }
689
779
 
690
- if (!safeTitle) return safeContent;
691
- if (!safeContent) return `<span pgs="notification-element-title">${safeTitle}</span>`;
780
+ function toggle() {
781
+ CONTENT.matches(":popover-open") ? close() : open();
782
+ }
692
783
 
693
- return `
694
- <span pgs="notification-element-title">${safeTitle}</span>
695
- <br>
696
- <span pgs="notification-element-content">${safeContent}</span>
697
- `;
784
+ API.set(DROPDOWN, {
785
+ element: DROPDOWN,
786
+ button: BUTTON,
787
+ content: CONTENT,
788
+ open,
789
+ close,
790
+ toggle,
791
+ updatePosition: updatePopoverPosition,
792
+ refresh: () => {
793
+ PGS_dropdown_init(DROPDOWN.parentNode || document);
794
+ return API.get(DROPDOWN);
795
+ },
796
+ isOpen: () => CONTENT.matches(":popover-open"),
797
+ });
798
+ });
698
799
  }
699
800
 
700
- function PGS_md_notification(root) {
701
- if (!root || root.dataset.initialize === "true") return;
702
- root.dataset.initialize = "true";
703
-
704
- const notification = getNotificationData(root);
705
- const title = String(notification.title || "").trim();
706
- const content = String(notification.message || "").trim();
707
- if (!title && !content) {
708
- root.remove();
709
- return;
710
- }
711
-
712
- const link = notification.link || null;
713
- const icon = notification.icon || undefined;
714
- const duration = getDuration(notification);
715
- const api = getNotificationApi(notification);
716
- const type = getNotificationType(notification, api);
717
- const formattedContent = getNotificationContent(title, content);
718
-
719
- if (api === _functions_notifications_js__WEBPACK_IMPORTED_MODULE_0__.PGS_toast) {
720
- api[type](formattedContent, duration, icon);
721
- } else {
722
- api[type](formattedContent, link, duration, icon);
723
- }
724
-
725
- root.remove();
726
- }
801
+ // # INIT
802
+ PGS_dropdown_init();
727
803
 
728
- function initMdNotifications() {
729
- pgs(document).querySelectorAll("notificationTrigger").forEach(PGS_md_notification);
804
+ // # API
805
+ function PGS_dropdown_api(selector) {
806
+ return API.get(selector);
730
807
  }
731
808
 
732
- if (document.readyState === "loading") {
733
- document.addEventListener("DOMContentLoaded", initMdNotifications);
734
- } else {
735
- initMdNotifications();
736
- }
809
+ const PGS_dropdown = {
810
+ PGS_name: "PGS_dropdown",
811
+ init: PGS_dropdown_init,
812
+ api: PGS_dropdown_api
813
+ };
737
814
 
738
815
 
739
816
  /***/ },
@@ -747,19 +824,25 @@ if (document.readyState === "loading") {
747
824
  "use strict";
748
825
  __webpack_require__.r(__webpack_exports__);
749
826
  /* harmony export */ __webpack_require__.d(__webpack_exports__, {
750
- /* harmony export */ PGS_menu: () => (/* binding */ PGS_menu)
827
+ /* harmony export */ PGS_menu: () => (/* binding */ PGS_menu),
828
+ /* harmony export */ PGS_menu_api: () => (/* binding */ PGS_menu_api),
829
+ /* harmony export */ PGS_menu_init: () => (/* binding */ PGS_menu_init)
751
830
  /* harmony export */ });
752
831
  /* harmony import */ var _dropdown__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./_dropdown */ "./assets/javascript/components/_dropdown.js");
753
832
 
754
833
 
834
+ const API = new WeakMap();
835
+
755
836
  //= DROP DOWN MENU
756
- function PGS_menu() {
837
+ function PGS_menu_init(root = document) {
757
838
 
758
- pgs(document).querySelectorAll('menu-horizontal').forEach(MENU => {
839
+ pgs(root).querySelectorAll('menu-horizontal').forEach(MENU => {
840
+ if (API.has(MENU)) return;
759
841
 
760
842
  MENU.querySelectorAll('nav > ul > li.menu-item-has-children').forEach(li => {
761
843
  if (li.querySelector("ul")) {
762
844
  const ul = li.querySelector("ul");
845
+ if (pgs(li).querySelector("dropdown-button")) return;
763
846
 
764
847
  const button = document.createElement("button");
765
848
  button.className = "icon-down";
@@ -774,14 +857,28 @@ function PGS_menu() {
774
857
  pgs(ul).add("menu-vertical")
775
858
  }
776
859
  });
860
+
861
+ API.set(MENU, {
862
+ element: MENU,
863
+ type: "horizontal",
864
+ items: () => Array.from(MENU.querySelectorAll('nav > ul > li')),
865
+ submenus: () => Array.from(MENU.querySelectorAll('.menu-item-has-children > ul')),
866
+ dropdowns: () => Array.from(MENU.querySelectorAll('.menu-item-has-children')).map(_dropdown__WEBPACK_IMPORTED_MODULE_0__.PGS_dropdown_api).filter(Boolean),
867
+ refresh: () => {
868
+ PGS_menu_init(MENU.parentNode || document);
869
+ return API.get(MENU);
870
+ },
871
+ });
777
872
  });
778
873
 
779
- pgs(document).querySelectorAll('menu-vertical').forEach(MENU => {
874
+ pgs(root).querySelectorAll('menu-vertical').forEach(MENU => {
875
+ if (API.has(MENU)) return;
780
876
 
781
877
  MENU.querySelectorAll('.menu-item-has-children').forEach((li, index) => {
782
878
  const ul = li.querySelector("ul");
783
879
 
784
880
  if (!ul) return
881
+ if (li.querySelector(":scope > button")) return;
785
882
 
786
883
  const button = document.createElement("button");
787
884
  button.className = "icon-down buttonIcon";
@@ -816,6 +913,42 @@ function PGS_menu() {
816
913
  });
817
914
  });
818
915
 
916
+ function submenu(index) {
917
+ return MENU.querySelectorAll('.menu-item-has-children > ul')[index];
918
+ }
919
+
920
+ function setSubmenu(index, open) {
921
+ const ul = submenu(index);
922
+ const button = ul?.parentElement?.querySelector(":scope > button");
923
+ if (!ul || !button) return;
924
+
925
+ pgs(ul).state.toggle("open", open);
926
+ button.setAttribute("aria-expanded", String(open));
927
+ button.setAttribute("aria-label", open ? "Chiudi sottomenu" : "Apri sottomenu");
928
+ }
929
+
930
+ API.set(MENU, {
931
+ element: MENU,
932
+ type: "vertical",
933
+ items: () => Array.from(MENU.querySelectorAll(':scope > li')),
934
+ submenus: () => Array.from(MENU.querySelectorAll('.menu-item-has-children > ul')),
935
+ openSubmenu: (index) => setSubmenu(index, true),
936
+ closeSubmenu: (index) => setSubmenu(index, false),
937
+ toggleSubmenu: (index) => {
938
+ const ul = submenu(index);
939
+ if (!ul) return;
940
+ setSubmenu(index, !pgs(ul).state.contains("open"));
941
+ },
942
+ isSubmenuOpen: (index) => {
943
+ const ul = submenu(index);
944
+ return ul ? pgs(ul).state.contains("open") : false;
945
+ },
946
+ refresh: () => {
947
+ PGS_menu_init(MENU.parentNode || document);
948
+ return API.get(MENU);
949
+ },
950
+ });
951
+
819
952
  // pgs(document).querySelectorAll('menu-vertical').forEach(MENU => {
820
953
 
821
954
  // MENU.querySelectorAll('.menu-item-has-children').forEach(li => {
@@ -837,11 +970,23 @@ function PGS_menu() {
837
970
  // });
838
971
  // });
839
972
  });
840
- (0,_dropdown__WEBPACK_IMPORTED_MODULE_0__.pgs_dropdown)()
973
+ (0,_dropdown__WEBPACK_IMPORTED_MODULE_0__.PGS_dropdown_init)()
841
974
  }
842
975
 
843
976
  //# INIT PGS_menu
844
- PGS_menu()
977
+ PGS_menu_init()
978
+
979
+ //# API
980
+ function PGS_menu_api(selector) {
981
+ return API.get(selector);
982
+ }
983
+
984
+ const PGS_menu = {
985
+ PGS_name: "PGS_menu",
986
+ init: PGS_menu_init,
987
+ api: PGS_menu_api
988
+ };
989
+
845
990
 
846
991
  /***/ },
847
992
 
@@ -854,12 +999,16 @@ PGS_menu()
854
999
  "use strict";
855
1000
  __webpack_require__.r(__webpack_exports__);
856
1001
  /* harmony export */ __webpack_require__.d(__webpack_exports__, {
857
- /* harmony export */ PGS_modal: () => (/* binding */ PGS_modal)
1002
+ /* harmony export */ PGS_modal: () => (/* binding */ PGS_modal),
1003
+ /* harmony export */ PGS_modal_api: () => (/* binding */ PGS_modal_api),
1004
+ /* harmony export */ PGS_modal_init: () => (/* binding */ PGS_modal_init)
858
1005
  /* harmony export */ });
859
1006
  //# MODAL
860
- PGS_modal()
861
- function PGS_modal(selector = "modal") {
1007
+ const API = new WeakMap();
1008
+
1009
+ function PGS_modal_init(selector = "modal") {
862
1010
  pgs(document).querySelectorAll(selector).forEach(MODAL => {
1011
+ if (API.has(MODAL)) return;
863
1012
 
864
1013
  const BUTTON_OPEN = pgs(MODAL).querySelector("modal-button");
865
1014
  const DIALOG = MODAL.querySelector("dialog");
@@ -912,9 +1061,14 @@ function PGS_modal(selector = "modal") {
912
1061
  //+ FN OPEN
913
1062
  function openModal(e) {
914
1063
  e?.stopImmediatePropagation();
1064
+ if (DIALOG.open) {
1065
+ closeModal(e);
1066
+ return;
1067
+ }
1068
+
915
1069
  if (!DIALOG.open) document.querySelectorAll("dialog[open]").forEach((dlg) => dlg.close());
916
1070
  statusModal(true);
917
- DIALOG.open ? closeModal(e) : topLevel ? DIALOG.showModal() : DIALOG.show();
1071
+ topLevel ? DIALOG.showModal() : DIALOG.show();
918
1072
  // modalCustomEvents('modal:open', { event: e });
919
1073
  MODAL.dispatchEvent(new CustomEvent('modal:open'));
920
1074
  DIALOG.dispatchEvent(new CustomEvent('modal:open'));
@@ -930,6 +1084,14 @@ function PGS_modal(selector = "modal") {
930
1084
  DIALOG.dispatchEvent(new CustomEvent('modal:close'));
931
1085
  }
932
1086
 
1087
+ function forceOpen(e) {
1088
+ if (!DIALOG.open) openModal(e);
1089
+ }
1090
+
1091
+ function forceClose(e) {
1092
+ if (DIALOG.open) closeModal(e);
1093
+ }
1094
+
933
1095
  //+ fn OPEN ON HISTORY
934
1096
  function openModalOnHistory() {
935
1097
  const params = new URLSearchParams(window.location.search);
@@ -975,10 +1137,216 @@ function PGS_modal(selector = "modal") {
975
1137
  } catch (_) { }
976
1138
  });
977
1139
  }
1140
+
1141
+ API.set(MODAL, {
1142
+ element: MODAL,
1143
+ button: BUTTON_OPEN,
1144
+ dialog: DIALOG,
1145
+ closeButton: BUTTON_CLOSE,
1146
+ open: forceOpen,
1147
+ close: forceClose,
1148
+ toggle: openModal,
1149
+ refresh: () => {
1150
+ PGS_modal_init(selector);
1151
+ return API.get(MODAL);
1152
+ },
1153
+ isOpen: () => DIALOG.open,
1154
+ });
978
1155
  });
979
1156
  }
980
1157
 
981
1158
  //# INIT PGS_modal
1159
+ PGS_modal_init()
1160
+
1161
+ //# API
1162
+ function PGS_modal_api(selector) {
1163
+ return API.get(selector);
1164
+ }
1165
+
1166
+ const PGS_modal = {
1167
+ PGS_name: "PGS_modal",
1168
+ init: PGS_modal_init,
1169
+ api: PGS_modal_api
1170
+ };
1171
+
1172
+
1173
+ /***/ },
1174
+
1175
+ /***/ "./assets/javascript/components/_notifications.js"
1176
+ /*!********************************************************!*\
1177
+ !*** ./assets/javascript/components/_notifications.js ***!
1178
+ \********************************************************/
1179
+ (__unused_webpack_module, __webpack_exports__, __webpack_require__) {
1180
+
1181
+ "use strict";
1182
+ __webpack_require__.r(__webpack_exports__);
1183
+ /* harmony export */ __webpack_require__.d(__webpack_exports__, {
1184
+ /* harmony export */ PGS_notification: () => (/* binding */ PGS_notification),
1185
+ /* harmony export */ PGS_notificationTrigger_init: () => (/* binding */ PGS_notificationTrigger_init)
1186
+ /* harmony export */ });
1187
+ //= PGS_notification
1188
+ const fn_notification = {
1189
+ _escapeHtml(value) {
1190
+ return String(value ?? "");
1191
+ },
1192
+
1193
+ _getDuration(notification) {
1194
+ const rawDuration = notification.duration;
1195
+ const duration = Number.parseInt(rawDuration, 10);
1196
+
1197
+ return Number.isNaN(duration) ? 5000 : duration;
1198
+ },
1199
+
1200
+ _getApi(notification) {
1201
+ const element = String(notification.element || "notification").trim();
1202
+
1203
+ return element === "toast" ? PGS_notification.toast : PGS_notification.alert;
1204
+ },
1205
+
1206
+ _getType(notification, api) {
1207
+ const type = String(notification.type || "info").trim();
1208
+
1209
+ return typeof api[type] === "function" ? type : "info";
1210
+ },
1211
+
1212
+ _getData(root) {
1213
+ try {
1214
+ return JSON.parse(root.dataset.notification || "{}");
1215
+ } catch (error) {
1216
+ console.warn("PGS notification: dati non validi", error);
1217
+ return {};
1218
+ }
1219
+ },
1220
+
1221
+ _getContent(title, content) {
1222
+ const safeContent = this._escapeHtml(content);
1223
+ const safeTitle = this._escapeHtml(title);
1224
+
1225
+ if (!safeTitle) return safeContent;
1226
+ if (!safeContent) return `<span pgs="notification-element-title">${safeTitle}</span>`;
1227
+
1228
+ return `
1229
+ <span pgs="notification-element-title">${safeTitle}</span>
1230
+ <br>
1231
+ <span pgs="notification-element-content">${safeContent}</span>
1232
+ `;
1233
+ },
1234
+
1235
+ initNotification(type, containerToken, icon, text, timeout, methodDelete = "replace", link = null) {
1236
+ let containerNotification = pgs(document).querySelector(containerToken);
1237
+
1238
+ //== Create Container
1239
+ if (!containerNotification) {
1240
+ const newContainer = document.createElement("div");
1241
+ pgs(newContainer).add(containerToken);
1242
+ newContainer.setAttribute("aria-live", "polite");
1243
+ newContainer.setAttribute("aria-relevant", "additions");
1244
+ document.body.appendChild(newContainer);
1245
+ containerNotification = newContainer;
1246
+ }
1247
+
1248
+ //== Create Notification
1249
+ const notification = document.createElement(link ? "a" : "div");
1250
+ if (methodDelete == "replace") containerNotification.innerHTML = "";
1251
+ if (link) notification.href = link;
1252
+ if (timeout > 0) notification.style.setProperty("--notification-timeout", timeout + "ms");
1253
+ pgs(notification).state.add(type);
1254
+ pgs(notification).add("notification-element");
1255
+ notification.setAttribute("role", type == "error" ? "alert" : "status")
1256
+ notification.innerHTML = `${icon} <p>${text}</p>`;
1257
+ containerNotification.appendChild(notification);
1258
+
1259
+
1260
+ //+ Animation delete
1261
+ function deleteNotification() {
1262
+ methodDelete == "stack" ? notification.style.translate = "120%" : notification.style.opacity = "0";
1263
+ setTimeout(() => notification.remove(), 300);
1264
+ }
1265
+
1266
+ //== Timeout delete
1267
+ if (timeout > 0) setTimeout(() => { deleteNotification() }, timeout);
1268
+
1269
+ //== button delete
1270
+ const btnDelete = document.createElement("button");
1271
+ btnDelete.type = "button";
1272
+ btnDelete.ariaLabel = "Rimuovi notifica";
1273
+ btnDelete.innerHTML = '<i class="fa-solid fa-xmark"></i>';
1274
+ btnDelete.setAttribute("pgs", "buttonClose");
1275
+ notification.insertAdjacentElement("afterbegin", btnDelete);
1276
+
1277
+ //== event
1278
+
1279
+ btnDelete.addEventListener("click", function (e) {
1280
+ e.preventDefault();
1281
+ e.stopPropagation();
1282
+ e.stopImmediatePropagation()
1283
+ deleteNotification(e); // Esegue la tua funzione
1284
+ });
1285
+ },
1286
+
1287
+ deleteAll(containerToken) {
1288
+ let containerNotification = pgs(document).querySelector(containerToken);
1289
+ if (containerNotification) containerNotification.innerHTML = "";
1290
+ },
1291
+
1292
+ trigger(root = document) {
1293
+ pgs(root).querySelectorAll("notificationTrigger").forEach(element => {
1294
+ if (!element || element.dataset.initialize === "true") return;
1295
+
1296
+ element.dataset.initialize = "true";
1297
+
1298
+ const notification = this._getData(element);
1299
+ const title = String(notification.title || "").trim();
1300
+ const content = String(notification.message || "").trim();
1301
+
1302
+ if (!title && !content) {
1303
+ element.remove();
1304
+ return;
1305
+ }
1306
+
1307
+ const link = notification.link || null;
1308
+ const icon = notification.icon || undefined;
1309
+ const duration = this._getDuration(notification);
1310
+ const api = this._getApi(notification);
1311
+ const type = this._getType(notification, api);
1312
+ const formattedContent = this._getContent(title, content);
1313
+
1314
+ if (api === PGS_notification.toast) api[type](formattedContent, duration, icon);
1315
+ else api[type](formattedContent, link, duration, icon);
1316
+
1317
+ element.remove();
1318
+ });
1319
+ }
1320
+ };
1321
+
1322
+ //# EXPORT
1323
+ function PGS_notificationTrigger_init(root = document) {
1324
+ return fn_notification.trigger(root);
1325
+ }
1326
+
1327
+ const PGS_notification = {
1328
+ PGS_name: "PGS_notification",
1329
+ trigger: PGS_notificationTrigger_init,
1330
+ alert: {
1331
+ error: (text = "Errore", link = null, timeout = 0, icon = '<i class="fa-solid fa-octagon-xmark"></i>') => fn_notification.initNotification("error", "notification", icon, text, timeout, "stack", link),
1332
+ success: (text = "Aggiornato", link = null, timeout = 0, icon = '<i class="fa-solid fa-check"></i>') => fn_notification.initNotification("success", "notification", icon, text, timeout, "stack", link),
1333
+ info: (text = "Aggiornamento", link = null, timeout = 0, icon = '<i class="fa-solid fa-circle-info"></i>',) => fn_notification.initNotification("info", "notification", icon, text, timeout, "stack", link),
1334
+ warning: (text = "Attenzione", link = null, timeout = 0, icon = '<i class="fa-solid fa-triangle-exclamation"></i>') => fn_notification.initNotification("warning", "notification", icon, text, timeout, "stack", link),
1335
+ deleteAll: () => fn_notification.deleteAll("notification")
1336
+ },
1337
+ toast: {
1338
+ error: (text = "Errore", timeout = 4000, icon = '<i class="fa-solid fa-octagon-xmark"></i>',) => fn_notification.initNotification("error", "toast", icon, text, timeout),
1339
+ success: (text = "Aggiornato", timeout = 4000, icon = '<i class="fa-solid fa-check"></i>',) => fn_notification.initNotification("success", "toast", icon, text, timeout),
1340
+ info: (text = "Aggiornamento", timeout = 0, icon = '<i class="fa-solid fa-circle-info"></i>',) => fn_notification.initNotification("info", "toast", icon, text, timeout),
1341
+ warning: (text = "Attenzione", timeout = 4000, icon = '<i class="fa-solid fa-triangle-exclamation"></i>',) => fn_notification.initNotification("warning", "toast", icon, text, timeout),
1342
+ deleteAll: () => fn_notification.deleteAll("toast")
1343
+ }
1344
+ };
1345
+
1346
+
1347
+ //= EXECUTE
1348
+ if (document.readyState === "loading") document.addEventListener("DOMContentLoaded", () => PGS_notificationTrigger_init());
1349
+ else PGS_notificationTrigger_init();
982
1350
 
983
1351
 
984
1352
  /***/ },
@@ -992,6 +1360,7 @@ function PGS_modal(selector = "modal") {
992
1360
  "use strict";
993
1361
  __webpack_require__.r(__webpack_exports__);
994
1362
  /* harmony export */ __webpack_require__.d(__webpack_exports__, {
1363
+ /* harmony export */ PGS_slides: () => (/* binding */ PGS_slides),
995
1364
  /* harmony export */ PGS_slides_api: () => (/* binding */ PGS_slides_api),
996
1365
  /* harmony export */ PGS_slides_init: () => (/* binding */ PGS_slides_init)
997
1366
  /* harmony export */ });
@@ -1160,10 +1529,13 @@ class PGS_Slides {
1160
1529
  const last = children[children.length - 1];
1161
1530
  return last?.classList.contains("view") || false;
1162
1531
  },
1532
+ refresh: () => {
1533
+ PGS_slides_init(this.selector.parentNode || document);
1534
+ return API.get(this.selector);
1535
+ },
1163
1536
  });
1164
1537
  }
1165
1538
  }
1166
- PGS_slides_init();
1167
1539
 
1168
1540
  //# INIT
1169
1541
  function PGS_slides_init(root = document) {
@@ -1175,11 +1547,19 @@ function PGS_slides_init(root = document) {
1175
1547
  });
1176
1548
  }
1177
1549
 
1550
+ PGS_slides_init();
1551
+
1178
1552
  //# API
1179
1553
  function PGS_slides_api(selector) {
1180
1554
  return API.get(selector);
1181
1555
  }
1182
1556
 
1557
+ const PGS_slides = {
1558
+ PGS_name: "PGS_slides",
1559
+ init: PGS_slides_init,
1560
+ api: PGS_slides_api
1561
+ };
1562
+
1183
1563
 
1184
1564
  /***/ },
1185
1565
 
@@ -1193,13 +1573,13 @@ function PGS_slides_api(selector) {
1193
1573
  __webpack_require__.r(__webpack_exports__);
1194
1574
  /* harmony export */ __webpack_require__.d(__webpack_exports__, {
1195
1575
  /* harmony export */ PGS_stepTabs: () => (/* binding */ PGS_stepTabs),
1196
- /* harmony export */ PGS_tabs_api: () => (/* binding */ PGS_tabs_api)
1576
+ /* harmony export */ PGS_stepTabs_api: () => (/* binding */ PGS_stepTabs_api),
1577
+ /* harmony export */ PGS_stepTabs_init: () => (/* binding */ PGS_stepTabs_init)
1197
1578
  /* harmony export */ });
1198
1579
  const API = new WeakMap();
1199
- PGS_stepTabs()
1200
1580
 
1201
- function PGS_stepTabs() {
1202
- pgs(document).querySelectorAll("stepTabs").forEach(tabsWizard => {
1581
+ function PGS_stepTabs_init(root = document) {
1582
+ pgs(root).querySelectorAll("stepTabs").forEach(tabsWizard => {
1203
1583
  if (tabsWizard.dataset.stepTabsInitialized === "true") return;
1204
1584
  tabsWizard.dataset.stepTabsInitialized = "true";
1205
1585
 
@@ -1226,7 +1606,7 @@ function PGS_stepTabs() {
1226
1606
  dots.innerHTML = "";
1227
1607
 
1228
1608
  allTab.forEach((tab, index) => {
1229
- const iconClass = tab.getAttribute("data-tab-icon") || "fa-circle";
1609
+ const iconClass = pgs(tab).option.getValueBrackets("tabIcon") || "fa-circle";
1230
1610
  const dot = document.createElement("button");
1231
1611
  dot.type = "button";
1232
1612
  pgs(dot).add("stepTabs-dots-dot");
@@ -1314,21 +1694,35 @@ function PGS_stepTabs() {
1314
1694
  //-(API)
1315
1695
  // tabsWizard.addEventListener("stepTabs:reset", () => restartTab());
1316
1696
  API.set(tabsWizard, {
1697
+ element: tabsWizard,
1698
+ container: tabsContainer,
1317
1699
  restart: restartTab,
1318
1700
  goTo,
1319
1701
  next: () => goTo(current + 1),
1320
1702
  prev: () => goTo(current - 1),
1321
1703
  toggleLock: (step, lock = true) => typeof step === "number" && allTab[step] && (pgs(allTab[step]).state.toggle("is-locked", lock), goTo(current)),
1704
+ refresh: () => {
1705
+ PGS_stepTabs_init(tabsWizard.parentNode || document);
1706
+ return API.get(tabsWizard);
1707
+ },
1322
1708
  getCurrent: () => current,
1323
1709
  getState: () => ({ current, total }),
1324
1710
  });
1325
1711
  });
1326
1712
  }
1327
1713
 
1328
- function PGS_tabs_api(selector) {
1714
+ PGS_stepTabs_init()
1715
+
1716
+ function PGS_stepTabs_api(selector) {
1329
1717
  return API.get(selector);
1330
1718
  }
1331
1719
 
1720
+ const PGS_stepTabs = {
1721
+ PGS_name: "PGS_stepTabs",
1722
+ init: PGS_stepTabs_init,
1723
+ api: PGS_stepTabs_api
1724
+ };
1725
+
1332
1726
  /*
1333
1727
  / EXAMPLE
1334
1728
  // vai allo step 2
@@ -1365,11 +1759,15 @@ function PGS_tabs_api(selector) {
1365
1759
  "use strict";
1366
1760
  __webpack_require__.r(__webpack_exports__);
1367
1761
  /* harmony export */ __webpack_require__.d(__webpack_exports__, {
1368
- /* harmony export */ PGS_ol: () => (/* binding */ PGS_ol)
1762
+ /* harmony export */ PGS_steps: () => (/* binding */ PGS_steps),
1763
+ /* harmony export */ PGS_steps_api: () => (/* binding */ PGS_steps_api),
1764
+ /* harmony export */ PGS_steps_init: () => (/* binding */ PGS_steps_init)
1369
1765
  /* harmony export */ });
1766
+ const API = new WeakMap();
1370
1767
 
1371
- function PGS_ol() {
1372
- pgs(document).querySelectorAll("steps").forEach(steps => {
1768
+ function PGS_steps_init(root = document) {
1769
+ pgs(root).querySelectorAll("steps").forEach(steps => {
1770
+ if (API.has(steps)) return;
1373
1771
 
1374
1772
  pgs(steps).querySelectorAll("steps-step").forEach((li, index) => {
1375
1773
 
@@ -1385,105 +1783,274 @@ function PGS_ol() {
1385
1783
  }
1386
1784
 
1387
1785
  //= line
1388
- const line = document.createElement("span");
1389
- pgs(line).add("steps-step-line")
1390
- li.insertAdjacentElement("afterbegin", line);
1786
+ if (!pgs(li).querySelector("steps-step-line")) {
1787
+ const line = document.createElement("span");
1788
+ pgs(line).add("steps-step-line")
1789
+ li.insertAdjacentElement("afterbegin", line);
1790
+ }
1791
+ });
1792
+
1793
+ API.set(steps, {
1794
+ element: steps,
1795
+ steps: () => Array.from(pgs(steps).querySelectorAll("steps-step")),
1796
+ getStep: (index) => pgs(steps).querySelectorAll("steps-step")[index],
1797
+ getTotal: () => pgs(steps).querySelectorAll("steps-step").length,
1798
+ refresh: () => {
1799
+ API.delete(steps);
1800
+ PGS_steps_init(steps.parentNode || document);
1801
+ return API.get(steps);
1802
+ },
1391
1803
  });
1392
1804
  });
1393
1805
  }
1394
1806
 
1395
1807
  //# INIT PGS_ol
1396
- PGS_ol()
1808
+ PGS_steps_init()
1809
+
1810
+ //# API
1811
+ function PGS_steps_api(selector) {
1812
+ return API.get(selector);
1813
+ }
1814
+
1815
+ const PGS_steps = {
1816
+ PGS_name: "PGS_steps",
1817
+ init: PGS_steps_init,
1818
+ api: PGS_steps_api
1819
+ };
1820
+
1397
1821
 
1398
1822
  /***/ },
1399
1823
 
1400
- /***/ "./assets/javascript/functions/_notifications.js"
1401
- /*!*******************************************************!*\
1402
- !*** ./assets/javascript/functions/_notifications.js ***!
1403
- \*******************************************************/
1824
+ /***/ "./assets/javascript/functions/_formValidate.js"
1825
+ /*!******************************************************!*\
1826
+ !*** ./assets/javascript/functions/_formValidate.js ***!
1827
+ \******************************************************/
1404
1828
  (__unused_webpack_module, __webpack_exports__, __webpack_require__) {
1405
1829
 
1406
1830
  "use strict";
1407
1831
  __webpack_require__.r(__webpack_exports__);
1408
1832
  /* harmony export */ __webpack_require__.d(__webpack_exports__, {
1409
- /* harmony export */ PGS_notification: () => (/* binding */ PGS_notification),
1410
- /* harmony export */ PGS_toast: () => (/* binding */ PGS_toast)
1833
+ /* harmony export */ PGS_formValidate: () => (/* binding */ PGS_formValidate)
1411
1834
  /* harmony export */ });
1412
- //# PGS_notification
1413
- function initNotification(type, containerToken, icon, text, timeout, methodDelete = "replace", link = null) {
1414
- let containerNotification = pgs(document).querySelector(containerToken);
1415
-
1416
- //== Create Container
1417
- if (!containerNotification) {
1418
- const newContainer = document.createElement("div");
1419
- pgs(newContainer).add(containerToken);
1420
- newContainer.setAttribute("aria-live", "polite");
1421
- newContainer.setAttribute("aria-relevant", "additions");
1422
- document.body.appendChild(newContainer);
1423
- containerNotification = newContainer;
1835
+ /* harmony import */ var _components_notifications_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ../components/_notifications.js */ "./assets/javascript/components/_notifications.js");
1836
+
1837
+
1838
+
1839
+ class PGS_formValidate {
1840
+ constructor({ form } = {}) {
1841
+ this.container = form;
1842
+ this._rules = [];
1843
+ // pgs(this.container).add("formError");
1424
1844
  }
1425
1845
 
1426
- //== Create Notification
1427
- const notification = document.createElement(link ? "a" : "div");
1428
- if (methodDelete == "replace") containerNotification.innerHTML = "";
1429
- if (link) notification.href = link;
1430
- if (timeout > 0) notification.style.setProperty("--notification-timeout", timeout + "ms");
1431
- pgs(notification).state.add(type);
1432
- pgs(notification).add("notification-element");
1433
- notification.setAttribute("role", type == "error" ? "alert" : "status")
1434
- notification.innerHTML = `${icon} <p>${text}</p>`;
1435
- containerNotification.appendChild(notification);
1436
-
1437
-
1438
- //+ Animation delete
1439
- function deleteNotification() {
1440
- methodDelete == "stack" ? notification.style.translate = "120%" : notification.style.opacity = "0";
1441
- setTimeout(() => notification.remove(), 300);
1846
+ //+ ADD
1847
+ addError(field, i) {
1848
+ field.setAttribute("data-form-field-status", "error");
1849
+ if (i == 0) field.scrollIntoView();
1850
+
1851
+ let message = field.getAttribute("data-form-field-message");
1852
+
1853
+ if (i == 0 && message) _components_notifications_js__WEBPACK_IMPORTED_MODULE_0__.PGS_notification.toast.error(message);
1854
+ else if (i == 0) _components_notifications_js__WEBPACK_IMPORTED_MODULE_0__.PGS_notification.toast.error("Compila tutti i campi!");
1442
1855
  }
1443
1856
 
1444
- //== Timeout delete
1445
- if (timeout > 0) setTimeout(() => { deleteNotification() }, timeout);
1857
+ //+ REMOVE
1858
+ removeError(field) {
1859
+ field.setAttribute("data-form-field-status", "");
1860
+ }
1446
1861
 
1447
- //== button delete
1448
- const btnDelete = document.createElement("button");
1449
- btnDelete.type = "button";
1450
- btnDelete.ariaLabel = "Rimuovi notifica";
1451
- btnDelete.innerHTML = '<i class="fa-solid fa-xmark"></i>';
1452
- btnDelete.setAttribute("pgs", "buttonClose");
1453
- notification.insertAdjacentElement("afterbegin", btnDelete);
1862
+ #removeErrorOnClick(allFields) {
1863
+ allFields.forEach(element => {
1864
+ element.addEventListener("click", e => this.removeError(element))
1865
+ });
1866
+ }
1454
1867
 
1455
- //== event
1456
- btnDelete.addEventListener("click", function (e) {
1457
- e.preventDefault();
1458
- e.stopPropagation();
1459
- e.stopImmediatePropagation()
1460
- deleteNotification(e); // Esegue la tua funzione
1461
- });
1462
- }
1868
+ // + --------------------------
1869
+ // + Helpers
1870
+ // + --------------------------
1871
+ help = {
1872
+ // supporta sia required nativo, sia data-required="true"
1873
+ isRequired(field) {
1874
+ if (!field) return false;
1875
+
1876
+ const required = field.required === true || field?.dataset?.required === "true" || field?.getAttribute('aria-required') == "true";
1877
+ return required && !field.hidden; // solo attributo/proprietà "hidden"
1878
+ },
1879
+ // input (non speciali), textarea
1880
+ isEmptyTextLike(field) { return !String(field?.value ?? "").trim(); },
1881
+ // select: vuoto se value == "" o null
1882
+ isEmptySelect(field) { return !String(field?.value ?? "").trim(); },
1883
+ // recupera name in modo sicuro
1884
+ getGroupName(field) { return field?.name || field?.getAttribute?.("name") || ""; }
1885
+ };
1463
1886
 
1464
- function deleteALl(containerToken) {
1465
- let containerNotification = pgs(document).querySelector(containerToken);
1466
- if (containerNotification) containerNotification.innerHTML = "";
1467
- }
1468
1887
 
1888
+ // + --------------------------
1889
+ // + input + altri elementi.
1890
+ // + --------------------------
1891
+ #inputValue(container) {
1469
1892
 
1893
+ //++ add rule
1894
+ const ruleInvalidFields = [];
1895
+ for (const rule of this._rules) {
1896
+ const res = rule(container);
1470
1897
 
1471
- let PGS_notification = {
1472
- error: (text = "Errore", link = null, timeout = 0, icon = '<i class="fa-solid fa-octagon-xmark"></i>') => initNotification("error", "notification", icon, text, timeout, "stack", link),
1473
- success: (text = "Aggiornato", link = null, timeout = 0, icon = '<i class="fa-solid fa-check"></i>') => initNotification("success", "notification", icon, text, timeout, "stack", link),
1474
- info: (text = "Aggiornamento", link = null, timeout = 0, icon = '<i class="fa-solid fa-circle-info"></i>',) => initNotification("info", "notification", icon, text, timeout, "stack", link),
1475
- warning: (text = "Attenzione", link = null, timeout = 0, icon = '<i class="fa-solid fa-triangle-exclamation"></i>') => initNotification("warning", "notification", icon, text, timeout, "stack", link),
1476
- deleteAllNotification: () => deleteALl("notification")
1477
- }
1898
+ // la rule può tornare:
1899
+ // null/undefined => ok
1900
+ // un elemento => invalido
1901
+ // un array di elementi => invalidi
1902
+ if (!res) continue;
1903
+
1904
+ if (Array.isArray(res)) ruleInvalidFields.push(...res);
1905
+ else ruleInvalidFields.push(res);
1906
+ }
1907
+
1908
+ //== INPUT
1909
+ // "testuali" (esclude hidden/disabled/checkbox/radio/file come nel tuo snippet)
1910
+ const textInputs = Array.from(container.querySelectorAll("input")).filter((input) => {
1911
+ if (input.disabled) return false;
1912
+ if (input.type === "hidden") return false;
1913
+ if (input.type === "checkbox" || input.type === "radio" || input.type === "file") return false;
1914
+
1915
+ // valida solo se required (o data-required="true")
1916
+ if (!this.help.isRequired(input)) return false;
1917
+
1918
+ return this.help.isEmptyTextLike(input);
1919
+ });
1920
+
1921
+ //== TEXTAREA
1922
+ // required vuote
1923
+ const textareas = Array.from(container.querySelectorAll("textarea")).filter((ta) => {
1924
+ if (ta.disabled) return false;
1925
+ if (!this.help.isRequired(ta)) return false;
1926
+ return this.help.isEmptyTextLike(ta);
1927
+ });
1928
+
1929
+ //== SELECT
1930
+ // required vuoti
1931
+ const selects = Array.from(container.querySelectorAll("select")).filter((sel) => {
1932
+ if (sel.disabled) return false;
1933
+ if (!this.help.isRequired(sel)) return false;
1934
+ return this.help.isEmptySelect(sel);
1935
+ });
1936
+
1937
+ //== RADIO
1938
+ // required: se in un gruppo required non ce n'è uno checked => errore sul "primo" radio del gruppo
1939
+ const radios = Array.from(container.querySelectorAll('input[type="radio"]')).filter((r) => !r.disabled);
1940
+ const requiredRadioGroups = new Map(); // name -> [elements]
1941
+ for (const r of radios) {
1942
+ if (!this.help.isRequired(r)) continue;
1943
+ const name = this.help.getGroupName(r);
1944
+ if (!name) continue;
1945
+ if (!requiredRadioGroups.has(name)) requiredRadioGroups.set(name, []);
1946
+ requiredRadioGroups.get(name).push(r);
1947
+ }
1948
+ const radioGroupErrors = [];
1949
+ for (const [name, group] of requiredRadioGroups.entries()) {
1950
+ const anyChecked = group.some((r) => r.checked);
1951
+ if (!anyChecked) {
1952
+ // scegli dove mettere l'errore: tipicamente sul primo radio del gruppo
1953
+ radioGroupErrors.push(group[0]);
1954
+ }
1955
+ }
1956
+
1957
+ //== CHECKBOX
1958
+ // required: può essere singola checkbox required (checked obbligatorio)
1959
+ // oppure gruppo di checkbox (stesso name) con almeno una selezionata
1960
+ const checkboxes = Array.from(container.querySelectorAll('input[type="checkbox"]')).filter((c) => !c.disabled);
1961
+ const requiredCheckboxSingles = [];
1962
+ const requiredCheckboxGroups = new Map(); // name -> [elements]
1963
+ for (const c of checkboxes) {
1964
+ if (!this.help.isRequired(c)) continue;
1965
+
1966
+ const name = this.help.getGroupName(c);
1967
+ if (!name) {
1968
+ // checkbox senza name: trattala come singola required
1969
+ if (!c.checked) requiredCheckboxSingles.push(c);
1970
+ continue;
1971
+ }
1972
+
1973
+ // se vuoi trattare come gruppo, raggruppa per name
1974
+ if (!requiredCheckboxGroups.has(name)) requiredCheckboxGroups.set(name, []);
1975
+ requiredCheckboxGroups.get(name).push(c);
1976
+ }
1977
+ const checkboxGroupErrors = [];
1978
+ for (const [name, group] of requiredCheckboxGroups.entries()) {
1979
+ // se è un gruppo (>=2) richiedi almeno una spuntata
1980
+ // se è 1 sola, si comporta come singola
1981
+ const anyChecked = group.some((c) => c.checked);
1982
+ if (!anyChecked) checkboxGroupErrors.push(group[0]);
1983
+ }
1984
+
1985
+ //== FILE
1986
+ // required: se vuoi includerlo
1987
+ const fileInputs = Array.from(container.querySelectorAll('input[type="file"]')).filter((f) => {
1988
+ if (f.disabled) return false;
1989
+ if (!this.help.isRequired(f)) return false;
1990
+ return !(f.files && f.files.length > 0);
1991
+ });
1478
1992
 
1479
- let PGS_toast = {
1480
- error: (text = "Errore", timeout = 4000, icon = '<i class="fa-solid fa-octagon-xmark"></i>',) => initNotification("error", "toast", icon, text, timeout),
1481
- success: (text = "Aggiornato", timeout = 4000, icon = '<i class="fa-solid fa-check"></i>',) => initNotification("success", "toast", icon, text, timeout),
1482
- info: (text = "Aggiornamento", timeout = 0, icon = '<i class="fa-solid fa-circle-info"></i>',) => initNotification("info", "toast", icon, text, timeout),
1483
- warning: (text = "Attenzione", timeout = 4000, icon = '<i class="fa-solid fa-triangle-exclamation"></i>',) => initNotification("warning", "toast", icon, text, timeout),
1484
- deleteTost: () => deleteALl("toast")
1993
+ //== risultato finale: tutti i campi da marcare come errore
1994
+ const invalidFields = [
1995
+ textInputs,
1996
+ textareas,
1997
+ selects,
1998
+ radioGroupErrors,
1999
+ requiredCheckboxSingles,
2000
+ checkboxGroupErrors,
2001
+ fileInputs,
2002
+ ruleInvalidFields
2003
+ ];
2004
+
2005
+ return invalidFields.flat();
2006
+ }
2007
+
2008
+ // + -------------------------
2009
+ // + VALIDATE
2010
+ // + -------------------------
2011
+ validate() {
2012
+ const invalid = this.#inputValue(this.container);
2013
+ const allFields = this.container.querySelectorAll("input, textarea, select")
2014
+
2015
+ //== pulizia/aggiornamento errori:
2016
+ // prima rimuovo errori dai campi "non più invalidi"
2017
+ Array.from(allFields).filter((el) => !el.disabled);
2018
+
2019
+ //== per radio/checkbox in gruppo:
2020
+ // rimuovi l'errore solo sull'elemento che lo ospita (qui: se presente)
2021
+ for (const el of allFields) { if (!invalid.includes(el)) this.removeError(el); }
2022
+
2023
+ //== aggiungo errori dove serve
2024
+ invalid.forEach((el, i) => this.addError(el, i))
2025
+
2026
+ //== rimuove l'errore al click
2027
+ this.#removeErrorOnClick(allFields)
2028
+
2029
+ //== status form
2030
+ if (invalid.length) {
2031
+ this.container.setAttribute("data-form-status", "error");
2032
+ return false;
2033
+ } else {
2034
+ this.container.setAttribute("data-form-status", "success");
2035
+ return true;
2036
+ }
2037
+ }
2038
+
2039
+ ifSuccess(text = "Inviato con successo") {
2040
+ if (this.validate() == true) _components_notifications_js__WEBPACK_IMPORTED_MODULE_0__.PGS_notification.toast.success(text)
2041
+ }
2042
+
2043
+ // + -------------------------
2044
+ // + ADD RULE
2045
+ // + -------------------------
2046
+ addNewRule(container) {
2047
+ if (typeof container !== "function") throw new Error("Rule must be a function");
2048
+ this._rules.push(container);
2049
+ return this;
2050
+ }
1485
2051
  }
1486
2052
 
2053
+
1487
2054
  /***/ },
1488
2055
 
1489
2056
  /***/ "./assets/javascript/functions/_scrollY.js"
@@ -1801,13 +2368,8 @@ document.addEventListener('DOMContentLoaded', function () {
1801
2368
  /*!***********************************************!*\
1802
2369
  !*** ./assets/javascript/patterns/_header.js ***!
1803
2370
  \***********************************************/
1804
- (__unused_webpack_module, __webpack_exports__, __webpack_require__) {
2371
+ () {
1805
2372
 
1806
- "use strict";
1807
- __webpack_require__.r(__webpack_exports__);
1808
- /* harmony export */ __webpack_require__.d(__webpack_exports__, {
1809
- /* harmony export */ PGS_header: () => (/* binding */ PGS_header)
1810
- /* harmony export */ });
1811
2373
  //# HEADER
1812
2374
  const header = pgs(document).querySelector("header");
1813
2375
  const headerElements = pgs(header).querySelectorAll("header-element");
@@ -2027,26 +2589,31 @@ var __webpack_exports__ = {};
2027
2589
  !*** ./assets/javascript/index.js ***!
2028
2590
  \************************************/
2029
2591
  __webpack_require__.r(__webpack_exports__);
2592
+ /* harmony export */ __webpack_require__.d(__webpack_exports__, {
2593
+ /* harmony export */ pgs: () => (/* reexport safe */ _pgs_js__WEBPACK_IMPORTED_MODULE_0__.pgs)
2594
+ /* harmony export */ });
2030
2595
  /* harmony import */ var _pgs_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./_pgs.js */ "./assets/javascript/_pgs.js");
2031
2596
  /* harmony import */ var _base_darkmode_js__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./base/_darkmode.js */ "./assets/javascript/base/_darkmode.js");
2032
2597
  /* harmony import */ var _base_darkmode_js__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(_base_darkmode_js__WEBPACK_IMPORTED_MODULE_1__);
2033
2598
  /* harmony import */ var _base_object_js__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ./base/_object.js */ "./assets/javascript/base/_object.js");
2034
2599
  /* harmony import */ var _base_object_js__WEBPACK_IMPORTED_MODULE_2___default = /*#__PURE__*/__webpack_require__.n(_base_object_js__WEBPACK_IMPORTED_MODULE_2__);
2035
2600
  /* harmony import */ var _components_accordion_js__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ./components/_accordion.js */ "./assets/javascript/components/_accordion.js");
2036
- /* harmony import */ var _components_accordion_js__WEBPACK_IMPORTED_MODULE_3___default = /*#__PURE__*/__webpack_require__.n(_components_accordion_js__WEBPACK_IMPORTED_MODULE_3__);
2037
2601
  /* harmony import */ var _components_dropdown_js__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! ./components/_dropdown.js */ "./assets/javascript/components/_dropdown.js");
2038
- /* harmony import */ var _components_exeNotifications_js__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(/*! ./components/_exeNotifications.js */ "./assets/javascript/components/_exeNotifications.js");
2039
- /* harmony import */ var _components_menu_js__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(/*! ./components/_menu.js */ "./assets/javascript/components/_menu.js");
2040
- /* harmony import */ var _components_modals_js__WEBPACK_IMPORTED_MODULE_7__ = __webpack_require__(/*! ./components/_modals.js */ "./assets/javascript/components/_modals.js");
2041
- /* harmony import */ var _components_slides_js__WEBPACK_IMPORTED_MODULE_8__ = __webpack_require__(/*! ./components/_slides.js */ "./assets/javascript/components/_slides.js");
2042
- /* harmony import */ var _components_steps_js__WEBPACK_IMPORTED_MODULE_9__ = __webpack_require__(/*! ./components/_steps.js */ "./assets/javascript/components/_steps.js");
2043
- /* harmony import */ var _components_stepTabs_js__WEBPACK_IMPORTED_MODULE_10__ = __webpack_require__(/*! ./components/_stepTabs.js */ "./assets/javascript/components/_stepTabs.js");
2044
- /* harmony import */ var _patterns_header_js__WEBPACK_IMPORTED_MODULE_11__ = __webpack_require__(/*! ./patterns/_header.js */ "./assets/javascript/patterns/_header.js");
2045
- /* harmony import */ var _patterns_cookieConsent_js__WEBPACK_IMPORTED_MODULE_12__ = __webpack_require__(/*! ./patterns/_cookieConsent.js */ "./assets/javascript/patterns/_cookieConsent.js");
2046
- /* harmony import */ var _patterns_cookieConsent_js__WEBPACK_IMPORTED_MODULE_12___default = /*#__PURE__*/__webpack_require__.n(_patterns_cookieConsent_js__WEBPACK_IMPORTED_MODULE_12__);
2602
+ /* harmony import */ var _components_menu_js__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(/*! ./components/_menu.js */ "./assets/javascript/components/_menu.js");
2603
+ /* harmony import */ var _components_modals_js__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(/*! ./components/_modals.js */ "./assets/javascript/components/_modals.js");
2604
+ /* harmony import */ var _components_slides_js__WEBPACK_IMPORTED_MODULE_7__ = __webpack_require__(/*! ./components/_slides.js */ "./assets/javascript/components/_slides.js");
2605
+ /* harmony import */ var _components_steps_js__WEBPACK_IMPORTED_MODULE_8__ = __webpack_require__(/*! ./components/_steps.js */ "./assets/javascript/components/_steps.js");
2606
+ /* harmony import */ var _components_stepTabs_js__WEBPACK_IMPORTED_MODULE_9__ = __webpack_require__(/*! ./components/_stepTabs.js */ "./assets/javascript/components/_stepTabs.js");
2607
+ /* harmony import */ var _components_notifications_js__WEBPACK_IMPORTED_MODULE_10__ = __webpack_require__(/*! ./components/_notifications.js */ "./assets/javascript/components/_notifications.js");
2608
+ /* harmony import */ var _imports_js__WEBPACK_IMPORTED_MODULE_11__ = __webpack_require__(/*! ./_imports.js */ "./assets/javascript/_imports.js");
2609
+ /* harmony import */ var _patterns_header_js__WEBPACK_IMPORTED_MODULE_12__ = __webpack_require__(/*! ./patterns/_header.js */ "./assets/javascript/patterns/_header.js");
2610
+ /* harmony import */ var _patterns_header_js__WEBPACK_IMPORTED_MODULE_12___default = /*#__PURE__*/__webpack_require__.n(_patterns_header_js__WEBPACK_IMPORTED_MODULE_12__);
2611
+ /* harmony import */ var _patterns_cookieConsent_js__WEBPACK_IMPORTED_MODULE_13__ = __webpack_require__(/*! ./patterns/_cookieConsent.js */ "./assets/javascript/patterns/_cookieConsent.js");
2612
+ /* harmony import */ var _patterns_cookieConsent_js__WEBPACK_IMPORTED_MODULE_13___default = /*#__PURE__*/__webpack_require__.n(_patterns_cookieConsent_js__WEBPACK_IMPORTED_MODULE_13__);
2047
2613
  //= PGS
2048
2614
 
2049
2615
 
2616
+
2050
2617
  //= BASE
2051
2618
 
2052
2619
 
@@ -2061,8 +2628,10 @@ __webpack_require__.r(__webpack_exports__);
2061
2628
 
2062
2629
 
2063
2630
 
2064
- //= patterns
2631
+ //= IMPORT REGISTRY
2632
+
2065
2633
 
2634
+ //= PATTERNS
2066
2635
 
2067
2636
 
2068
2637
  })();