(function () { "use strict"; var $ = window.MailSharp; var DEFAULT_mailsPageSize = 20; var mailsPageSize = DEFAULT_mailsPageSize; var state = { strings: {}, lang: "nl", contacts: [], filter: "", selectedEmail: null, editing: false, mails: null, mailsPage: 1, selectedMail: null, selectedMessage: null }; function bootstrap() { $.initHeader().then(function (result) { state.strings = result.langState.strings; state.lang = result.langState.current; if (result.authState.account && result.authState.account.contactsPerPage > 0) { mailsPageSize = result.authState.account.contactsPerPage; } return $.apiFetch("api/contacts"); }).then(function (contacts) { state.contacts = contacts; renderContactList(); renderHeader(); renderMailsList(); renderMailDetail(); }); } function filteredContacts() { var f = state.filter.toLowerCase(); if (!f) return state.contacts; return state.contacts.filter(function (c) { return c.displayName.toLowerCase().indexOf(f) !== -1 || c.email.toLowerCase().indexOf(f) !== -1; }); } function selectedContact() { return state.contacts.find(function (c) { return c.email === state.selectedEmail; }); } // ---------- rendering ---------- function renderContactList() { var t = state.strings; var list = filteredContacts(); var html; if (list.length === 0) { html = '
' + $.esc(t.contacts_empty) + "
"; } else { html = '"; } document.getElementById("contactListBody").innerHTML = html; } function renderHeader() { var t = state.strings; var header = document.getElementById("contactHeader"); var contact = selectedContact(); if (!contact) { header.innerHTML = '' + $.esc(t.contacts_select) + ""; return; } var infoHtml = state.editing ? ( '
' ) : ( '
' + '' + $.esc(contact.displayName) + "" + '' + $.esc(contact.email) + "" + "
" ); var actionsHtml = state.editing ? ( '" + '" ) : ( '' + $.esc(t.mail_refresh) + "" + '' + $.esc(t.contacts_edit) + "" + '' + $.esc(t.contacts_mail) + "" ); header.innerHTML = infoHtml + actionsHtml; } function renderMailsList() { var t = state.strings; var body = document.getElementById("contactMailsBody"); var contact = selectedContact(); if (!contact) { body.innerHTML = '
' + $.esc(t.contacts_select) + "
"; return; } if (state.mails == null) { body.innerHTML = ""; return; } if (state.mails.length === 0) { body.innerHTML = '
' + $.esc(t.contacts_no_mails) + "
"; return; } var totalCount = state.mails.length; var totalPages = Math.max(1, Math.ceil(totalCount / mailsPageSize)); var page = Math.min(Math.max(1, state.mailsPage), totalPages); var pageMails = state.mails.slice((page - 1) * mailsPageSize, page * mailsPageSize); body.innerHTML = '" + '
' + '' + $.esc(t.mail_previous) + "" + '' + $.esc($.formatTemplate(t.mail_pager_info, page, totalPages, totalCount)) + "" + '' + $.esc(t.mail_next) + "" + "
"; } function renderMailRow(m) { var selected = state.selectedMail && state.selectedMail.uid === m.uid && state.selectedMail.folder === m.folder ? "selected" : ""; return ( '
  • ' + '
    ' + $.esc(m.subject) + '
    ' + '
    ' + $.esc(m.from) + "
    " + '
    ' + $.formatDate(m.date) + "
    " + "
  • " ); } function updateSelectedMailRowClasses() { document.querySelectorAll("#contactMailsBody .message-row").forEach(function (row) { var uid = parseInt(row.getAttribute("data-uid"), 10); var folder = row.getAttribute("data-folder"); var isSelected = !!state.selectedMail && state.selectedMail.uid === uid && state.selectedMail.folder === folder; row.classList.toggle("selected", isSelected); }); } function renderMailDetail() { var t = state.strings; var pane = document.getElementById("contactMailDetailPane"); var content = document.getElementById("contactContent"); var m = state.selectedMessage; if (!m) { pane.innerHTML = '
    ' + $.esc(t.detail_empty) + "
    "; content.classList.remove("has-detail"); return; } content.classList.add("has-detail"); var imagesBanner = ""; if (m.hasExternalImages && !m.imagesAllowed) { imagesBanner = '
    ' + $.esc(t.detail_images_blocked) + " " + '" + "
    "; } var attachmentsHtml = ""; if (m.attachments && m.attachments.length > 0) { attachmentsHtml = '
    ' + m.attachments.map(function (att) { return ( '
    ' + "📎 " + $.esc(att.fileName) + " (" + (Math.round(att.sizeBytes / 1024 * 10) / 10) + " kB)" + '" + '" + "
    " ); }).join("") + "
    "; } var bodyHtml = (m.htmlBody && m.htmlBody.trim() !== "") ? '
    ' : '
    ' + $.esc(m.textBody) + "
    "; pane.innerHTML = '
    ' + '' + $.esc(t.detail_back_to_list) + "" + '
    ' + $.esc(m.subject) + "
    " + '
    ' + "
    " + $.esc(t.detail_from) + " " + $.esc(m.from) + "
    " + "
    " + $.esc(t.detail_to) + " " + $.esc(m.to) + "
    " + (m.cc ? "
    " + $.esc(t.detail_cc) + " " + $.esc(m.cc) + "
    " : "") + "
    " + $.esc(t.detail_date) + " " + $.esc($.formatFullDate(m.date, state.lang)) + "
    " + "
    " + imagesBanner + attachmentsHtml + bodyHtml + "
    "; } // ---------- data loading ---------- function loadContactMails(email, opts) { opts = opts || {}; var params = new URLSearchParams({ email: email, refresh: !!opts.refresh }); return $.apiFetch("api/contacts/mails?" + params.toString()).then(function (mails) { state.mails = mails; state.mailsPage = 1; }); } function openMail(folder, uid) { if (state.selectedMail && state.selectedMail.uid === uid && state.selectedMail.folder === folder) return; state.selectedMail = { folder: folder, uid: uid }; updateSelectedMailRowClasses(); var params = new URLSearchParams({ folder: folder }); $.apiFetch("api/mail/messages/" + uid + "?" + params.toString()).then(function (detail) { state.selectedMessage = detail; renderMailDetail(); }).catch(reportError); } function closeMailDetail() { state.selectedMail = null; state.selectedMessage = null; renderMailDetail(); updateSelectedMailRowClasses(); } function reportError(err) { if (err.cancelled) return; window.alert(err.message); } // ---------- events ---------- document.getElementById("sidebarToggle").addEventListener("click", function () { document.getElementById("sidebar").classList.toggle("open"); }); document.getElementById("contactSearch").addEventListener("input", function (e) { state.filter = e.target.value; renderContactList(); }); document.getElementById("contactListBody").addEventListener("click", function (e) { var row = e.target.closest(".message-row[data-email]"); if (!row) return; var email = row.getAttribute("data-email"); if (email === state.selectedEmail) return; state.selectedEmail = email; state.editing = false; state.mails = null; state.mailsPage = 1; state.selectedMail = null; state.selectedMessage = null; document.getElementById("sidebar").classList.remove("open"); renderContactList(); renderHeader(); renderMailsList(); renderMailDetail(); loadContactMails(email).then(renderMailsList).catch(reportError); }); document.getElementById("contactHeader").addEventListener("click", function (e) { if (e.target.id === "refreshContactMailsBtn") { e.preventDefault(); loadContactMails(state.selectedEmail, { refresh: true }).then(renderMailsList).catch(reportError); return; } if (e.target.id === "mailContactBtn") { e.preventDefault(); sessionStorage.setItem("mailsharp_compose_prefill", JSON.stringify({ to: state.selectedEmail })); window.location.href = "Mail/Compose"; return; } if (e.target.id === "editContactBtn") { e.preventDefault(); state.editing = true; renderHeader(); return; } if (e.target.id === "cancelEditBtn") { e.preventDefault(); state.editing = false; renderHeader(); return; } if (e.target.id === "saveContactBtn") { e.preventDefault(); var newName = document.getElementById("editDisplayName").value.trim(); $.apiFetch("api/contacts/update", { method: "POST", body: { email: state.selectedEmail, displayName: newName } }) .then(function () { var contact = selectedContact(); if (contact) contact.displayName = newName || contact.email; state.editing = false; renderContactList(); renderHeader(); }) .catch(reportError); return; } }); document.getElementById("contactMailsBody").addEventListener("click", function (e) { var mailPageLink = e.target.closest("a[data-mail-page]"); if (mailPageLink) { e.preventDefault(); var newPage = parseInt(mailPageLink.getAttribute("data-mail-page"), 10) || 1; state.mailsPage = newPage; renderMailsList(); return; } var row = e.target.closest(".message-row[data-uid]"); if (row) openMail(row.getAttribute("data-folder"), parseInt(row.getAttribute("data-uid"), 10)); }); document.getElementById("contactMailDetailPane").addEventListener("click", function (e) { if (e.target.id === "closeMailDetailBtn") { e.preventDefault(); closeMailDetail(); return; } if (e.target.id === "allowImagesBtn") { e.preventDefault(); var sender = state.selectedMessage.senderEmail; $.apiFetch("api/mail/allow-images", { method: "POST", body: { sender: sender } }).then(function () { return openMailRefresh(); }).catch(reportError); return; } var attBtn = e.target.closest("[data-attachment]"); if (attBtn) downloadOrViewAttachment(attBtn); }); function openMailRefresh() { var mail = state.selectedMail; var params = new URLSearchParams({ folder: mail.folder }); return $.apiFetch("api/mail/messages/" + mail.uid + "?" + params.toString()).then(function (detail) { state.selectedMessage = detail; renderMailDetail(); }); } function downloadOrViewAttachment(btn) { var mail = state.selectedMail; var part = btn.getAttribute("data-part"); var fileName = btn.getAttribute("data-filename"); var mode = btn.getAttribute("data-attachment"); var params = new URLSearchParams({ folder: mail.folder }); fetch("api/mail/attachments/" + mail.uid + "/" + part + "?" + params.toString(), { credentials: "same-origin" }) .then(function (response) { if (!response.ok) throw new Error("HTTP " + response.status); return response.blob(); }) .then(function (blob) { var blobUrl = URL.createObjectURL(blob); if (mode === "view") { window.open(blobUrl, "_blank"); } else { var a = document.createElement("a"); a.href = blobUrl; a.download = fileName; document.body.appendChild(a); a.click(); document.body.removeChild(a); } setTimeout(function () { URL.revokeObjectURL(blobUrl); }, 60000); }) .catch(reportError); } bootstrap(); })();