Tutte le view marketing, legali, viewer, dashboard e admin usano t(); mailer utente-facing e flash localizzati; admin con LocaleResolver e selettore lingua. Co-authored-by: Cursor <cursoragent@cursor.com>
369 lines
13 KiB
JavaScript
369 lines
13 KiB
JavaScript
(function () {
|
|
var pendingForm = null;
|
|
var pendingScope = null;
|
|
var dialog = null;
|
|
|
|
var DEFAULT_I18N = {
|
|
eyebrow: "Conferma richiesta",
|
|
title: "Sei sicuro?",
|
|
deleteTitle: "Eliminare definitivamente?",
|
|
confirmOk: "Conferma",
|
|
deleteOk: "Elimina",
|
|
cancel: "Annulla",
|
|
multiDeleteTitle: "Cosa vuoi eliminare?",
|
|
multiDeleteMessage: "Scegli dove rimuovere il replay. L'operazione è irreversibile.",
|
|
deleteYoutubeTitle: "Eliminare da YouTube?",
|
|
deleteYoutubeMessage: "Il video verrà rimosso da YouTube. Il replay resterà disponibile sul sito.",
|
|
deleteYoutubeOk: "Elimina da YouTube",
|
|
deleteSiteTitle: "Eliminare dal sito?",
|
|
deleteSiteMessageWithYoutube: "Il replay verrà rimosso dal sito. Il video su YouTube resterà online.",
|
|
deleteSiteMessageOnly: "Stai per eliminare definitivamente questo replay dal sito. L'operazione è irreversibile.",
|
|
deleteSiteOk: "Elimina dal sito",
|
|
choiceSiteLabel: "Solo dal sito",
|
|
choiceSiteHintWithYoutube: "Il video resta su YouTube",
|
|
choiceSiteHintOnly: "Rimuove i file dal sito",
|
|
choiceYoutubeLabel: "Solo da YouTube",
|
|
choiceYoutubeHintWithSite: "Resta disponibile sul sito",
|
|
choiceYoutubeHintOnly: "Rimuove solo il video YouTube",
|
|
choiceBothLabel: "Da sito e YouTube",
|
|
choiceBothHint: "Eliminazione completa"
|
|
};
|
|
|
|
function loadI18n() {
|
|
var raw = document.body && document.body.getAttribute("data-confirm-i18n");
|
|
if (!raw) return DEFAULT_I18N;
|
|
try {
|
|
var parsed = JSON.parse(raw);
|
|
var merged = {};
|
|
for (var key in DEFAULT_I18N) {
|
|
merged[key] = parsed[key] || DEFAULT_I18N[key];
|
|
}
|
|
return merged;
|
|
} catch (err) {
|
|
return DEFAULT_I18N;
|
|
}
|
|
}
|
|
|
|
var I18N = loadI18n();
|
|
|
|
function escapeHtml(str) {
|
|
return String(str == null ? "" : str).replace(/[&<>"']/g, function (ch) {
|
|
return (
|
|
{
|
|
"&": "&",
|
|
"<": "<",
|
|
">": ">",
|
|
'"': """,
|
|
"'": "'"
|
|
}[ch] || ch
|
|
);
|
|
});
|
|
}
|
|
|
|
function ensureDialog() {
|
|
if (dialog) return dialog;
|
|
|
|
dialog = document.createElement("div");
|
|
dialog.className = "site-confirm";
|
|
dialog.setAttribute("role", "dialog");
|
|
dialog.setAttribute("aria-modal", "true");
|
|
dialog.setAttribute("aria-labelledby", "site-confirm-title");
|
|
dialog.hidden = true;
|
|
dialog.innerHTML =
|
|
'<div class="site-confirm__backdrop" data-confirm-cancel></div>' +
|
|
'<div class="site-confirm__panel site-confirm__panel--choices">' +
|
|
' <p class="site-confirm__eyebrow">' + escapeHtml(I18N.eyebrow) + '</p>' +
|
|
' <h2 class="site-confirm__title" id="site-confirm-title">' + escapeHtml(I18N.title) + '</h2>' +
|
|
' <p class="site-confirm__message" id="site-confirm-message"></p>' +
|
|
' <div class="site-confirm__choices" id="site-confirm-choices" hidden>' +
|
|
' <button type="button" class="site-confirm__choice" data-confirm-scope="site">' +
|
|
' <span class="site-confirm__choice-label">' + escapeHtml(I18N.choiceSiteLabel) + '</span>' +
|
|
' <span class="site-confirm__choice-hint" data-hint-site>' + escapeHtml(I18N.choiceSiteHintWithYoutube) + '</span>' +
|
|
" </button>" +
|
|
' <button type="button" class="site-confirm__choice" data-confirm-scope="youtube">' +
|
|
' <span class="site-confirm__choice-label">' + escapeHtml(I18N.choiceYoutubeLabel) + '</span>' +
|
|
' <span class="site-confirm__choice-hint" data-hint-youtube>' + escapeHtml(I18N.choiceYoutubeHintWithSite) + '</span>' +
|
|
" </button>" +
|
|
' <button type="button" class="site-confirm__choice site-confirm__choice--danger" data-confirm-scope="both">' +
|
|
' <span class="site-confirm__choice-label">' + escapeHtml(I18N.choiceBothLabel) + '</span>' +
|
|
' <span class="site-confirm__choice-hint" data-hint-both>' + escapeHtml(I18N.choiceBothHint) + '</span>' +
|
|
" </button>" +
|
|
" </div>" +
|
|
' <div class="site-confirm__actions">' +
|
|
' <button type="button" class="btn btn-secondary site-confirm__btn" data-confirm-cancel>' + escapeHtml(I18N.cancel) + '</button>' +
|
|
' <button type="button" class="btn btn-primary site-confirm__btn site-confirm__btn--danger" data-confirm-ok>' + escapeHtml(I18N.deleteOk) + '</button>' +
|
|
" </div>" +
|
|
"</div>";
|
|
|
|
document.body.appendChild(dialog);
|
|
|
|
dialog.addEventListener("click", function (event) {
|
|
var target = event.target;
|
|
if (!(target instanceof Element)) return;
|
|
if (target.closest("[data-confirm-cancel]")) {
|
|
closeDialog();
|
|
return;
|
|
}
|
|
var scopeBtn = target.closest("[data-confirm-scope]");
|
|
if (scopeBtn) {
|
|
if (scopeBtn.disabled || scopeBtn.getAttribute("aria-disabled") === "true") return;
|
|
submitPending(scopeBtn.getAttribute("data-confirm-scope"));
|
|
return;
|
|
}
|
|
if (target.closest("[data-confirm-ok]")) {
|
|
submitPending(pendingScope || "both");
|
|
}
|
|
});
|
|
|
|
document.addEventListener("keydown", function (event) {
|
|
if (!dialog || dialog.hidden) return;
|
|
if (event.key === "Escape") {
|
|
event.preventDefault();
|
|
closeDialog();
|
|
}
|
|
});
|
|
|
|
return dialog;
|
|
}
|
|
|
|
function setChoiceVisible(btn, visible) {
|
|
if (!(btn instanceof HTMLElement)) return;
|
|
btn.hidden = !visible;
|
|
if (!visible) {
|
|
btn.disabled = true;
|
|
btn.setAttribute("aria-disabled", "true");
|
|
}
|
|
}
|
|
|
|
function setChoiceEnabled(btn, enabled) {
|
|
if (!(btn instanceof HTMLButtonElement)) return;
|
|
btn.disabled = !enabled;
|
|
btn.setAttribute("aria-disabled", enabled ? "false" : "true");
|
|
btn.classList.toggle("site-confirm__choice--disabled", !enabled);
|
|
}
|
|
|
|
function openDialog(message, options) {
|
|
options = options || {};
|
|
var hasSite = options.hasSite !== false;
|
|
var hasYoutube = !!options.hasYoutube;
|
|
var isDelete = !!options.isDelete;
|
|
var canSite = hasSite;
|
|
var canYoutube = hasYoutube;
|
|
var canBoth = hasSite && hasYoutube;
|
|
var choiceCount = (canSite ? 1 : 0) + (canYoutube ? 1 : 0) + (canBoth ? 1 : 0);
|
|
// Una sola destinazione disponibile → conferma semplice, senza elenco
|
|
var multi = !!options.multi && choiceCount > 1;
|
|
|
|
if (canBoth) pendingScope = "both";
|
|
else if (canSite) pendingScope = "site";
|
|
else if (canYoutube) pendingScope = "youtube";
|
|
else pendingScope = "both";
|
|
|
|
var el = ensureDialog();
|
|
var titleEl = el.querySelector("#site-confirm-title");
|
|
var messageEl = el.querySelector("#site-confirm-message");
|
|
var okBtn = el.querySelector("[data-confirm-ok]");
|
|
var choicesEl = el.querySelector("#site-confirm-choices");
|
|
var siteBtn = el.querySelector('[data-confirm-scope="site"]');
|
|
var youtubeBtn = el.querySelector('[data-confirm-scope="youtube"]');
|
|
var bothBtn = el.querySelector('[data-confirm-scope="both"]');
|
|
var hintSite = el.querySelector("[data-hint-site]");
|
|
var hintYoutube = el.querySelector("[data-hint-youtube]");
|
|
var hintBoth = el.querySelector("[data-hint-both]");
|
|
var panel = el.querySelector(".site-confirm__panel");
|
|
|
|
if (titleEl) {
|
|
if (multi) {
|
|
titleEl.textContent = I18N.multiDeleteTitle;
|
|
} else if (pendingScope === "youtube") {
|
|
titleEl.textContent = I18N.deleteYoutubeTitle;
|
|
} else if (pendingScope === "site") {
|
|
titleEl.textContent = I18N.deleteSiteTitle;
|
|
} else {
|
|
titleEl.textContent = isDelete ? I18N.deleteTitle : I18N.title;
|
|
}
|
|
}
|
|
|
|
if (messageEl) {
|
|
if (multi) {
|
|
messageEl.textContent = I18N.multiDeleteMessage;
|
|
} else if (pendingScope === "youtube") {
|
|
messageEl.textContent = I18N.deleteYoutubeMessage;
|
|
} else if (pendingScope === "site") {
|
|
messageEl.textContent = hasYoutube
|
|
? I18N.deleteSiteMessageWithYoutube
|
|
: I18N.deleteSiteMessageOnly;
|
|
} else {
|
|
messageEl.textContent = message;
|
|
}
|
|
}
|
|
|
|
if (choicesEl) choicesEl.hidden = !multi;
|
|
if (panel) panel.classList.toggle("site-confirm__panel--choices", multi);
|
|
|
|
if (okBtn instanceof HTMLElement) {
|
|
okBtn.hidden = multi;
|
|
if (pendingScope === "youtube") okBtn.textContent = I18N.deleteYoutubeOk;
|
|
else if (pendingScope === "site") okBtn.textContent = I18N.deleteSiteOk;
|
|
else okBtn.textContent = isDelete ? I18N.deleteOk : I18N.confirmOk;
|
|
}
|
|
|
|
setChoiceVisible(siteBtn, canSite);
|
|
setChoiceVisible(youtubeBtn, canYoutube);
|
|
setChoiceVisible(bothBtn, canBoth);
|
|
if (multi) {
|
|
setChoiceEnabled(siteBtn, canSite);
|
|
setChoiceEnabled(youtubeBtn, canYoutube);
|
|
setChoiceEnabled(bothBtn, canBoth);
|
|
if (hintSite) {
|
|
hintSite.textContent = canYoutube
|
|
? I18N.choiceSiteHintWithYoutube
|
|
: I18N.choiceSiteHintOnly;
|
|
}
|
|
if (hintYoutube) {
|
|
hintYoutube.textContent = canSite
|
|
? I18N.choiceYoutubeHintWithSite
|
|
: I18N.choiceYoutubeHintOnly;
|
|
}
|
|
if (hintBoth) hintBoth.textContent = I18N.choiceBothHint;
|
|
}
|
|
|
|
el.hidden = false;
|
|
document.body.classList.add("site-confirm-open");
|
|
|
|
if (multi) {
|
|
var focusBtn = canSite ? siteBtn : canYoutube ? youtubeBtn : bothBtn;
|
|
if (focusBtn instanceof HTMLElement) focusBtn.focus();
|
|
} else if (okBtn instanceof HTMLElement) {
|
|
okBtn.focus();
|
|
}
|
|
}
|
|
|
|
function closeDialog() {
|
|
if (!dialog) return;
|
|
dialog.hidden = true;
|
|
document.body.classList.remove("site-confirm-open");
|
|
pendingForm = null;
|
|
pendingScope = null;
|
|
}
|
|
|
|
function ensureHiddenInput(form, name, value) {
|
|
var input = form.querySelector('input[name="' + name + '"]');
|
|
if (!(input instanceof HTMLInputElement)) {
|
|
input = document.createElement("input");
|
|
input.type = "hidden";
|
|
input.name = name;
|
|
form.appendChild(input);
|
|
}
|
|
input.value = value;
|
|
}
|
|
|
|
function submitPending(scope) {
|
|
var form = pendingForm;
|
|
if (form && form.closest(".replay-archive")) {
|
|
saveArchiveScrollPosition();
|
|
}
|
|
closeDialog();
|
|
if (!form) return;
|
|
ensureHiddenInput(form, "delete_scope", scope || "both");
|
|
form.dataset.confirmAccepted = "1";
|
|
if (typeof form.requestSubmit === "function") {
|
|
form.requestSubmit();
|
|
} else {
|
|
form.submit();
|
|
}
|
|
}
|
|
|
|
document.addEventListener(
|
|
"submit",
|
|
function (event) {
|
|
var form = event.target;
|
|
if (!(form instanceof HTMLFormElement)) return;
|
|
|
|
if (form.dataset.confirmAccepted === "1") {
|
|
delete form.dataset.confirmAccepted;
|
|
return;
|
|
}
|
|
|
|
var message =
|
|
form.getAttribute("data-confirm") ||
|
|
form.getAttribute("data-turbo-confirm");
|
|
if (!message) return;
|
|
|
|
event.preventDefault();
|
|
event.stopImmediatePropagation();
|
|
pendingForm = form;
|
|
pendingScope = "both";
|
|
|
|
var mode = form.getAttribute("data-confirm-mode") || "";
|
|
var isReplayDelete =
|
|
mode === "delete-replay" || mode === "delete-replay-youtube";
|
|
var hasYoutube =
|
|
form.getAttribute("data-has-youtube") === "1" ||
|
|
mode === "delete-replay-youtube";
|
|
var hasSiteAttr = form.getAttribute("data-has-site");
|
|
var hasSite = hasSiteAttr == null ? true : hasSiteAttr === "1";
|
|
var isDelete =
|
|
form.getAttribute("data-confirm-kind") === "delete" || isReplayDelete;
|
|
|
|
openDialog(message, {
|
|
multi: isReplayDelete,
|
|
hasYoutube: hasYoutube,
|
|
hasSite: hasSite,
|
|
isDelete: isDelete
|
|
});
|
|
},
|
|
true
|
|
);
|
|
|
|
// Dopo submit nell'archivio replay, resta alla stessa altezza di scroll
|
|
// (il redirect ricarica la pagina e altrimenti torna in cima).
|
|
var SCROLL_KEY = "matchlivetv.replayArchive.scrollY";
|
|
|
|
function saveArchiveScrollPosition() {
|
|
try {
|
|
sessionStorage.setItem(
|
|
SCROLL_KEY,
|
|
String(window.scrollY || window.pageYOffset || 0)
|
|
);
|
|
} catch (err) {
|
|
/* ignore */
|
|
}
|
|
}
|
|
|
|
function saveArchiveScroll(event) {
|
|
var form = event.target;
|
|
if (!(form instanceof HTMLFormElement)) return;
|
|
if (!form.closest(".replay-archive")) return;
|
|
var needsConfirm =
|
|
form.getAttribute("data-confirm") ||
|
|
form.getAttribute("data-turbo-confirm");
|
|
// Con confirm lo scroll si salva in submitPending, dopo la scelta nel dialog
|
|
if (needsConfirm) return;
|
|
saveArchiveScrollPosition();
|
|
}
|
|
|
|
function restoreArchiveScroll() {
|
|
try {
|
|
var raw = sessionStorage.getItem(SCROLL_KEY);
|
|
if (raw == null) return;
|
|
sessionStorage.removeItem(SCROLL_KEY);
|
|
var top = parseInt(raw, 10);
|
|
if (isNaN(top)) return;
|
|
window.scrollTo(0, top);
|
|
requestAnimationFrame(function () {
|
|
window.scrollTo(0, top);
|
|
});
|
|
} catch (err) {
|
|
/* ignore */
|
|
}
|
|
}
|
|
|
|
document.addEventListener("submit", saveArchiveScroll, true);
|
|
if (document.readyState === "loading") {
|
|
document.addEventListener("DOMContentLoaded", restoreArchiveScroll);
|
|
} else {
|
|
restoreArchiveScroll();
|
|
}
|
|
})();
|