mypgs 1.0.0
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.
- package/README.md +33 -0
- package/assets/javascript/_pgs.js +214 -0
- package/assets/javascript/base/_darkmode.js +121 -0
- package/assets/javascript/base/_object.js +42 -0
- package/assets/javascript/components/_accordion.js +77 -0
- package/assets/javascript/components/_dropdown.js +107 -0
- package/assets/javascript/components/_exeNotifications.js +85 -0
- package/assets/javascript/components/_menu.js +92 -0
- package/assets/javascript/components/_modals.js +123 -0
- package/assets/javascript/components/_slides.js +183 -0
- package/assets/javascript/components/_steps.js +27 -0
- package/assets/javascript/components/_tabs.js +134 -0
- package/assets/javascript/functions/_formValidate.js +217 -0
- package/assets/javascript/functions/_notifications.js +74 -0
- package/assets/javascript/functions/_scrollY.js +77 -0
- package/assets/javascript/functions/_sendForm.js +100 -0
- package/assets/javascript/index.js +20 -0
- package/assets/javascript/patterns/_cookieConsent.js +209 -0
- package/assets/javascript/patterns/_header.js +134 -0
- package/assets/javascript/pgs.d.ts +23 -0
- package/assets/scss/base/_body.scss +151 -0
- package/assets/scss/base/_color.scss +56 -0
- package/assets/scss/base/_general.scss +58 -0
- package/assets/scss/base/_heading.scss +20 -0
- package/assets/scss/base/_html.scss +4 -0
- package/assets/scss/base/_reset.scss +15 -0
- package/assets/scss/base/_variables.scss +39 -0
- package/assets/scss/components/_accordion.scss +91 -0
- package/assets/scss/components/_breadcumbs.scss +40 -0
- package/assets/scss/components/_button.scss +28 -0
- package/assets/scss/components/_dropdown.scss +106 -0
- package/assets/scss/components/_form.scss +53 -0
- package/assets/scss/components/_logo.scss +51 -0
- package/assets/scss/components/_menu.scss +23 -0
- package/assets/scss/components/_modals.scss +120 -0
- package/assets/scss/components/_notification.scss +193 -0
- package/assets/scss/components/_searchbar.scss +68 -0
- package/assets/scss/components/_slides.scss +198 -0
- package/assets/scss/components/_steps.scss +111 -0
- package/assets/scss/components/_table.scss +59 -0
- package/assets/scss/components/_tabs.scss +69 -0
- package/assets/scss/components/_tooltip.scss +16 -0
- package/assets/scss/index.scss +64 -0
- package/assets/scss/layout/_flex.scss +47 -0
- package/assets/scss/layout/_gap.scss +12 -0
- package/assets/scss/layout/_grid.scss +11 -0
- package/assets/scss/layout/_layout.scss +41 -0
- package/assets/scss/layout/_pageShell.scss +171 -0
- package/assets/scss/mixin/_mx-base.scss +126 -0
- package/assets/scss/mixin/_mx-button.scss +186 -0
- package/assets/scss/mixin/_mx-card.scss +77 -0
- package/assets/scss/mixin/_mx-color.scss +34 -0
- package/assets/scss/mixin/_mx-form-addon.scss +180 -0
- package/assets/scss/mixin/_mx-form.scss +512 -0
- package/assets/scss/mixin/_mx-menu.scss +154 -0
- package/assets/scss/mixin/_mx-responsive.scss +353 -0
- package/assets/scss/mixin/_mx-semantic.scss +147 -0
- package/assets/scss/mixin/mixin.scss +36 -0
- package/assets/scss/patterns/_cookieConsent.scss +101 -0
- package/assets/scss/patterns/_footer.scss +180 -0
- package/assets/scss/patterns/_header.scss +143 -0
- package/dist/css/index.css +7026 -0
- package/dist/css/index.css.map +1 -0
- package/dist/css/index.min.css +1 -0
- package/dist/index.d.ts +24 -0
- package/dist/javascript/index.js +2034 -0
- package/dist/javascript/index.js.map +1 -0
- package/dist/javascript/index.min.js +1 -0
- package/package.json +40 -0
- package/templates/components/md-breadcumbs.html +23 -0
- package/templates/components/md-menu.html +6 -0
- package/templates/components/md-notification.html +10 -0
- package/templates/components/md-searchbar.html +24 -0
- package/templates/components/md-tooltip.html +5 -0
- package/templates/layout/md-body.html +20 -0
- package/templates/layout/md-cookieConsent.html +51 -0
- package/templates/layout/md-footer.html +16 -0
- package/templates/layout/md-header.html +43 -0
- package/webpack.config.js +131 -0
|
@@ -0,0 +1,217 @@
|
|
|
1
|
+
import { PGS_toast } from "../functions/_notifications.js";
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
export class PGS_formValidate {
|
|
5
|
+
constructor({ form } = {}) {
|
|
6
|
+
this.container = form;
|
|
7
|
+
this._rules = [];
|
|
8
|
+
// pgs(this.container).add("formError");
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
//+ ADD
|
|
12
|
+
addError(field, i) {
|
|
13
|
+
field.setAttribute("data-form-field-status", "error");
|
|
14
|
+
if (i == 0) field.scrollIntoView();
|
|
15
|
+
|
|
16
|
+
let message = field.getAttribute("data-form-field-message");
|
|
17
|
+
|
|
18
|
+
if (i == 0 && message) PGS_toast.error(message);
|
|
19
|
+
else if (i == 0) PGS_toast.error("Compila tutti i campi!");
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
//+ REMOVE
|
|
23
|
+
removeError(field) {
|
|
24
|
+
field.setAttribute("data-form-field-status", "");
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
#removeErrorOnClick(allFields) {
|
|
28
|
+
allFields.forEach(element => {
|
|
29
|
+
element.addEventListener("click", e => this.removeError(element))
|
|
30
|
+
});
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
// + --------------------------
|
|
34
|
+
// + Helpers
|
|
35
|
+
// + --------------------------
|
|
36
|
+
help = {
|
|
37
|
+
// supporta sia required nativo, sia data-required="true"
|
|
38
|
+
isRequired(field) {
|
|
39
|
+
if (!field) return false;
|
|
40
|
+
|
|
41
|
+
const required = field.required === true || field?.dataset?.required === "true" || field?.getAttribute('aria-required') == "true";
|
|
42
|
+
return required && !field.hidden; // solo attributo/proprietà "hidden"
|
|
43
|
+
},
|
|
44
|
+
// input (non speciali), textarea
|
|
45
|
+
isEmptyTextLike(field) { return !String(field?.value ?? "").trim(); },
|
|
46
|
+
// select: vuoto se value == "" o null
|
|
47
|
+
isEmptySelect(field) { return !String(field?.value ?? "").trim(); },
|
|
48
|
+
// recupera name in modo sicuro
|
|
49
|
+
getGroupName(field) { return field?.name || field?.getAttribute?.("name") || ""; }
|
|
50
|
+
};
|
|
51
|
+
|
|
52
|
+
|
|
53
|
+
// + --------------------------
|
|
54
|
+
// + input + altri elementi.
|
|
55
|
+
// + --------------------------
|
|
56
|
+
#inputValue(container) {
|
|
57
|
+
|
|
58
|
+
//++ add rule
|
|
59
|
+
const ruleInvalidFields = [];
|
|
60
|
+
for (const rule of this._rules) {
|
|
61
|
+
const res = rule(container);
|
|
62
|
+
|
|
63
|
+
// la rule può tornare:
|
|
64
|
+
// • null/undefined => ok
|
|
65
|
+
// • un elemento => invalido
|
|
66
|
+
// • un array di elementi => invalidi
|
|
67
|
+
if (!res) continue;
|
|
68
|
+
|
|
69
|
+
if (Array.isArray(res)) ruleInvalidFields.push(...res);
|
|
70
|
+
else ruleInvalidFields.push(res);
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
//== INPUT
|
|
74
|
+
// "testuali" (esclude hidden/disabled/checkbox/radio/file come nel tuo snippet)
|
|
75
|
+
const textInputs = Array.from(container.querySelectorAll("input")).filter((input) => {
|
|
76
|
+
if (input.disabled) return false;
|
|
77
|
+
if (input.type === "hidden") return false;
|
|
78
|
+
if (input.type === "checkbox" || input.type === "radio" || input.type === "file") return false;
|
|
79
|
+
|
|
80
|
+
// valida solo se required (o data-required="true")
|
|
81
|
+
if (!this.help.isRequired(input)) return false;
|
|
82
|
+
|
|
83
|
+
return this.help.isEmptyTextLike(input);
|
|
84
|
+
});
|
|
85
|
+
|
|
86
|
+
//== TEXTAREA
|
|
87
|
+
// required vuote
|
|
88
|
+
const textareas = Array.from(container.querySelectorAll("textarea")).filter((ta) => {
|
|
89
|
+
if (ta.disabled) return false;
|
|
90
|
+
if (!this.help.isRequired(ta)) return false;
|
|
91
|
+
return this.help.isEmptyTextLike(ta);
|
|
92
|
+
});
|
|
93
|
+
|
|
94
|
+
//== SELECT
|
|
95
|
+
// required vuoti
|
|
96
|
+
const selects = Array.from(container.querySelectorAll("select")).filter((sel) => {
|
|
97
|
+
if (sel.disabled) return false;
|
|
98
|
+
if (!this.help.isRequired(sel)) return false;
|
|
99
|
+
return this.help.isEmptySelect(sel);
|
|
100
|
+
});
|
|
101
|
+
|
|
102
|
+
//== RADIO
|
|
103
|
+
// required: se in un gruppo required non ce n'è uno checked => errore sul "primo" radio del gruppo
|
|
104
|
+
const radios = Array.from(container.querySelectorAll('input[type="radio"]')).filter((r) => !r.disabled);
|
|
105
|
+
const requiredRadioGroups = new Map(); // name -> [elements]
|
|
106
|
+
for (const r of radios) {
|
|
107
|
+
if (!this.help.isRequired(r)) continue;
|
|
108
|
+
const name = this.help.getGroupName(r);
|
|
109
|
+
if (!name) continue;
|
|
110
|
+
if (!requiredRadioGroups.has(name)) requiredRadioGroups.set(name, []);
|
|
111
|
+
requiredRadioGroups.get(name).push(r);
|
|
112
|
+
}
|
|
113
|
+
const radioGroupErrors = [];
|
|
114
|
+
for (const [name, group] of requiredRadioGroups.entries()) {
|
|
115
|
+
const anyChecked = group.some((r) => r.checked);
|
|
116
|
+
if (!anyChecked) {
|
|
117
|
+
// scegli dove mettere l'errore: tipicamente sul primo radio del gruppo
|
|
118
|
+
radioGroupErrors.push(group[0]);
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
//== CHECKBOX
|
|
123
|
+
// required: può essere singola checkbox required (checked obbligatorio)
|
|
124
|
+
// oppure gruppo di checkbox (stesso name) con almeno una selezionata
|
|
125
|
+
const checkboxes = Array.from(container.querySelectorAll('input[type="checkbox"]')).filter((c) => !c.disabled);
|
|
126
|
+
const requiredCheckboxSingles = [];
|
|
127
|
+
const requiredCheckboxGroups = new Map(); // name -> [elements]
|
|
128
|
+
for (const c of checkboxes) {
|
|
129
|
+
if (!this.help.isRequired(c)) continue;
|
|
130
|
+
|
|
131
|
+
const name = this.help.getGroupName(c);
|
|
132
|
+
if (!name) {
|
|
133
|
+
// checkbox senza name: trattala come singola required
|
|
134
|
+
if (!c.checked) requiredCheckboxSingles.push(c);
|
|
135
|
+
continue;
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
// se vuoi trattare come gruppo, raggruppa per name
|
|
139
|
+
if (!requiredCheckboxGroups.has(name)) requiredCheckboxGroups.set(name, []);
|
|
140
|
+
requiredCheckboxGroups.get(name).push(c);
|
|
141
|
+
}
|
|
142
|
+
const checkboxGroupErrors = [];
|
|
143
|
+
for (const [name, group] of requiredCheckboxGroups.entries()) {
|
|
144
|
+
// se è un gruppo (>=2) richiedi almeno una spuntata
|
|
145
|
+
// se è 1 sola, si comporta come singola
|
|
146
|
+
const anyChecked = group.some((c) => c.checked);
|
|
147
|
+
if (!anyChecked) checkboxGroupErrors.push(group[0]);
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
//== FILE
|
|
151
|
+
// required: se vuoi includerlo
|
|
152
|
+
const fileInputs = Array.from(container.querySelectorAll('input[type="file"]')).filter((f) => {
|
|
153
|
+
if (f.disabled) return false;
|
|
154
|
+
if (!this.help.isRequired(f)) return false;
|
|
155
|
+
return !(f.files && f.files.length > 0);
|
|
156
|
+
});
|
|
157
|
+
|
|
158
|
+
//== risultato finale: tutti i campi da marcare come errore
|
|
159
|
+
const invalidFields = [
|
|
160
|
+
textInputs,
|
|
161
|
+
textareas,
|
|
162
|
+
selects,
|
|
163
|
+
radioGroupErrors,
|
|
164
|
+
requiredCheckboxSingles,
|
|
165
|
+
checkboxGroupErrors,
|
|
166
|
+
fileInputs,
|
|
167
|
+
ruleInvalidFields
|
|
168
|
+
];
|
|
169
|
+
|
|
170
|
+
return invalidFields.flat();
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
// + -------------------------
|
|
174
|
+
// + VALIDATE
|
|
175
|
+
// + -------------------------
|
|
176
|
+
validate() {
|
|
177
|
+
const invalid = this.#inputValue(this.container);
|
|
178
|
+
const allFields = this.container.querySelectorAll("input, textarea, select")
|
|
179
|
+
|
|
180
|
+
//== pulizia/aggiornamento errori:
|
|
181
|
+
// prima rimuovo errori dai campi "non più invalidi"
|
|
182
|
+
Array.from(allFields).filter((el) => !el.disabled);
|
|
183
|
+
|
|
184
|
+
//== per radio/checkbox in gruppo:
|
|
185
|
+
// rimuovi l'errore solo sull'elemento che lo ospita (qui: se presente)
|
|
186
|
+
for (const el of allFields) { if (!invalid.includes(el)) this.removeError(el); }
|
|
187
|
+
|
|
188
|
+
//== aggiungo errori dove serve
|
|
189
|
+
invalid.forEach((el, i) => this.addError(el, i))
|
|
190
|
+
|
|
191
|
+
//== rimuove l'errore al click
|
|
192
|
+
this.#removeErrorOnClick(allFields)
|
|
193
|
+
|
|
194
|
+
//== status form
|
|
195
|
+
if (invalid.length) {
|
|
196
|
+
this.container.setAttribute("data-form-status", "error");
|
|
197
|
+
return false;
|
|
198
|
+
} else {
|
|
199
|
+
this.container.setAttribute("data-form-status", "success");
|
|
200
|
+
return true;
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
ifSuccess(text = "Inviato con successo") {
|
|
205
|
+
if (this.validate() == true) PGS_toast.success(text)
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
// + -------------------------
|
|
209
|
+
// + ADD RULE
|
|
210
|
+
// + -------------------------
|
|
211
|
+
addNewRule(container) {
|
|
212
|
+
if (typeof container !== "function") throw new Error("Rule must be a function");
|
|
213
|
+
this._rules.push(container);
|
|
214
|
+
return this;
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
//# PGS_notification
|
|
2
|
+
function initNotification(type, containerToken, icon, text, timeout, methodDelete = "replace", link = null) {
|
|
3
|
+
let containerNotification = pgs(document).querySelector(containerToken);
|
|
4
|
+
|
|
5
|
+
//== Create Container
|
|
6
|
+
if (!containerNotification) {
|
|
7
|
+
const newContainer = document.createElement("div");
|
|
8
|
+
pgs(newContainer).add(containerToken);
|
|
9
|
+
newContainer.setAttribute("aria-live", "polite");
|
|
10
|
+
newContainer.setAttribute("aria-relevant", "additions");
|
|
11
|
+
document.body.appendChild(newContainer);
|
|
12
|
+
containerNotification = newContainer;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
//== Create Notification
|
|
16
|
+
const notification = document.createElement(link ? "a" : "div");
|
|
17
|
+
if (methodDelete == "replace") containerNotification.innerHTML = "";
|
|
18
|
+
if (link) notification.href = link;
|
|
19
|
+
if (timeout > 0) notification.style.setProperty("--notification-timeout", timeout + "ms");
|
|
20
|
+
pgs(notification).state.add(type);
|
|
21
|
+
pgs(notification).add("notification-element");
|
|
22
|
+
notification.setAttribute("role", type == "error" ? "alert" : "status")
|
|
23
|
+
notification.innerHTML = `${icon} <p>${text}</p>`;
|
|
24
|
+
containerNotification.appendChild(notification);
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
//+ Animation delete
|
|
28
|
+
function deleteNotification() {
|
|
29
|
+
methodDelete == "stack" ? notification.style.translate = "120%" : notification.style.opacity = "0";
|
|
30
|
+
setTimeout(() => notification.remove(), 300);
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
//== Timeout delete
|
|
34
|
+
if (timeout > 0) setTimeout(() => { deleteNotification() }, timeout);
|
|
35
|
+
|
|
36
|
+
//== button delete
|
|
37
|
+
const btnDelete = document.createElement("button");
|
|
38
|
+
btnDelete.type = "button";
|
|
39
|
+
btnDelete.ariaLabel = "Rimuovi notifica";
|
|
40
|
+
btnDelete.innerHTML = '<i class="fa-solid fa-xmark"></i>';
|
|
41
|
+
btnDelete.setAttribute("pgs", "buttonClose");
|
|
42
|
+
notification.insertAdjacentElement("afterbegin", btnDelete);
|
|
43
|
+
|
|
44
|
+
//== event
|
|
45
|
+
btnDelete.addEventListener("click", function (e) {
|
|
46
|
+
e.preventDefault();
|
|
47
|
+
e.stopPropagation();
|
|
48
|
+
e.stopImmediatePropagation()
|
|
49
|
+
deleteNotification(e); // Esegue la tua funzione
|
|
50
|
+
});
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
function deleteALl(containerToken) {
|
|
54
|
+
let containerNotification = pgs(document).querySelector(containerToken);
|
|
55
|
+
if (containerNotification) containerNotification.innerHTML = "";
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
|
|
59
|
+
|
|
60
|
+
export let PGS_notification = {
|
|
61
|
+
error: (text = "Errore", link = null, timeout = 0, icon = '<i class="fa-solid fa-octagon-xmark"></i>') => initNotification("error", "notification", icon, text, timeout, "stack", link),
|
|
62
|
+
success: (text = "Aggiornato", link = null, timeout = 0, icon = '<i class="fa-solid fa-check"></i>') => initNotification("success", "notification", icon, text, timeout, "stack", link),
|
|
63
|
+
info: (text = "Aggiornamento", link = null, timeout = 0, icon = '<i class="fa-solid fa-circle-info"></i>',) => initNotification("info", "notification", icon, text, timeout, "stack", link),
|
|
64
|
+
warning: (text = "Attenzione", link = null, timeout = 0, icon = '<i class="fa-solid fa-triangle-exclamation"></i>') => initNotification("warning", "notification", icon, text, timeout, "stack", link),
|
|
65
|
+
deleteAllNotification: () => deleteALl("notification")
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
export let PGS_toast = {
|
|
69
|
+
error: (text = "Errore", timeout = 4000, icon = '<i class="fa-solid fa-octagon-xmark"></i>',) => initNotification("error", "toast", icon, text, timeout),
|
|
70
|
+
success: (text = "Aggiornato", timeout = 4000, icon = '<i class="fa-solid fa-check"></i>',) => initNotification("success", "toast", icon, text, timeout),
|
|
71
|
+
info: (text = "Aggiornamento", timeout = 0, icon = '<i class="fa-solid fa-circle-info"></i>',) => initNotification("info", "toast", icon, text, timeout),
|
|
72
|
+
warning: (text = "Attenzione", timeout = 4000, icon = '<i class="fa-solid fa-triangle-exclamation"></i>',) => initNotification("warning", "toast", icon, text, timeout),
|
|
73
|
+
deleteTost: () => deleteALl("toast")
|
|
74
|
+
}
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
export function PGS_scrollHorizontal(querySelector, dataSpeed) {
|
|
2
|
+
// Se hai più contenitori, selezionali tutti:
|
|
3
|
+
// Semplice "singleton" per stimare se la sorgente è trackpad
|
|
4
|
+
const TrackpadDetector = (() => {
|
|
5
|
+
let lastTs = 0;
|
|
6
|
+
let smallAndFast = 0;
|
|
7
|
+
let samples = 0;
|
|
8
|
+
let isTrackpad = false;
|
|
9
|
+
|
|
10
|
+
function update(e) {
|
|
11
|
+
const now = performance.now();
|
|
12
|
+
const dt = now - lastTs;
|
|
13
|
+
|
|
14
|
+
// Porta delta in px (0: px, 1: linee, 2: pagine)
|
|
15
|
+
let dy = Math.abs(e.deltaY);
|
|
16
|
+
if (e.deltaMode === 1) dy *= 16;
|
|
17
|
+
else if (e.deltaMode === 2) dy *= e.currentTarget?.clientHeight || 800;
|
|
18
|
+
|
|
19
|
+
// Heuristica: eventi piccoli e ravvicinati → prob. trackpad
|
|
20
|
+
const small = dy < 30; // soglia prudente
|
|
21
|
+
const fast = dt < 35; // alta frequenza
|
|
22
|
+
if (small && fast) smallAndFast++;
|
|
23
|
+
|
|
24
|
+
samples++;
|
|
25
|
+
if (samples >= 6) { // aggiorna il giudizio ogni N eventi
|
|
26
|
+
isTrackpad = smallAndFast >= 3;
|
|
27
|
+
smallAndFast = 0;
|
|
28
|
+
samples = 0;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
lastTs = now;
|
|
32
|
+
return isTrackpad;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
return {
|
|
36
|
+
update,
|
|
37
|
+
get value() { return isTrackpad; }
|
|
38
|
+
};
|
|
39
|
+
})();
|
|
40
|
+
|
|
41
|
+
//= Scorrimento orizzontale con rotella (evita il trackpad)
|
|
42
|
+
|
|
43
|
+
let el = querySelector
|
|
44
|
+
el.addEventListener('wheel', (e) => {
|
|
45
|
+
const speed = dataSpeed;
|
|
46
|
+
|
|
47
|
+
//== lascia lo scroll naturale del trackpad
|
|
48
|
+
if (TrackpadDetector.update(e)) return;
|
|
49
|
+
|
|
50
|
+
//== Evita interferenze con zoom o scroll orizzontale nativo
|
|
51
|
+
if (e.ctrlKey) return;
|
|
52
|
+
if (Math.abs(e.deltaX) > Math.abs(e.deltaY)) return;
|
|
53
|
+
|
|
54
|
+
//== Converti delta in px per lo shift orizzontale
|
|
55
|
+
let delta = e.deltaY;
|
|
56
|
+
if (e.deltaMode === 1) delta *= 16;
|
|
57
|
+
else if (e.deltaMode === 2) delta *= el.clientHeight;
|
|
58
|
+
|
|
59
|
+
//== Verifica se il contenitore può ancora scrollare orizzontalmente
|
|
60
|
+
const atStart = el.scrollLeft <= 0;
|
|
61
|
+
const atEnd = el.scrollLeft + el.clientWidth >= el.scrollWidth - 1;
|
|
62
|
+
const scrollingRight = delta > 0;
|
|
63
|
+
const scrollingLeft = delta < 0;
|
|
64
|
+
const canScrollHoriz =
|
|
65
|
+
(scrollingRight && !atEnd) ||
|
|
66
|
+
(scrollingLeft && !atStart);
|
|
67
|
+
|
|
68
|
+
// Se non può più scrollare in quella direzione, lascia che la pagina gestisca lo scroll verticale
|
|
69
|
+
if (!canScrollHoriz) return;
|
|
70
|
+
|
|
71
|
+
//== Previeni il default solo quando facciamo noi lo scroll orizzontale
|
|
72
|
+
e.preventDefault();
|
|
73
|
+
|
|
74
|
+
//== rotella giù => destra
|
|
75
|
+
el.scrollLeft += delta * speed;
|
|
76
|
+
}, { passive: false });
|
|
77
|
+
}
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
import { PGS_toast } from "../functions/_notifications.js";
|
|
2
|
+
export async function PGS_sendForm(
|
|
3
|
+
append = {
|
|
4
|
+
formAppend: [
|
|
5
|
+
{ name: "", value: "" }
|
|
6
|
+
],
|
|
7
|
+
wpnonce: {
|
|
8
|
+
name: "",
|
|
9
|
+
value: ""
|
|
10
|
+
},
|
|
11
|
+
action: ""
|
|
12
|
+
},
|
|
13
|
+
tost = {
|
|
14
|
+
succesText: "Inviato con succeso",
|
|
15
|
+
errorGenericText: "Si è verificato un errore",
|
|
16
|
+
infoText: "Invio in corso..."
|
|
17
|
+
}, log = true) {
|
|
18
|
+
|
|
19
|
+
PGS_toast.info(tost.infoText, -1)
|
|
20
|
+
|
|
21
|
+
//== FORM DATA
|
|
22
|
+
const formData = new FormData();
|
|
23
|
+
|
|
24
|
+
//=== Mandatory data
|
|
25
|
+
formData.append(append.wpnonce.name, append.wpnonce.value);
|
|
26
|
+
formData.append('action', append.action);
|
|
27
|
+
|
|
28
|
+
//=== append esempio
|
|
29
|
+
append.formAppend.forEach(item => formData.append(item.name, item.value));
|
|
30
|
+
|
|
31
|
+
let status
|
|
32
|
+
|
|
33
|
+
try {
|
|
34
|
+
const response = await fetch('/wp-admin/admin-ajax.php', {
|
|
35
|
+
method: 'POST',
|
|
36
|
+
body: formData
|
|
37
|
+
});
|
|
38
|
+
|
|
39
|
+
if (!response.ok) {
|
|
40
|
+
PGS_toast.error(`Errore: ${response.status}`)
|
|
41
|
+
status = { success: false, data: [], response: response };
|
|
42
|
+
throw new Error(`HTTP error! status: ${response.status}`);
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
const result = await response.json();
|
|
46
|
+
|
|
47
|
+
if (result.success) {
|
|
48
|
+
status = result;
|
|
49
|
+
PGS_toast.success(tost.succesText)
|
|
50
|
+
|
|
51
|
+
} else {
|
|
52
|
+
status = result;
|
|
53
|
+
PGS_toast.error(result.data ? result.data.message : 'Errore sconosciuto')
|
|
54
|
+
console.error(result);
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
} catch (error) {
|
|
58
|
+
status = status ? status : { success: false, data: []};
|
|
59
|
+
PGS_toast.error(`Si è verificato un errore nella richiesta.`)
|
|
60
|
+
console.error('Errore:', error);
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
if (log) console.log("Status:", status);
|
|
64
|
+
if (log) console.log("formData:", Array.from(formData.entries()));
|
|
65
|
+
return status;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
/*
|
|
69
|
+
let documentForm = document.querySelector("#formExample");
|
|
70
|
+
if (documentForm) {
|
|
71
|
+
documentForm.addEventListener("submit", function (e) {
|
|
72
|
+
e.preventDefault();
|
|
73
|
+
|
|
74
|
+
let appendMandatory = {
|
|
75
|
+
formAppend: [
|
|
76
|
+
{
|
|
77
|
+
name: "",
|
|
78
|
+
value: ""
|
|
79
|
+
},
|
|
80
|
+
{
|
|
81
|
+
name: "",
|
|
82
|
+
value: ""
|
|
83
|
+
},
|
|
84
|
+
],
|
|
85
|
+
wpnonce: {
|
|
86
|
+
name: "testName",
|
|
87
|
+
value: "testValue"
|
|
88
|
+
},
|
|
89
|
+
action: "test_submit_form"
|
|
90
|
+
};
|
|
91
|
+
let tost = {
|
|
92
|
+
succesText: "inviato ottimo",
|
|
93
|
+
errorGenericText: "errore invio",
|
|
94
|
+
infoText: "Invio in corso...",
|
|
95
|
+
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
sendBooking(appendMandatory, tost)
|
|
99
|
+
})
|
|
100
|
+
} */
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
//= PGS
|
|
2
|
+
import "./_pgs.js";
|
|
3
|
+
|
|
4
|
+
//= BASE
|
|
5
|
+
import "./base/_darkmode.js";
|
|
6
|
+
import "./base/_object.js";
|
|
7
|
+
|
|
8
|
+
//= CN
|
|
9
|
+
import "./components/_accordion.js";
|
|
10
|
+
import "./components/_dropdown.js";
|
|
11
|
+
import "./components/_exeNotifications.js";
|
|
12
|
+
import "./components/_menu.js"
|
|
13
|
+
import "./components/_modals.js";
|
|
14
|
+
import "./components/_slides.js"
|
|
15
|
+
import "./components/_steps.js";
|
|
16
|
+
import "./components/_tabs.js";
|
|
17
|
+
|
|
18
|
+
//= patterns
|
|
19
|
+
import "./patterns/_header.js";
|
|
20
|
+
import "./patterns/_cookieConsent.js";
|