Add global music player, invoicing/payment system, account subpages, mail account admin, and the qualityiron.vegas Jet 2.0 port
Jet interpreter (Tag.cpp, __call.cpp, __imap*.cpp/h, __smtpsend.cpp/h, __imapemptyfolder.cpp/h - new): assorted parser/tag fixes found across this work - a stray literal-tag-in-comment and backslash-quote parser corruption class, a dangling-pointer fix, a __call.cpp fd leak, IMAP folder-management tags, multi-account/per-host IMAP support, and a smtpsend Message-ID fix. barant.com site (jetc/barant-site/): - A site-wide persistent music player (header band, playlist/queue, stereo FFT EQ, session-persisted state) fed by new library/ ianslibrary/music song-list subpages. - /account split into info/phones/invoices subpages; a full invoicing and Square payment system (create/edit/copy/pay/email invoice); admin invoice management and mail-account management subpages. - /services split into overview/hosting/siptrunking/documents subpages, retiring the old standalone pages. - SIPPHONE.tag: a Jet 2.0 WebRTC softphone tag. - main.css/spa.js/email.js: the SPA loading indicator, the music player band styling, and assorted fixes accumulated alongside this work. qualityiron-site/: the qualityiron.vegas job/contractor/customer/ document management app, ported from its original Jet 1.4 codebase to Jet 2.0 as barant.coms APIServers second multi-tenant site. wcwc/wcwc.jet: the WCWC site Jet source (wcwc.jtc build output not included). Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
1 parent
905fbafa5a
commit
b8f7793773
406 files changed
+15803
-587
No files matched your search
@@ -1,6 +1,7 @@
|
||||
(function() {
|
||||
var content = document.getElementById('content');
|
||||
var form = document.getElementById('mainform');
|
||||
var loadingIndicator = document.getElementById('spa-loading-indicator');
|
||||
// Lives outside #content (a sibling in the persistent shell, next to
|
||||
// the menu bar/form) - a fragment swap never touches it on its own,
|
||||
// so a per-page side menu would otherwise stay frozen on whichever
|
||||
@@ -220,6 +221,12 @@
|
||||
function navigate(url, push) {
|
||||
var sep = url.indexOf('?') === -1 ? '?' : '&';
|
||||
content.classList.add('spa-fading');
|
||||
// Opacity transition alone (see the CSS) means a fetch that resolves
|
||||
// quickly never gets the indicator past a barely-visible opacity
|
||||
// before this removes the class again - exactly the "do not flash
|
||||
// this for a fast load" behavior wanted, with no separate delay
|
||||
// timer needed to achieve it.
|
||||
if (loadingIndicator) loadingIndicator.classList.add('spa-loading-visible');
|
||||
Promise.all([
|
||||
fetch(url + sep + '_fragment=1', { credentials: 'same-origin' }).then(function(r) { return r.text(); }),
|
||||
delay(180)
|
||||
@@ -233,6 +240,7 @@
|
||||
syncActiveTab(finalUrl.split('?')[0]);
|
||||
}
|
||||
content.classList.remove('spa-fading');
|
||||
if (loadingIndicator) loadingIndicator.classList.remove('spa-loading-visible');
|
||||
});
|
||||
}
|
||||
|
||||
@@ -254,6 +262,7 @@
|
||||
var subpage = fd.get('SUBPAGE') || '';
|
||||
var url = formPrefix + '/' + page + (subpage ? '/' + subpage : '');
|
||||
content.classList.add('spa-fading');
|
||||
if (loadingIndicator) loadingIndicator.classList.add('spa-loading-visible');
|
||||
Promise.all([
|
||||
fetch(url + '?_fragment=1', {
|
||||
method: 'POST',
|
||||
@@ -271,6 +280,7 @@
|
||||
syncActiveTab(finalUrl.split('?')[0]);
|
||||
}
|
||||
content.classList.remove('spa-fading');
|
||||
if (loadingIndicator) loadingIndicator.classList.remove('spa-loading-visible');
|
||||
});
|
||||
});
|
||||
}
|
||||
@@ -279,6 +289,24 @@
|
||||
navigate(window.location.pathname + window.location.search, false);
|
||||
});
|
||||
|
||||
// Instant visual feedback on a side-menu click - without this, the
|
||||
// active-item highlight only updated once applyResponse() swapped in
|
||||
// the new #_spa_panelmenu markup after the fetch finished, which read
|
||||
// as unresponsive (the click did nothing visible until the whole
|
||||
// subpage had already loaded). That server-rendered swap is still the
|
||||
// authoritative source of truth and will correct this on arrival (e.g.
|
||||
// if a click ends up redirected somewhere else entirely), so this is
|
||||
// purely an optimistic bridge, not a second source of truth.
|
||||
if (panelMenu) {
|
||||
panelMenu.addEventListener('click', function(e) {
|
||||
var a = e.target.closest('a');
|
||||
if (!a || !panelMenu.contains(a)) return;
|
||||
var current = panelMenu.querySelector('.submenuitem-active');
|
||||
if (current) current.classList.remove('submenuitem-active');
|
||||
a.classList.add('submenuitem-active');
|
||||
});
|
||||
}
|
||||
|
||||
// Drag-to-resize for the side menu (#panelmenu) against the main
|
||||
// content column - the resizer bar (#panelmenu-resizer) lives in the
|
||||
// persistent shell right alongside panelMenu itself (see its own
|
||||
|
||||
Reference in new issue
Block a user