From 6127e431133b076d528fdb12de860739b6790ec3 Mon Sep 17 00:00:00 2001 From: pewdiepie-archdaemon Date: Tue, 30 Jun 2026 12:48:47 +0000 Subject: [PATCH] Preserve HTML email quote history --- static/index.html | 6 +++--- static/js/document.js | 38 ++++++++++++++++++++++++++++++++++++++ static/sw.js | 2 +- 3 files changed, 42 insertions(+), 4 deletions(-) diff --git a/static/index.html b/static/index.html index 34195ca38..c175558e9 100644 --- a/static/index.html +++ b/static/index.html @@ -219,8 +219,8 @@ }, { once: true }); })(); - - + + @@ -2512,7 +2512,7 @@ - + diff --git a/static/js/document.js b/static/js/document.js index c4c97e841..65599bc71 100644 --- a/static/js/document.js +++ b/static/js/document.js @@ -2588,9 +2588,47 @@ import { bindMenuDismiss, dismissOrRemove } from './escMenuStack.js'; return -1; } + function _emailQuoteStartOffset(text) { + const original = String(text || ''); + if (!original) return -1; + const boundary = String.raw`(?:^|\n||<\/(?:p|div|blockquote|li|tr|h[1-6])>)`; + const patterns = [ + new RegExp(`${boundary}\\s*(?:[-_=–—\\s]| ){3,}(?:previous|original|forwarded)\\s+(?:message|email|mail)(?:[-_=–—\\s]| ){3,}`, 'i'), + new RegExp(`${boundary}\\s*On\\s+.{1,700}?\\s+wrote:\\s*`, 'i'), + new RegExp(`${boundary}\\s*-{2,}\\s*Original Message\\s*-{2,}`, 'i'), + ]; + let best = -1; + for (const re of patterns) { + const m = re.exec(original); + if (!m) continue; + let idx = m.index; + const prefix = m[0].match(/^(?:\n||<\/(?:p|div|blockquote|li|tr|h[1-6])>)/i); + if (prefix) idx += prefix[0].length; + if (best < 0 || idx < best) best = idx; + } + const fromRe = new RegExp(`${boundary}\\s*From:\\s*\\S`, 'i'); + const fromMatch = fromRe.exec(original); + if (fromMatch) { + let idx = fromMatch.index; + const prefix = fromMatch[0].match(/^(?:\n||<\/(?:p|div|blockquote|li|tr|h[1-6])>)/i); + if (prefix) idx += prefix[0].length; + const nearby = original.slice(idx, idx + 1200); + if (/(?:^|\n||<\/(?:p|div|blockquote|li|tr|h[1-6])>)\s*(?:To|Subject):\s*/i.test(nearby)) { + if (best < 0 || idx < best) best = idx; + } + } + return best; + } + function _splitEmailReplyQuote(text) { const original = String(text || ''); if (!original) return { body: '', quote: '', stripped: false }; + const htmlQuoteOffset = _emailQuoteStartOffset(original); + if (htmlQuoteOffset >= 0) { + const body = original.slice(0, htmlQuoteOffset).trim(); + const quote = original.slice(htmlQuoteOffset).trim(); + return { body, quote, stripped: true }; + } const lines = original.split('\n'); const quoteIdx = _emailQuoteStartIndex(lines); if (quoteIdx < 0) return { body: original.trim(), quote: '', stripped: false }; diff --git a/static/sw.js b/static/sw.js index 3df123bce..18beb4456 100644 --- a/static/sw.js +++ b/static/sw.js @@ -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-v334'; +const CACHE_NAME = 'odysseus-v335'; // Core shell precached on install so repeat opens are instant without any // network wait. Keep this list in sync with the