botui/ui/suite/mail/mail.js
Rodrigo Rodriguez (Pragmatismo) 69654f37d6 refactor(ui): extract inline CSS/JS to external files
Phase 2 of CSS/JS extraction - replace inline styles and scripts with
external file references for better maintainability and caching.

Files updated:
- home.html -> css/home.css, js/home.js
- tasks/tasks.html -> tasks/tasks.css, tasks/tasks.js
- admin/index.html -> admin/admin.css, admin/admin.js
- analytics/analytics.html -> analytics/analytics.css, analytics/analytics.js
- mail/mail.html -> mail/mail.css, mail/mail.js
- monitoring/monitoring.html -> monitoring/monitoring.css, monitoring/monitoring.js
- attendant/index.html -> attendant/attendant.css, attendant/attendant.js

All JS wrapped in IIFE pattern to prevent global namespace pollution.
Functions called from HTML onclick handlers exposed via window object.
HTMX reload handlers included for proper reinitialization.

Per PROMPT.md: no CDN links, HTMX-first approach, local assets only.
2026-01-10 20:12:48 -03:00

478 lines
13 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

(function () {
"use strict";
var selectedEmails = new Set();
var currentFolder = "inbox";
function openCompose() {
var modal = document.getElementById("compose-modal");
if (modal && modal.showModal) {
modal.showModal();
}
}
function closeCompose() {
var modal = document.getElementById("compose-modal");
if (modal && modal.close) {
modal.close();
}
}
function minimizeCompose() {
closeCompose();
}
function toggleCcBcc() {
document.querySelectorAll(".cc-bcc").forEach(function (el) {
el.style.display = el.style.display === "none" ? "flex" : "none";
});
}
function toggleScheduleMenu() {
var menu = document.getElementById("schedule-menu");
if (menu) {
menu.classList.toggle("show");
}
}
function scheduleSend(option) {
var date = new Date();
switch (option) {
case "tomorrow-morning":
date.setDate(date.getDate() + 1);
date.setHours(8, 0, 0, 0);
break;
case "tomorrow-afternoon":
date.setDate(date.getDate() + 1);
date.setHours(13, 0, 0, 0);
break;
case "monday":
var daysUntilMonday = (8 - date.getDay()) % 7 || 7;
date.setDate(date.getDate() + daysUntilMonday);
date.setHours(8, 0, 0, 0);
break;
}
confirmScheduleSend(date);
toggleScheduleMenu();
}
function openCustomSchedule() {
toggleScheduleMenu();
var today = new Date().toISOString().split("T")[0];
var dateInput = document.getElementById("schedule-date");
if (dateInput) {
dateInput.min = today;
dateInput.value = today;
}
var modal = document.getElementById("schedule-modal");
if (modal && modal.showModal) {
modal.showModal();
}
}
function closeScheduleModal() {
var modal = document.getElementById("schedule-modal");
if (modal && modal.close) {
modal.close();
}
}
function confirmSchedule() {
var dateInput = document.getElementById("schedule-date");
var timeInput = document.getElementById("schedule-time");
if (dateInput && timeInput) {
var scheduledDate = new Date(dateInput.value + "T" + timeInput.value);
confirmScheduleSend(scheduledDate);
}
closeScheduleModal();
}
function confirmScheduleSend(date) {
var form = document.getElementById("compose-form");
if (form) {
var input = document.createElement("input");
input.type = "hidden";
input.name = "scheduled_at";
input.value = date.toISOString();
form.appendChild(input);
prepareSubmit();
form.requestSubmit();
}
}
function prepareSubmit() {
var body = document.getElementById("compose-body");
var hidden = document.getElementById("compose-body-hidden");
if (body && hidden) {
hidden.value = body.innerHTML;
}
}
function formatText(command) {
document.execCommand(command, false, null);
var body = document.getElementById("compose-body");
if (body) {
body.focus();
}
}
function openTemplates() {
var modal = document.getElementById("templates-modal");
if (modal && modal.showModal) {
modal.showModal();
}
}
function closeTemplates() {
var modal = document.getElementById("templates-modal");
if (modal && modal.close) {
modal.close();
}
}
function openSignatures() {
var modal = document.getElementById("signatures-modal");
if (modal && modal.showModal) {
modal.showModal();
}
}
function closeSignatures() {
var modal = document.getElementById("signatures-modal");
if (modal && modal.close) {
modal.close();
}
}
function openRules() {
var modal = document.getElementById("rules-modal");
if (modal && modal.showModal) {
modal.showModal();
}
}
function closeRules() {
var modal = document.getElementById("rules-modal");
if (modal && modal.close) {
modal.close();
}
}
function openAutoResponder() {
var modal = document.getElementById("autoresponder-modal");
if (modal && modal.showModal) {
modal.showModal();
}
}
function closeAutoResponder() {
var modal = document.getElementById("autoresponder-modal");
if (modal && modal.close) {
modal.close();
}
}
function saveAutoResponder() {
var form = document.getElementById("autoresponder-form");
if (form && typeof htmx !== "undefined") {
htmx.trigger(form, "submit");
}
closeAutoResponder();
if (typeof window.showNotification === "function") {
window.showNotification("Auto-reply settings saved", "success");
}
}
function openLabelManager() {
if (typeof window.showNotification === "function") {
window.showNotification("Label manager coming soon", "info");
}
}
function toggleSelectAll(checkbox) {
var items = document.querySelectorAll('.mail-item input[type="checkbox"]');
items.forEach(function (item) {
item.checked = checkbox.checked;
if (checkbox.checked) {
selectedEmails.add(item.dataset.id);
} else {
selectedEmails.delete(item.dataset.id);
}
});
updateBulkActions();
}
function updateBulkActions() {
var bulkBar = document.getElementById("bulk-actions");
if (bulkBar) {
if (selectedEmails.size > 0) {
bulkBar.style.display = "flex";
var countEl = bulkBar.querySelector(".selected-count");
if (countEl) {
countEl.textContent = selectedEmails.size + " selected";
}
} else {
bulkBar.style.display = "none";
}
}
}
function refreshMailList() {
var folderEl = document.querySelector(
'[data-folder="' + currentFolder + '"]',
);
if (folderEl && typeof htmx !== "undefined") {
htmx.trigger(folderEl, "click");
}
}
function insertSignature() {
fetch("/api/email/signatures/default")
.then(function (r) {
return r.json();
})
.then(function (sig) {
if (sig.content_html) {
var body = document.getElementById("compose-body");
if (body) {
body.innerHTML += "<br><br>" + sig.content_html;
}
}
})
.catch(function (e) {
console.warn("Failed to load signature:", e);
});
}
function showTemplateSelector() {
openTemplates();
}
function attachFile() {
var input = document.createElement("input");
input.type = "file";
input.multiple = true;
input.onchange = function (e) {
var files = e.target.files;
var container = document.getElementById("compose-attachments");
if (container) {
Array.from(files).forEach(function (file) {
var chip = document.createElement("div");
chip.className = "attachment-chip";
chip.innerHTML =
"<span>" +
escapeHtml(file.name) +
"</span>" +
'<button type="button" onclick="this.parentElement.remove()">×</button>';
container.appendChild(chip);
});
}
};
input.click();
}
function insertLink() {
var url = prompt("Enter URL:");
if (url) {
document.execCommand("createLink", false, url);
}
}
function insertImage() {
var url = prompt("Enter image URL:");
if (url) {
document.execCommand("insertImage", false, url);
}
}
function saveDraft() {
prepareSubmit();
var form = document.getElementById("compose-form");
if (form) {
var formData = new FormData(form);
fetch("/api/email/draft", {
method: "POST",
body: formData,
})
.then(function () {
if (typeof window.showNotification === "function") {
window.showNotification("Draft saved", "success");
}
})
.catch(function (e) {
console.warn("Failed to save draft:", e);
});
}
}
function createNewTemplate() {
if (typeof window.showNotification === "function") {
window.showNotification("Template editor coming soon", "info");
}
}
function createNewSignature() {
if (typeof window.showNotification === "function") {
window.showNotification("Signature editor coming soon", "info");
}
}
function createNewRule() {
if (typeof window.showNotification === "function") {
window.showNotification("Rule editor coming soon", "info");
}
}
function archiveSelected() {
if (typeof window.showNotification === "function") {
window.showNotification(
selectedEmails.size + " emails archived",
"success",
);
}
selectedEmails.clear();
updateBulkActions();
refreshMailList();
}
function markAsRead() {
if (typeof window.showNotification === "function") {
window.showNotification(
selectedEmails.size + " emails marked as read",
"success",
);
}
selectedEmails.clear();
updateBulkActions();
refreshMailList();
}
function addLabelToSelected() {
if (typeof window.showNotification === "function") {
window.showNotification("Label picker coming soon", "info");
}
}
function deleteSelected() {
if (confirm("Delete " + selectedEmails.size + " emails?")) {
if (typeof window.showNotification === "function") {
window.showNotification(
selectedEmails.size + " emails deleted",
"success",
);
}
selectedEmails.clear();
updateBulkActions();
refreshMailList();
}
}
function openAddAccount() {
var modal = document.getElementById("account-modal");
if (modal && modal.showModal) {
modal.showModal();
}
}
function closeAddAccount() {
var modal = document.getElementById("account-modal");
if (modal && modal.close) {
modal.close();
}
}
function saveAccount() {
var form = document.getElementById("account-form");
if (form && typeof htmx !== "undefined") {
htmx.trigger(form, "submit");
}
closeAddAccount();
if (typeof window.showNotification === "function") {
window.showNotification("Email account added", "success");
}
}
function escapeHtml(text) {
var div = document.createElement("div");
div.textContent = text;
return div.innerHTML;
}
function initFolderHandlers() {
document
.querySelectorAll(".nav-item[data-folder]")
.forEach(function (item) {
item.addEventListener("click", function () {
document.querySelectorAll(".nav-item").forEach(function (i) {
i.classList.remove("active");
});
this.classList.add("active");
currentFolder = this.dataset.folder;
});
});
}
function initMail() {
initFolderHandlers();
var inboxItem = document.querySelector('.nav-item[data-folder="inbox"]');
if (inboxItem && typeof htmx !== "undefined") {
htmx.trigger(inboxItem, "click");
}
}
window.openCompose = openCompose;
window.closeCompose = closeCompose;
window.minimizeCompose = minimizeCompose;
window.toggleCcBcc = toggleCcBcc;
window.toggleScheduleMenu = toggleScheduleMenu;
window.scheduleSend = scheduleSend;
window.openCustomSchedule = openCustomSchedule;
window.closeScheduleModal = closeScheduleModal;
window.confirmSchedule = confirmSchedule;
window.prepareSubmit = prepareSubmit;
window.formatText = formatText;
window.openTemplates = openTemplates;
window.closeTemplates = closeTemplates;
window.openSignatures = openSignatures;
window.closeSignatures = closeSignatures;
window.openRules = openRules;
window.closeRules = closeRules;
window.openAutoResponder = openAutoResponder;
window.closeAutoResponder = closeAutoResponder;
window.saveAutoResponder = saveAutoResponder;
window.openLabelManager = openLabelManager;
window.toggleSelectAll = toggleSelectAll;
window.updateBulkActions = updateBulkActions;
window.refreshMailList = refreshMailList;
window.insertSignature = insertSignature;
window.showTemplateSelector = showTemplateSelector;
window.attachFile = attachFile;
window.insertLink = insertLink;
window.insertImage = insertImage;
window.saveDraft = saveDraft;
window.createNewTemplate = createNewTemplate;
window.createNewSignature = createNewSignature;
window.createNewRule = createNewRule;
window.archiveSelected = archiveSelected;
window.markAsRead = markAsRead;
window.addLabelToSelected = addLabelToSelected;
window.deleteSelected = deleteSelected;
window.openAddAccount = openAddAccount;
window.closeAddAccount = closeAddAccount;
window.saveAccount = saveAccount;
if (document.readyState === "loading") {
document.addEventListener("DOMContentLoaded", initMail);
} else {
initMail();
}
document.body.addEventListener("htmx:afterSwap", function (evt) {
if (evt.detail.target && evt.detail.target.id === "main-content") {
if (document.querySelector(".mail-layout")) {
initMail();
}
}
});
})();