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

97 lines
3.5 KiB
JavaScript

(function() {
var dropzone = document.getElementById('documents-dropzone');
var fileInput = document.getElementById('documents-file-input');
var listBody = document.getElementById('documents-list-body');
if (!dropzone || !listBody)
return;
function escapeHtml(s) {
var div = document.createElement('div');
div.textContent = s == null ? '' : String(s);
return div.innerHTML;
}
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 loadList() {
post('/documents/api/list', {}).then(function(res) {
if (!res.ok || !res.documents.length) {
listBody.innerHTML = '<div id="documents-empty">No documents yet - upload your first one above.</div>';
return;
}
var html = '<table id="documents-list"><tr><th>Name</th><th>Uploaded</th><th></th><th></th></tr>';
for (var i = 0; i < res.documents.length; i++) {
var doc = res.documents[i];
html += '<tr>' +
'<td>' + escapeHtml(doc.name) + '</td>' +
'<td>' + escapeHtml(doc.created) + '</td>' +
'<td><span class="documents-action" data-action="download" data-id="' + doc.id + '" data-name="' + escapeHtml(doc.name) + '">Download</span></td>' +
'<td><span class="documents-action" data-action="delete" data-id="' + doc.id + '">Delete</span></td>' +
'</tr>';
}
html += '</table>';
listBody.innerHTML = html;
var actions = listBody.querySelectorAll('.documents-action');
for (var j = 0; j < actions.length; j++) {
actions[j].addEventListener('click', function() {
var id = this.getAttribute('data-id');
if (this.getAttribute('data-action') === 'download') {
window.fileManagerDownload && window.fileManagerDownload(id, this.getAttribute('data-name'));
} else {
post('/documents/api/delete', { id: id }).then(function(res) {
if (res.ok)
loadList();
});
}
});
}
}).catch(function() {
listBody.innerHTML = '<div id="documents-empty">Could not load your documents.</div>';
});
}
function uploadFiles(files) {
if (!files || !files.length)
return;
if (window.fileManagerUpload)
window.fileManagerUpload(files);
}
dropzone.addEventListener('click', function() {
fileInput.click();
});
fileInput.addEventListener('change', function() {
uploadFiles(fileInput.files);
fileInput.value = '';
});
dropzone.addEventListener('dragover', function(e) {
e.preventDefault();
dropzone.classList.add('documents-dropzone-active');
});
dropzone.addEventListener('dragleave', function() {
dropzone.classList.remove('documents-dropzone-active');
});
dropzone.addEventListener('drop', function(e) {
e.preventDefault();
dropzone.classList.remove('documents-dropzone-active');
uploadFiles(e.dataTransfer.files);
});
// The site-wide file manager (documents.js, loaded once via
// mainpagetemplate.jet) dispatches this after a successful upload -
// listening here (rather than only refreshing right after our own
// uploadFiles() calls) also picks up uploads that were still running
// when this page was navigated to via spa.js.
document.addEventListener('documents:changed', loadList);
loadList();
})();