(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 = '' + list.map(function (c)
{
var selected = c.email === state.selectedEmail ? "selected" : "";
return (
'' +
'' + $.esc(c.displayName) + '
' +
'
' + $.esc(c.email) + "
" +
" "
);
}).join("") + " ";
}
document.getElementById("contactListBody").innerHTML = html;
}
function renderHeader()
{
var t = state.strings;
var header = document.getElementById("contactHeader");
var contact = selectedContact();
if (!contact)
{
header.innerHTML = '";
return;
}
var infoHtml = state.editing
? (
'
'
)
: (
'"
);
var actionsHtml = state.editing
? (
'' + $.esc(t.contacts_save) + " " +
'' + $.esc(t.contacts_cancel) + " "
)
: (
'' + $.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 =
'' + pageMails.map(renderMailRow).join("") + " " +
'";
}
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) + "
" +
'" +
" "
);
}
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) + " " +
'' +
$.esc($.formatTemplate(t.detail_always_show_for, m.senderEmail)) +
" " +
"
";
}
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) " +
'' + $.esc(t.detail_view) + " " +
'' + $.esc(t.detail_download) + " " +
"
"
);
}).join("") +
"
";
}
var bodyHtml = (m.htmlBody && m.htmlBody.trim() !== "")
? '
'
: '' + $.esc(m.textBody) + " ";
pane.innerHTML =
'";
}
// ---------- 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();
})();