mirror of
https://github.com/pewdiepie-archdaemon/odysseus.git
synced 2026-07-08 11:56:59 +00:00
Speed up email composer typing
This commit is contained in:
+3
-3
@@ -219,8 +219,8 @@
|
||||
}, { once: true });
|
||||
})();
|
||||
</script>
|
||||
<link rel="stylesheet" href="/static/style.css?v=20260630emailquote">
|
||||
<link rel="modulepreload" href="/static/app.js?v=20260630emailquote">
|
||||
<link rel="stylesheet" href="/static/style.css?v=20260630emailtype">
|
||||
<link rel="modulepreload" href="/static/app.js?v=20260630emailtype">
|
||||
<link rel="modulepreload" href="/static/js/chat.js">
|
||||
<link rel="modulepreload" href="/static/js/ui.js">
|
||||
<link rel="modulepreload" href="/static/js/sessions.js">
|
||||
@@ -2512,7 +2512,7 @@
|
||||
<script type="module" src="/static/js/settings.js"></script>
|
||||
<script type="module" src="/static/js/admin.js"></script>
|
||||
<script type="module" src="/static/js/assistant.js"></script>
|
||||
<script type="module" src="/static/app.js?v=20260630emailquote"></script> <!-- app.js must be LAST -->
|
||||
<script type="module" src="/static/app.js?v=20260630emailtype"></script> <!-- app.js must be LAST -->
|
||||
<script type="module" src="/static/js/init.js"></script>
|
||||
<script type="module" src="/static/js/a11y.js"></script>
|
||||
<script nonce="{{CSP_NONCE}}">if('serviceWorker' in navigator){navigator.serviceWorker.register('/static/sw.js').catch(()=>{});}</script>
|
||||
|
||||
+30
-5
@@ -36,6 +36,7 @@ import { bindMenuDismiss, dismissOrRemove } from './escMenuStack.js';
|
||||
let _emailStreamRenderedBody = '';
|
||||
let _emailStreamTargetBody = '';
|
||||
let _emailLocalDraftDebounce = null;
|
||||
let _emailRichbodySaveDebounce = null;
|
||||
const _EMAIL_LOCAL_DRAFT_PREFIX = 'odysseus.email.replyDraft.v1:';
|
||||
|
||||
// Diff mode state
|
||||
@@ -2353,7 +2354,7 @@ import { bindMenuDismiss, dismissOrRemove } from './escMenuStack.js';
|
||||
|
||||
function _persistEmailLocalDraftSoon() {
|
||||
clearTimeout(_emailLocalDraftDebounce);
|
||||
_emailLocalDraftDebounce = setTimeout(_persistEmailLocalDraftNow, 250);
|
||||
_emailLocalDraftDebounce = setTimeout(_persistEmailLocalDraftNow, 800);
|
||||
}
|
||||
|
||||
function _clearEmailLocalDraft(sourceUid, sourceFolder, inReplyTo) {
|
||||
@@ -2393,20 +2394,41 @@ import { bindMenuDismiss, dismissOrRemove } from './escMenuStack.js';
|
||||
const ta = document.getElementById('doc-editor-textarea');
|
||||
if (!ta) return;
|
||||
ta.value = rich.innerText;
|
||||
ta.dispatchEvent(new Event('input', { bubbles: true }));
|
||||
const doc = activeDocId && docs.get(activeDocId);
|
||||
if (doc && doc.language === 'email') {
|
||||
const fields = _parseEmailHeader(doc.content || '');
|
||||
doc.content = _buildEmailContent(
|
||||
document.getElementById('doc-email-to')?.value || fields.to || '',
|
||||
document.getElementById('doc-email-subject')?.value || fields.subject || '',
|
||||
document.getElementById('doc-email-in-reply-to')?.value || fields.inReplyTo || '',
|
||||
document.getElementById('doc-email-references')?.value || fields.references || '',
|
||||
rich.innerHTML,
|
||||
document.getElementById('doc-email-source-uid')?.value || fields.sourceUid || '',
|
||||
document.getElementById('doc-email-source-folder')?.value || fields.sourceFolder || '',
|
||||
document.getElementById('doc-email-cc')?.value || fields.cc || '',
|
||||
document.getElementById('doc-email-bcc')?.value || fields.bcc || '',
|
||||
);
|
||||
}
|
||||
}
|
||||
function _scheduleEmailRichbodySave() {
|
||||
_persistEmailLocalDraftSoon();
|
||||
clearTimeout(_emailRichbodySaveDebounce);
|
||||
_emailRichbodySaveDebounce = setTimeout(() => { saveDocument({ silent: true }); }, 2500);
|
||||
}
|
||||
function _wireEmailRichbody(rich) {
|
||||
if (rich._wired) { _syncEmailRichbody(rich); return; }
|
||||
rich._wired = true;
|
||||
rich.addEventListener('input', () => {
|
||||
_syncEmailRichbody(rich);
|
||||
_persistEmailLocalDraftSoon();
|
||||
_scheduleEmailRichbodySave();
|
||||
});
|
||||
// Highlight toolbar buttons (B / I / S, headings, lists) when the caret
|
||||
// sits inside formatted text. queryCommandState reflects the live
|
||||
// selection — we just translate that into .is-active classes the CSS
|
||||
// already understands.
|
||||
const syncActive = () => {
|
||||
let syncActiveFrame = 0;
|
||||
const syncActiveNow = () => {
|
||||
syncActiveFrame = 0;
|
||||
if (!rich.isConnected || rich.style.display === 'none') return;
|
||||
// Only sync when focus is inside the rich body — otherwise selection
|
||||
// outside it (e.g. clicking the toolbar itself) gives misleading state.
|
||||
@@ -2430,10 +2452,13 @@ import { bindMenuDismiss, dismissOrRemove } from './escMenuStack.js';
|
||||
if (lBtn) lBtn.classList.toggle('is-active', !!inList);
|
||||
} catch (_) {}
|
||||
};
|
||||
const syncActive = () => {
|
||||
if (syncActiveFrame) return;
|
||||
syncActiveFrame = requestAnimationFrame(syncActiveNow);
|
||||
};
|
||||
rich.addEventListener('keyup', syncActive);
|
||||
rich.addEventListener('mouseup', syncActive);
|
||||
rich.addEventListener('focus', syncActive);
|
||||
rich.addEventListener('input', syncActive);
|
||||
// selectionchange fires on the document; filter to selections inside rich.
|
||||
document.addEventListener('selectionchange', () => {
|
||||
const sel = window.getSelection();
|
||||
|
||||
+1
-1
@@ -7,7 +7,7 @@
|
||||
// - Other static assets (images/fonts/libs): cache-first with bg refresh.
|
||||
// - API / non-GET: never cached.
|
||||
// Bump CACHE_NAME whenever the precache list or SW logic changes.
|
||||
const CACHE_NAME = 'odysseus-v331';
|
||||
const CACHE_NAME = 'odysseus-v332';
|
||||
|
||||
// Core shell precached on install so repeat opens are instant without any
|
||||
// network wait. Keep this list in sync with the <script type="module"> tags
|
||||
|
||||
Reference in New Issue
Block a user