Files
Brad Arant c1491b044b Add IMAP webmail tag, admin/opensource subpage tiers, store/cart, htmleditor, uploads
New __imap*/__smtpsend/__eval Jet tags give templates real IMAP
(list/message/flag/delete/move/search/folders/accounts) and SMTP-send
capability, backing the new /email webmail client (email.jet/
email.menu, assets/images/email.js + newemail.js) and its
mainpagetemplate.jet-based page shell. Most of this tag family's
source was already being built into the live site (Tag.cpp already
registered __imap/__imaplist/__imapmessage/__imapflag/__imapdelete/
__eval) but had never actually been committed; this also registers
and commits the remaining five (__imapmove/__imapfolders/
__imapsearch/__smtpsend/__imapaccounts).

admin.page/admin.menu gain a real subpage tier (admin-email,
admin-newemail, admin-invoices, admin-products, admin-users) replacing
several previously top-level pages, mirrored by a similar
opensource.page subpage tier (opensource-overview/asm1802/barantmail/
jet/serverframework/synthmax) - old top-level pages retired via git
rename (asm1802.page, jet.page, serverframework.page,
admin_invoices.page); barantmail.page is dropped outright, folded into
opensource-barantmail.subpage.

New storefront (store.page, store-createstore.subpage,
barantstore.page) and cart flow (cart.jet, updatecartqty.proc,
removecartitem.proc, editproduct.page/selectproduct.proc/
update_product.proc for inventory maintenance against the barant
database).

New document upload/download manager (documents.jet, documents_api.jet,
documents_upload.proc, documents_delete.proc,
assets/images/documents.js + documents-page.js) with a persistent
floating panel, and a rich-text page editor (htmleditor.jet/.page,
createhtmleditor.proc, savehtmleditor.proc, assets/images/htmleditor.js
+ its icon/logo assets).

SESSIONCTL.tag: login now redirects back to the originally-requested
page instead of always landing on /account ($[start:0] vs $[start]
variable-name mismatch).

main.css/menu.bar/invoices.menu/jet_overview.section/login.menu:
styling and navigation updates for the above; new site assets (fonts,
images, audio) referenced by them.

jetc/build-assets.sh, list_jet_files.sh, lowercase_jet.py,
strip_fragments.py: small dev tooling used while building the above.
2026-09-06 04:14:00 +00:00

77 lines
2.3 KiB
JavaScript

(function() {
var form = document.getElementById('newemail-form');
if (!form)
return;
function post(path, params) {
return fetch(path, {
method: 'POST',
credentials: 'same-origin',
headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
body: new URLSearchParams(params || {}).toString()
}).then(function(r) { return r.json(); });
}
function navigateTo(url) {
var a = document.createElement('a');
a.href = url;
document.body.appendChild(a);
a.click();
document.body.removeChild(a);
}
var body = document.getElementById('newemail-body');
var toolbar = document.getElementById('newemail-toolbar');
toolbar.addEventListener('click', function(e) {
var btn = e.target.closest('button');
if (!btn)
return;
body.focus();
var cmd = btn.getAttribute('data-cmd');
if (cmd === 'createLink') {
var url = window.prompt('Link URL:');
if (url)
document.execCommand('createLink', false, url);
} else {
document.execCommand(cmd, false, null);
}
});
var errorDiv = document.getElementById('newemail-error');
var sendBtn = document.getElementById('newemail-send-btn');
var cancelBtn = document.getElementById('newemail-cancel-btn');
cancelBtn.addEventListener('click', function() {
navigateTo('/admin/email');
});
sendBtn.addEventListener('click', function() {
var to = document.getElementById('newemail-to').value.trim();
var subject = document.getElementById('newemail-subject').value.trim();
var html = body.innerHTML.trim();
errorDiv.textContent = '';
if (!to) {
errorDiv.textContent = 'A recipient address is required.';
return;
}
if (!html) {
errorDiv.textContent = 'The message body is empty.';
return;
}
sendBtn.classList.add('newemail-sending');
post('/email/send', { to: to, subject: subject, body: html })
.then(function(res) {
sendBtn.classList.remove('newemail-sending');
if (!res.ok) {
errorDiv.textContent = res.error || 'Could not send the message.';
return;
}
navigateTo('/admin/email');
})
.catch(function() {
sendBtn.classList.remove('newemail-sending');
errorDiv.textContent = 'Could not send the message.';
});
});
})();