fix docs toc fallback and remove redundant iifes
This commit is contained in:
parent
e84f19b5cb
commit
0503a25d0b
10 changed files with 61 additions and 35 deletions
|
|
@ -1139,6 +1139,8 @@ textarea.full-input{resize:vertical;}
|
||||||
.docs-reader-body th{background:var(--g50);font-weight:600;}
|
.docs-reader-body th{background:var(--g50);font-weight:600;}
|
||||||
.docs-reader-body a{color:var(--blue);text-decoration:none;}
|
.docs-reader-body a{color:var(--blue);text-decoration:none;}
|
||||||
.docs-reader-body a:hover{text-decoration:underline;}
|
.docs-reader-body a:hover{text-decoration:underline;}
|
||||||
|
.docs-reader-body .docs-anchor-link{color:var(--blue);cursor:pointer;text-decoration:none;}
|
||||||
|
.docs-reader-body .docs-anchor-link:hover{text-decoration:underline;}
|
||||||
.docs-reader-body hr{border:0;border-top:1px solid var(--g200);margin:1.6em 0;}
|
.docs-reader-body hr{border:0;border-top:1px solid var(--g200);margin:1.6em 0;}
|
||||||
|
|
||||||
@media (max-width:900px){
|
@media (max-width:900px){
|
||||||
|
|
|
||||||
|
|
@ -132,6 +132,26 @@
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function prepareDocLinks(body) {
|
||||||
|
if (!body) return;
|
||||||
|
body.querySelectorAll('a[href]').forEach(function (link) {
|
||||||
|
var href = link.getAttribute('href') || '';
|
||||||
|
if (href.charAt(0) !== '#' && link.hash) {
|
||||||
|
try {
|
||||||
|
var u = new URL(link.href, window.location.href);
|
||||||
|
if (u.origin !== window.location.origin || u.pathname !== window.location.pathname) return;
|
||||||
|
href = u.hash;
|
||||||
|
} catch (_) { return; }
|
||||||
|
}
|
||||||
|
if (!href || href.charAt(0) !== '#') return;
|
||||||
|
link.dataset.docHash = href;
|
||||||
|
link.removeAttribute('href');
|
||||||
|
link.setAttribute('role', 'button');
|
||||||
|
link.setAttribute('tabindex', '0');
|
||||||
|
link.classList.add('docs-anchor-link');
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
function scrollReaderToHash(hash) {
|
function scrollReaderToHash(hash) {
|
||||||
var body = $('docs-reader-body');
|
var body = $('docs-reader-body');
|
||||||
var reader = $('docs-reader');
|
var reader = $('docs-reader');
|
||||||
|
|
@ -152,25 +172,24 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
function handleDocAnchorClick(e) {
|
function handleDocAnchorClick(e) {
|
||||||
var link = e.target.closest('a[href]');
|
var link = e.target.closest('[data-doc-hash]');
|
||||||
var body = $('docs-reader-body');
|
var body = $('docs-reader-body');
|
||||||
if (!link || !body || !body.contains(link)) return;
|
if (!link || !body || !body.contains(link)) return;
|
||||||
var href = link.getAttribute('href') || '';
|
var href = link.dataset.docHash || '';
|
||||||
if (href.charAt(0) !== '#' && link.hash) {
|
|
||||||
try {
|
|
||||||
var u = new URL(link.href, window.location.href);
|
|
||||||
if (u.origin !== window.location.origin || u.pathname !== window.location.pathname) return;
|
|
||||||
href = u.hash;
|
|
||||||
} catch (_) { return; }
|
|
||||||
}
|
|
||||||
if (!href || href.charAt(0) !== '#') return;
|
if (!href || href.charAt(0) !== '#') return;
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
requestAnimationFrame(function () {
|
requestAnimationFrame(function () {
|
||||||
scrollReaderToHash(href);
|
if (scrollReaderToHash(href)) {
|
||||||
try { history.replaceState(null, '', href); } catch (_) { window.location.hash = href; }
|
try { history.replaceState(null, '', href); } catch (_) {}
|
||||||
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function handleDocAnchorKeydown(e) {
|
||||||
|
if (e.key !== 'Enter' && e.key !== ' ') return;
|
||||||
|
handleDocAnchorClick(e);
|
||||||
|
}
|
||||||
|
|
||||||
function loadTree() {
|
function loadTree() {
|
||||||
if (_treeLoaded) return;
|
if (_treeLoaded) return;
|
||||||
fetch('/api/admin/docs/tree', { headers: getAuthHeaders() })
|
fetch('/api/admin/docs/tree', { headers: getAuthHeaders() })
|
||||||
|
|
@ -217,6 +236,7 @@
|
||||||
}
|
}
|
||||||
body.innerHTML = data.html || '';
|
body.innerHTML = data.html || '';
|
||||||
prepareDocAnchors(body);
|
prepareDocAnchors(body);
|
||||||
|
prepareDocLinks(body);
|
||||||
if (meta) {
|
if (meta) {
|
||||||
meta.textContent = relPath + ' • ' + (data.bytes != null ? (data.bytes + ' bytes') : '');
|
meta.textContent = relPath + ' • ' + (data.bytes != null ? (data.bytes + ' bytes') : '');
|
||||||
}
|
}
|
||||||
|
|
@ -277,6 +297,7 @@
|
||||||
if (body && !body.dataset.anchorsWired) {
|
if (body && !body.dataset.anchorsWired) {
|
||||||
body.dataset.anchorsWired = '1';
|
body.dataset.anchorsWired = '1';
|
||||||
body.addEventListener('click', handleDocAnchorClick);
|
body.addEventListener('click', handleDocAnchorClick);
|
||||||
|
body.addEventListener('keydown', handleDocAnchorKeydown);
|
||||||
}
|
}
|
||||||
|
|
||||||
var filter = $('docs-filter');
|
var filter = $('docs-filter');
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
// E2E harness bootstrap — external file because the app's CSP blocks inline scripts.
|
// E2E harness bootstrap — external file because the app's CSP blocks inline scripts.
|
||||||
// Runs after calc-math.js + calculators.js (all three have `defer`, so execution
|
// Runs after calc-math.js + calculators.js (all three have `defer`, so execution
|
||||||
// is in document order once parsing completes).
|
// is in document order once parsing completes).
|
||||||
(async function bootstrap() {
|
async function bootstrapE2eHarness() {
|
||||||
try {
|
try {
|
||||||
// Cache-bust so stale playwright browser caches never serve an outdated
|
// Cache-bust so stale playwright browser caches never serve an outdated
|
||||||
// component HTML between reorg deploys.
|
// component HTML between reorg deploys.
|
||||||
|
|
@ -20,4 +20,5 @@
|
||||||
console.error('[e2e-harness] bootstrap failed:', e);
|
console.error('[e2e-harness] bootstrap failed:', e);
|
||||||
window.__harnessError = String(e);
|
window.__harnessError = String(e);
|
||||||
}
|
}
|
||||||
})();
|
}
|
||||||
|
bootstrapE2eHarness();
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,7 @@
|
||||||
// ENCOUNTERS.JS — Save/resume/pause encounter progress
|
// ENCOUNTERS.JS — Save/resume/pause encounter progress
|
||||||
// ============================================================
|
// ============================================================
|
||||||
|
|
||||||
(function() {
|
function setupEncountersModule() {
|
||||||
|
|
||||||
// ── Pause/Resume for recording buttons ─────────────────────────────────
|
// ── Pause/Resume for recording buttons ─────────────────────────────────
|
||||||
// Each recording module (encounter, dictation) gets a pause button wired here.
|
// Each recording module (encounter, dictation) gets a pause button wired here.
|
||||||
|
|
@ -94,14 +94,15 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
// Restore saved encounter IDs from sessionStorage (survive page refresh, cleared on tab close)
|
// Restore saved encounter IDs from sessionStorage (survive page refresh, cleared on tab close)
|
||||||
(function() {
|
function restoreSavedEncounterIds() {
|
||||||
['encounter','dictation','ed','hospital','chart','wellvisit','sickvisit','soap'].forEach(function(t) {
|
['encounter','dictation','ed','hospital','chart','wellvisit','sickvisit','soap'].forEach(function(t) {
|
||||||
try {
|
try {
|
||||||
var id = sessionStorage.getItem('_savedEncId_' + t);
|
var id = sessionStorage.getItem('_savedEncId_' + t);
|
||||||
if (id) window['_savedEncId_' + t] = id;
|
if (id) window['_savedEncId_' + t] = id;
|
||||||
} catch(e) {}
|
} catch(e) {}
|
||||||
});
|
});
|
||||||
})();
|
}
|
||||||
|
restoreSavedEncounterIds();
|
||||||
|
|
||||||
// Register a load handler for a specific tab type
|
// Register a load handler for a specific tab type
|
||||||
window.registerEncounterLoadHandler = function(type, fn) {
|
window.registerEncounterLoadHandler = function(type, fn) {
|
||||||
|
|
@ -513,4 +514,5 @@
|
||||||
|
|
||||||
console.log('✅ Encounters module loaded');
|
console.log('✅ Encounters module loaded');
|
||||||
|
|
||||||
})();
|
}
|
||||||
|
setupEncountersModule();
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,7 @@
|
||||||
(function() {
|
var _liveEncounterInited = false;
|
||||||
var _inited = false;
|
|
||||||
document.addEventListener('tabChanged', function(e) {
|
document.addEventListener('tabChanged', function(e) {
|
||||||
if (e.detail.tab !== 'encounter' || _inited) return;
|
if (e.detail.tab !== 'encounter' || _liveEncounterInited) return;
|
||||||
_inited = true;
|
_liveEncounterInited = true;
|
||||||
var recordBtn = document.getElementById('enc-record-btn');
|
var recordBtn = document.getElementById('enc-record-btn');
|
||||||
var pauseBtn = document.getElementById('enc-pause-btn');
|
var pauseBtn = document.getElementById('enc-pause-btn');
|
||||||
var indicator = document.getElementById('enc-recording-indicator');
|
var indicator = document.getElementById('enc-recording-indicator');
|
||||||
|
|
@ -239,4 +238,3 @@
|
||||||
|
|
||||||
console.log('✅ Encounter module loaded');
|
console.log('✅ Encounter module loaded');
|
||||||
});
|
});
|
||||||
})();
|
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,7 @@
|
||||||
// SHADESS.JS — SSHADESS psychosocial screening form + well visit note
|
// SHADESS.JS — SSHADESS psychosocial screening form + well visit note
|
||||||
// ============================================================
|
// ============================================================
|
||||||
|
|
||||||
(function() {
|
function setupShadessModule() {
|
||||||
|
|
||||||
// ── SSHADESS domain definitions ──────────────────────────────────────────
|
// ── SSHADESS domain definitions ──────────────────────────────────────────
|
||||||
// Each domain has key questions (most important shown first) + comment field
|
// Each domain has key questions (most important shown first) + comment field
|
||||||
|
|
@ -1059,4 +1059,5 @@
|
||||||
|
|
||||||
console.log('SHADESS module loaded');
|
console.log('SHADESS module loaded');
|
||||||
|
|
||||||
})();
|
}
|
||||||
|
setupShadessModule();
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,7 @@
|
||||||
(function() {
|
var _voiceDictationInited = false;
|
||||||
var _inited = false;
|
|
||||||
document.addEventListener('tabChanged', function(e) {
|
document.addEventListener('tabChanged', function(e) {
|
||||||
if (e.detail.tab !== 'dictation' || _inited) return;
|
if (e.detail.tab !== 'dictation' || _voiceDictationInited) return;
|
||||||
_inited = true;
|
_voiceDictationInited = true;
|
||||||
var recordBtn = document.getElementById('dict-record-btn');
|
var recordBtn = document.getElementById('dict-record-btn');
|
||||||
var pauseBtn = document.getElementById('dict-pause-btn');
|
var pauseBtn = document.getElementById('dict-pause-btn');
|
||||||
var indicator = document.getElementById('dict-recording-indicator');
|
var indicator = document.getElementById('dict-recording-indicator');
|
||||||
|
|
@ -210,4 +209,3 @@
|
||||||
|
|
||||||
console.log('✅ Dictation module loaded');
|
console.log('✅ Dictation module loaded');
|
||||||
});
|
});
|
||||||
})();
|
|
||||||
|
|
|
||||||
|
|
@ -436,7 +436,7 @@ async function initDatabase() {
|
||||||
|
|
||||||
// Boot sequence: inline init (idempotent baseline) → node-pg-migrate for
|
// Boot sequence: inline init (idempotent baseline) → node-pg-migrate for
|
||||||
// incremental changes. Migrations live in /app/migrations/.
|
// incremental changes. Migrations live in /app/migrations/.
|
||||||
(async function() {
|
async function bootstrapDatabase() {
|
||||||
await initDatabase();
|
await initDatabase();
|
||||||
try {
|
try {
|
||||||
var { runMigrations } = require('./migrate');
|
var { runMigrations } = require('./migrate');
|
||||||
|
|
@ -447,7 +447,8 @@ async function initDatabase() {
|
||||||
// broken DB separately.
|
// broken DB separately.
|
||||||
console.error('[DB] Migration runner failed:', e.message);
|
console.error('[DB] Migration runner failed:', e.message);
|
||||||
}
|
}
|
||||||
})();
|
}
|
||||||
|
bootstrapDatabase();
|
||||||
|
|
||||||
// Clean up expired saved encounters and audio backups
|
// Clean up expired saved encounters and audio backups
|
||||||
async function cleanupExpired() {
|
async function cleanupExpired() {
|
||||||
|
|
|
||||||
|
|
@ -568,7 +568,7 @@ router.post('/forgot-password', async (req, res) => {
|
||||||
|
|
||||||
// Fire-and-forget: DB lookup + token + email happen after the response
|
// Fire-and-forget: DB lookup + token + email happen after the response
|
||||||
// is sent, so their latency cannot be measured by the caller.
|
// is sent, so their latency cannot be measured by the caller.
|
||||||
(async function () {
|
async function sendResetEmailInBackground() {
|
||||||
try {
|
try {
|
||||||
var user = await db.get('SELECT id FROM users WHERE email = ?', [email]);
|
var user = await db.get('SELECT id FROM users WHERE email = ?', [email]);
|
||||||
if (!user) return;
|
if (!user) return;
|
||||||
|
|
@ -586,7 +586,8 @@ router.post('/forgot-password', async (req, res) => {
|
||||||
} catch (bgErr) {
|
} catch (bgErr) {
|
||||||
console.error('[Auth] forgot-password background send failed:', bgErr.message);
|
console.error('[Auth] forgot-password background send failed:', bgErr.message);
|
||||||
}
|
}
|
||||||
})();
|
}
|
||||||
|
sendResetEmailInBackground();
|
||||||
} catch (err) { console.error('[Auth] Forgot password error:', err.message); res.status(500).json({ error: 'Password reset request failed' }); }
|
} catch (err) { console.error('[Auth] Forgot password error:', err.message); res.status(500).json({ error: 'Password reset request failed' }); }
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -350,7 +350,7 @@ router.post('/embeddings/generate', async function(req, res) {
|
||||||
console.log('[Embeddings] Starting batch generation for ' + content.length + ' items...');
|
console.log('[Embeddings] Starting batch generation for ' + content.length + ' items...');
|
||||||
|
|
||||||
// Don't await — run in background
|
// Don't await — run in background
|
||||||
(async function() {
|
async function generateEmbeddingsInBackground() {
|
||||||
for (var i = 0; i < content.length; i++) {
|
for (var i = 0; i < content.length; i++) {
|
||||||
var item = content[i];
|
var item = content[i];
|
||||||
try {
|
try {
|
||||||
|
|
@ -384,7 +384,8 @@ router.post('/embeddings/generate', async function(req, res) {
|
||||||
console.error('[Embeddings] Index creation failed:', e.message);
|
console.error('[Embeddings] Index creation failed:', e.message);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
})();
|
}
|
||||||
|
generateEmbeddingsInBackground();
|
||||||
|
|
||||||
res.json({
|
res.json({
|
||||||
success: true,
|
success: true,
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue