feat(chat): quote with the '>' line prefix instead of guillemets

The Quote button produced `@[user] »text« ` — a shape mc-webui invented back
when it could not send newlines, and one that other MeshCore clients neither
write nor understand. It now writes the quote on its own line behind a '>'
and leaves the cursor underneath it, matching the plain-text convention some
users already type by hand.

processQuotes() styles both syntaxes, so messages sent by older builds keep
their formatting. The '>' match is anchored to a line start or a leading
@[mention] badge and looks for the escaped '>', so neither "5 > 3" in
prose nor the brackets of generated tags can trigger it.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
MarekWo
2026-07-27 11:58:53 +02:00
parent 993013e0f5
commit 17398e8e41
4 changed files with 49 additions and 9 deletions
+6 -2
View File
@@ -1531,11 +1531,15 @@ function truncateToBytes(text, maxBytes) {
}
/**
* Insert a quote into the message input.
* Insert a quote into the message input, leaving the cursor on a fresh line
* for the reply. Uses the `>` line prefix rather than the guillemets of older
* versions, so the quote also reads as one in clients that don't style it.
*/
function insertQuote(username, quotedText) {
const input = document.getElementById('messageInput');
input.value = `@[${username}] »${quotedText}« `;
// One '>' per line — a quoted multi-line message stays fully quoted.
const quoted = quotedText.split('\n').map(line => `>${line}`).join('\n');
input.value = `@[${username}] ${quoted}\n`;
updateCharCounter();
input.focus();
}
+20 -6
View File
@@ -134,18 +134,32 @@ function processChannelLinks(text) {
}
/**
* Convert »quoted text« to styled quote blocks
* Convert quoted text to styled quote blocks. Two syntaxes are recognised:
* `>quoted line` (current, also what other MeshCore clients use) and
* `»quoted text«` (what mc-webui produced before 2.2.0 — still rendered so
* older messages keep their styling).
* @param {string} text - HTML-escaped text
* @returns {string} - Text with styled quotes
*/
function processQuotes(text) {
// Match »...« pattern (guillemets) including optional trailing whitespace
const quotePattern = /»([^«]+)«\s*/g;
return text.replace(quotePattern, (_match, quoted) => {
// Display without guillemets (styling is enough) + line break after
// Legacy guillemets: the markers are dropped (styling replaces them) and
// the pattern eats the space separating quote from reply, hence the <br>.
const legacyPattern = /»([^«]+)«\s*/g;
text = text.replace(legacyPattern, (_match, quoted) => {
return `<span class="quote-text">${quoted}</span><br>`;
});
// `>quoted line`. The text arrives HTML-escaped, so a typed '>' shows up as
// '&gt;' and the '>' of generated tags can never match. Anchored to the
// start of a line or to a leading @[mention] badge, so "5 &gt; 3" mid
// sentence is left alone. The trailing newline stays in place — the message
// containers are pre-wrap and render it as the break.
const quotePattern = /(^|\n|<\/span>[ \t]*)&gt;[ \t]*([^\n]*)/g;
return text.replace(quotePattern, (match, prefix, quoted) => {
if (!quoted.trim()) return match;
return `${prefix}<span class="quote-text">${quoted}</span>`;
});
}
/**