mirror of
https://github.com/pewdiepie-archdaemon/odysseus.git
synced 2026-07-12 12:37:32 +00:00
Merge remote-tracking branch 'origin/dev'
# Conflicts: # routes/contacts_routes.py
This commit is contained in:
+13
-6
@@ -2433,20 +2433,27 @@ import { bindMenuDismiss, dismissOrRemove } from './escMenuStack.js';
|
||||
}
|
||||
|
||||
// ── WYSIWYG email body helpers ──
|
||||
function _emailPlainTextToHtml(text) {
|
||||
const d = document.createElement('div');
|
||||
d.textContent = text == null ? '' : String(text);
|
||||
return d.innerHTML.replace(/\n/g, '<br>');
|
||||
}
|
||||
|
||||
function _emailBodyToHtml(text) {
|
||||
const t = (text || '').trim();
|
||||
if (!t) return '';
|
||||
// If it already contains a formatting/structural HTML tag, it's a saved
|
||||
// WYSIWYG body — use it verbatim. (Checking a leading '<' isn't enough: a
|
||||
// WYSIWYG body — sanitize it before rendering. (Checking a leading '<' isn't enough: a
|
||||
// rich body often starts with plain text, e.g. "Hi <b>there</b>".)
|
||||
if (/<\/?(b|i|u|s|strong|em|del|strike|a|p|div|br|ul|ol|li|h[1-3]|blockquote|span|code|pre)\b[^>]*>/i.test(t)) return t;
|
||||
if (/<\/?(b|i|u|s|strong|em|del|strike|a|p|div|br|ul|ol|li|h[1-3]|blockquote|span|code|pre)\b[^>]*>/i.test(t)) {
|
||||
return markdownModule.sanitizeAllowedHtml
|
||||
? markdownModule.sanitizeAllowedHtml(t)
|
||||
: _emailPlainTextToHtml(t);
|
||||
}
|
||||
// Email body: keep author-typed `:shortcode:` text literal. Issue #345
|
||||
// (shortcode → emoji) is scoped to chat; do not rewrite colons in mail.
|
||||
try { return markdownModule.mdToHtml(text, { shortcodes: false }); }
|
||||
catch (_) {
|
||||
const d = document.createElement('div'); d.textContent = text;
|
||||
return d.innerHTML.replace(/\n/g, '<br>');
|
||||
}
|
||||
catch (_) { return _emailPlainTextToHtml(text); }
|
||||
}
|
||||
// Mirror the rich body's plain text into the hidden textarea so the existing
|
||||
// send / draft / change-detection plumbing (which reads the textarea) stays
|
||||
|
||||
@@ -133,7 +133,7 @@ function _cleanAllowedHtmlOnce(htmlString) {
|
||||
return tpl.innerHTML;
|
||||
}
|
||||
|
||||
function sanitizeAllowedHtml(html) {
|
||||
export function sanitizeAllowedHtml(html) {
|
||||
const raw = String(html == null ? '' : html);
|
||||
// Non-browser context (e.g. a future SSR/Node import): fail closed by
|
||||
// escaping rather than trusting the markup.
|
||||
@@ -835,6 +835,7 @@ export function renderMermaid(container) {
|
||||
const markdownModule = {
|
||||
escapeHtml,
|
||||
mdToHtml,
|
||||
sanitizeAllowedHtml,
|
||||
squashOutsideCode,
|
||||
renderContent,
|
||||
processWithThinking,
|
||||
|
||||
@@ -542,6 +542,9 @@ async function initDefaultChat() {
|
||||
renderFallbacks();
|
||||
} catch (e) { console.warn('Failed to load default chat settings', e); }
|
||||
|
||||
epSel.addEventListener('change', function() { refreshModels(''); saveDefault(); });
|
||||
modelSel.addEventListener('change', saveDefault);
|
||||
|
||||
async function saveDefault() {
|
||||
try {
|
||||
var clean = _fallbacks.filter(function(f) { return f.endpoint_id && f.model; });
|
||||
@@ -558,8 +561,6 @@ async function initDefaultChat() {
|
||||
} catch (e) { msg.textContent = 'Failed to save'; msg.style.color = 'var(--red)'; }
|
||||
}
|
||||
|
||||
epSel.addEventListener('change', function() { refreshModels(''); saveDefault(); });
|
||||
modelSel.addEventListener('change', saveDefault);
|
||||
if (addFbBtn) addFbBtn.addEventListener('click', function() {
|
||||
var first = enabledEndpoints()[0];
|
||||
_fallbacks.push({ endpoint_id: first ? first.id : '', model: '' });
|
||||
|
||||
@@ -40438,3 +40438,13 @@ body.theme-frosted .modal {
|
||||
.log-line-default {
|
||||
color: var(--fg, #9cdef2);
|
||||
}
|
||||
|
||||
/* The model-comparison grid hard-codes 2-4 equal columns with no phone
|
||||
breakpoint that stacks them, so at 390px two models render ~178px columns and
|
||||
four render ~88px columns. Each column is a full scrolling chat (code blocks,
|
||||
tool output, vote footer), so the text is unreadably over-wrapped and clipped.
|
||||
On phones, stack the panes into a single scrollable column instead. */
|
||||
@media (max-width: 768px) {
|
||||
.compare-grid[data-cols] { grid-template-columns: 1fr !important; overflow-y: auto; }
|
||||
.compare-pane { min-height: 60dvh; }
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user