FIX: avoid inline oneboxing watched words on rich editor (#37349)

Watched link words can generate `link_open` markdown-it tokens with a
`linkify` `markup`. This attribute is used both to allow serialization
back to markdown without the link `[]()` syntax, and also to be captured
by the onebox extension to trigger a oneboxing attempt.

This PR adds a test to only attempt oneboxes to `linkify` links that
also happen to have a URL-like content, avoiding this edge case.
This commit is contained in:
Renato Atilio
2026-01-28 14:00:46 -03:00
committed by GitHub
parent 3a3164047f
commit 715b7c7d18
2 changed files with 36 additions and 1 deletions
@@ -5,7 +5,10 @@ import {
import { load } from "pretty-text/oneboxer";
import { ajax } from "discourse/lib/ajax";
import escapeRegExp from "discourse/lib/escape-regexp";
import { isWhiteSpace } from "discourse/static/prosemirror/lib/markdown-it";
import {
getLinkify,
isWhiteSpace,
} from "discourse/static/prosemirror/lib/markdown-it";
import { isTopLevel } from "discourse-markdown-it/features/onebox";
/** @type {RichEditorExtension} */
@@ -169,6 +172,8 @@ const extension = {
if (
link?.attrs.markup === "linkify" &&
// Excludes watched word links
getLinkify().test(node.text) &&
set.find(pos, pos + node.nodeSize).length === 0 &&
isOutsideSelection(pos, node.nodeSize, tr)
) {
@@ -180,4 +180,34 @@ describe "Composer - ProseMirror - Oneboxing", type: :system do
expect(composer).to have_value("Hey https://example.com/x and https://example.com/x")
end
context "with watched word links" do
fab!(:topic) { Fabricate(:topic, user: current_user) }
fab!(:post) do
Fabricate(:post, topic:, user: current_user, raw: "Check out discourse for more info")
end
fab!(:watched_word) do
Fabricate(
:watched_word,
action: WatchedWord.actions[:link],
word: "discourse",
replacement: "https://example.com/x",
)
end
it "does not onebox watched word links" do
visit "/t/#{topic.slug}/#{topic.id}"
find(".post-action-menu__edit").click
expect(composer).to be_opened
composer.focus
expect(rich).to have_css("a[href='https://example.com/x']", text: "discourse")
expect(rich).to have_no_css("a.inline-onebox")
expect(rich).to have_no_css(".inline-onebox-loading")
composer.toggle_rich_editor
expect(composer).to have_value("Check out discourse for more info")
end
end
end