Files
MatchLiveTv/backend/public/tournament-invite-editor.js
T

264 lines
8.4 KiB
JavaScript

(function () {
var MIN_WIDTH = 80;
var MAX_WIDTH = 560;
function csrfToken() {
var meta = document.querySelector("meta[name='csrf-token']");
return meta ? meta.getAttribute("content") : "";
}
function initEditor(root) {
if (root.dataset.ready === "1") return;
root.dataset.ready = "1";
var surface = root.querySelector(".invite-editor__surface");
var handle = root.querySelector(".invite-editor__handle");
var fileInput = root.querySelector("[data-invite-file]");
var htmlField = root.closest("form").querySelector("[data-invite-html]");
var noteInput = root.closest("form").querySelector("[data-invite-note]");
var status = root.querySelector("[data-invite-status]");
var selectedImg = null;
var drag = null;
function showStatus(message, isError) {
if (!status) return;
if (!message) {
status.hidden = true;
status.textContent = "";
return;
}
status.hidden = false;
status.textContent = message;
status.classList.toggle("invite-editor__status--error", !!isError);
}
function syncHtml() {
if (htmlField) htmlField.value = surface.innerHTML;
}
function syncNote() {
var note = (noteInput && noteInput.value || "").trim();
var el = surface.querySelector("[data-invite-note]");
if (!note) {
if (el) el.remove();
syncHtml();
return;
}
if (!el) {
el = document.createElement("p");
el.setAttribute("data-invite-note", "");
var first = surface.querySelector("p");
if (first && first.nextSibling) surface.insertBefore(el, first.nextSibling);
else if (first) first.after(el);
else surface.appendChild(el);
}
el.textContent = note;
syncHtml();
}
function prepareImage(img) {
img.draggable = false;
img.style.maxWidth = "100%";
img.style.height = "auto";
if (!img.getAttribute("width") && img.naturalWidth) {
img.setAttribute("width", Math.min(img.naturalWidth, MAX_WIDTH));
}
}
function updateHandle() {
if (!selectedImg || !handle) return;
var frame = handle.parentElement.getBoundingClientRect();
var rect = selectedImg.getBoundingClientRect();
handle.hidden = false;
handle.style.left = rect.right - frame.left - 8 + "px";
handle.style.top = rect.bottom - frame.top - 8 + "px";
}
function clearSelection() {
selectedImg = null;
if (handle) handle.hidden = true;
surface.querySelectorAll("img.invite-editor__img--selected").forEach(function (img) {
img.classList.remove("invite-editor__img--selected");
});
}
function selectImage(img) {
clearSelection();
selectedImg = img;
img.classList.add("invite-editor__img--selected");
updateHandle();
}
function insertImage(url) {
surface.focus();
document.execCommand("insertHTML", false, '<img src="' + url.replace(/"/g, "&quot;") + '" alt="">');
var images = surface.querySelectorAll("img");
var img = images[images.length - 1];
if (img) {
prepareImage(img);
selectImage(img);
}
syncHtml();
}
function uploadFile(file) {
if (!file || !file.type.match(/^image\/(png|jpeg|webp|gif)$/)) {
showStatus(root.getAttribute("data-msg-type"), true);
return;
}
if (file.size > 2 * 1024 * 1024) {
showStatus(root.getAttribute("data-msg-size"), true);
return;
}
var data = new FormData();
data.append("file", file);
showStatus(root.getAttribute("data-msg-uploading"), false);
fetch(root.getAttribute("data-upload-url"), {
method: "POST",
headers: { "X-CSRF-Token": csrfToken(), Accept: "application/json" },
body: data,
credentials: "same-origin"
}).then(function (res) {
return res.json().then(function (json) {
if (!res.ok) throw new Error(json.error || root.getAttribute("data-msg-failed"));
return json;
});
}).then(function (json) {
showStatus("", false);
insertImage(json.url);
}).catch(function (err) {
showStatus(err.message || root.getAttribute("data-msg-failed"), true);
});
}
root.querySelectorAll("[data-invite-cmd]").forEach(function (btn) {
btn.addEventListener("mousedown", function (e) {
e.preventDefault();
});
btn.addEventListener("click", function (e) {
e.preventDefault();
var cmd = btn.getAttribute("data-invite-cmd");
surface.focus();
if (cmd === "createLink") {
var url = window.prompt(root.getAttribute("data-msg-link") || "URL", "https://");
if (url) document.execCommand("createLink", false, url);
} else if (cmd === "image") {
fileInput.click();
} else {
document.execCommand(cmd, false, null);
}
syncHtml();
});
});
fileInput.addEventListener("change", function () {
var file = fileInput.files && fileInput.files[0];
fileInput.value = "";
if (file) uploadFile(file);
});
surface.addEventListener("click", function (e) {
if (e.target.tagName === "IMG") {
e.preventDefault();
selectImage(e.target);
} else {
clearSelection();
}
});
surface.addEventListener("input", syncHtml);
surface.addEventListener("blur", syncHtml);
if (noteInput) noteInput.addEventListener("input", syncNote);
surface.addEventListener("paste", function (e) {
var items = e.clipboardData && e.clipboardData.files;
if (items && items.length && items[0].type.indexOf("image/") === 0) {
e.preventDefault();
uploadFile(items[0]);
}
});
["dragenter", "dragover"].forEach(function (type) {
surface.addEventListener(type, function (e) {
e.preventDefault();
surface.classList.add("invite-editor__surface--drop");
});
});
["dragleave", "drop"].forEach(function (type) {
surface.addEventListener(type, function () {
surface.classList.remove("invite-editor__surface--drop");
});
});
surface.addEventListener("drop", function (e) {
e.preventDefault();
var file = e.dataTransfer && e.dataTransfer.files && e.dataTransfer.files[0];
if (file) uploadFile(file);
});
handle.addEventListener("mousedown", function (e) {
if (!selectedImg) return;
e.preventDefault();
e.stopPropagation();
drag = {
startX: e.clientX,
startWidth: selectedImg.getBoundingClientRect().width
};
document.body.classList.add("invite-editor--resizing");
});
document.addEventListener("mousemove", function (e) {
if (!drag || !selectedImg) return;
var width = Math.round(Math.min(MAX_WIDTH, Math.max(MIN_WIDTH, drag.startWidth + (e.clientX - drag.startX))));
selectedImg.style.width = width + "px";
selectedImg.style.height = "auto";
selectedImg.setAttribute("width", String(width));
selectedImg.removeAttribute("height");
updateHandle();
});
document.addEventListener("mouseup", function () {
if (!drag) return;
drag = null;
document.body.classList.remove("invite-editor--resizing");
syncHtml();
});
window.addEventListener("resize", updateHandle);
surface.querySelectorAll("img").forEach(prepareImage);
var form = root.closest("form");
form.addEventListener("submit", function () {
syncNote();
syncHtml();
});
form.addEventListener("turbo:submit-start", function () {
syncNote();
syncHtml();
});
syncNote();
syncHtml();
}
function bindSelectUncovered() {
document.querySelectorAll("[data-select-uncovered]").forEach(function (btn) {
if (btn.dataset.boundSelect === "1") return;
btn.dataset.boundSelect = "1";
btn.addEventListener("click", function (e) {
e.preventDefault();
var formId = btn.getAttribute("data-select-uncovered");
document.querySelectorAll('input[data-uncovered-match][form="' + formId + '"]').forEach(function (cb) {
cb.checked = true;
});
});
});
}
function boot() {
document.querySelectorAll("[data-invite-editor]").forEach(initEditor);
bindSelectUncovered();
}
document.addEventListener("DOMContentLoaded", boot);
document.addEventListener("turbo:load", boot);
})();