From a3d2939569f3616c0dec8dd0ea76ddd2b3d8cf27 Mon Sep 17 00:00:00 2001 From: "Stanko K.R." Date: Mon, 20 Jul 2026 15:35:13 +0200 Subject: [PATCH] Polish --- .../autocompletable/users_controller.rb | 6 ++++- .../remove_solo_unfurled_link_text.rb | 24 ++++++++++++++---- .../controllers/unfurl_controller.js | 25 +++++++++++++++---- app/javascript/models/client_message.js | 16 ++++++++++-- app/javascript/models/message_formatter.js | 13 +++++----- 5 files changed, 65 insertions(+), 19 deletions(-) diff --git a/app/controllers/autocompletable/users_controller.rb b/app/controllers/autocompletable/users_controller.rb index 32aa8ee..0de562e 100644 --- a/app/controllers/autocompletable/users_controller.rb +++ b/app/controllers/autocompletable/users_controller.rb @@ -10,7 +10,11 @@ class Autocompletable::UsersController < ApplicationController private def find_autocompletable_users - query.present? ? users_scope.active.filtered_by(query) : users_scope.active + if query.present? + users_scope.active.filtered_by(query) + else + users_scope.active + end end # The rich text editor's mentions prompt filters with `filter`, the diff --git a/app/helpers/content_filters/remove_solo_unfurled_link_text.rb b/app/helpers/content_filters/remove_solo_unfurled_link_text.rb index 2e2d247..85568ab 100644 --- a/app/helpers/content_filters/remove_solo_unfurled_link_text.rb +++ b/app/helpers/content_filters/remove_solo_unfurled_link_text.rb @@ -4,12 +4,10 @@ class ContentFilters::RemoveSoloUnfurledLinkText < ActionText::Content::Filter end def apply - if fragment.find_all("div").any? - # Trix-era bodies: one
wrapping the link text and the embed - fragment.replace("div") { |node| node.tap { |n| n.inner_html = unfurled_links.first.to_s } } + if trix_body? + remove_link_text_from_wrapping_div else - # Lexxy bodies: the link sits in its own

, the embed follows it - fragment.replace("p") { |node| node.at_css("action-text-attachment") ? node : nil } + remove_link_paragraphs end end @@ -41,4 +39,20 @@ class ContentFilters::RemoveSoloUnfurledLinkText < ActionText::Content::Filter def twitter_url?(url) url.present? && TWITTER_DOMAINS.any? { |domain| url.strip.include?(domain) } end + + def trix_body? + fragment.find_all("div").any? + end + + def remove_link_text_from_wrapping_div + fragment.replace("div") { |node| node.tap { |n| n.inner_html = unfurled_links.first.to_s } } + end + + def remove_link_paragraphs + fragment.replace("p") do |node| + if node.at_css("action-text-attachment") + node + end + end + end end diff --git a/app/javascript/controllers/unfurl_controller.js b/app/javascript/controllers/unfurl_controller.js index 4fb675d..40d963b 100644 --- a/app/javascript/controllers/unfurl_controller.js +++ b/app/javascript/controllers/unfurl_controller.js @@ -8,7 +8,6 @@ const OPENGRAPH_EMBED_CONTENT_TYPE = "application/vnd.actiontext.opengraph-embed const UNFURLED_TWITTER_AVATAR_CSS_CLASS = "cf-twitter-avatar" const TWITTER_AVATAR_URL_PREFIX = "https://pbs.twimg.com/profile_images" -// Unfurls URLs pasted into the rich text editor into OpenGraph preview attachments export default class extends Controller { #abortController @@ -44,14 +43,14 @@ export default class extends Controller { if (title && href) return { title, href, image, description } } } catch { - // Ignore aborted or failed requests, like the previous implementation did + // Ignore aborted and failed requests } return null } #opengraphEmbedHTML({ title, href, image, description }) { - return ` + return `

@@ -59,12 +58,28 @@ export default class extends Controller {
${escapeHTML(truncateString(description, 560))}
- ${image ? `
` : ""} + ${this.#imageHTML(image)}
` } + #embedClass(image) { + if (this.#isTwitterAvatar(image)) { + return UNFURLED_TWITTER_AVATAR_CSS_CLASS + } else { + return "" + } + } + #isTwitterAvatar(image) { - return !!image?.startsWith(TWITTER_AVATAR_URL_PREFIX) + return Boolean(image) && image.startsWith(TWITTER_AVATAR_URL_PREFIX) + } + + #imageHTML(image) { + if (image) { + return `
` + } else { + return "" + } } } diff --git a/app/javascript/models/client_message.js b/app/javascript/models/client_message.js index 68ce212..952366b 100644 --- a/app/javascript/models/client_message.js +++ b/app/javascript/models/client_message.js @@ -18,7 +18,7 @@ export default class ClientMessage { body, messageTimestamp: Math.floor(now.getTime()), messageDatetime: now.toISOString(), - messageClasses: this.#containsOnlyEmoji(this.#plainTextFromNode(node)) ? "message--emoji" : "", + messageClasses: this.#messageClassesFromNode(node), }) } @@ -52,6 +52,14 @@ export default class ClientMessage { } } + #messageClassesFromNode(node) { + if (this.#containsOnlyEmoji(this.#plainTextFromNode(node))) { + return "message--emoji" + } else { + return "" + } + } + #isPlayCommand(node) { return this.#matchPlayCommand(node) @@ -62,7 +70,11 @@ export default class ClientMessage { } #plainTextFromNode(node) { - return this.#isRichText(node) ? node.toString()?.trim() : node + if (this.#isRichText(node)) { + return node.toString().trim() + } else { + return node + } } #isRichText(node) { diff --git a/app/javascript/models/message_formatter.js b/app/javascript/models/message_formatter.js index b5f9b27..32e1694 100644 --- a/app/javascript/models/message_formatter.js +++ b/app/javascript/models/message_formatter.js @@ -77,14 +77,15 @@ export default class MessageFormatter { #highlightCodeBlock(block) { this.#normalizeLineBreaks(block) - if (!this.#isPlainText(block)) return - const language = block.dataset.language - if (language && window.hljs.getLanguage(language)) { - block.classList.add(`language-${language}`) + if (this.#isPlainText(block)) { + const language = block.dataset.language + if (language && window.hljs.getLanguage(language)) { + block.classList.add(`language-${language}`) + } + + window.hljs.highlightElement(block) } - - window.hljs.highlightElement(block) } // Lexxy breaks code block lines with
, Trix-era blocks used newlines