DEV: Drop experimental enable_diffhtml_preview setting (#31306)

This was intended to provide a better UX for interactive elements in the
composer preview. However, the morphing strategy has irreconcilable
conflicts with our `decorateCooked` API, and so we have been unable to
enable this by default.

Going forward, we're focussing efforts on the WYSIWYG composer to
provide this kind of smooth UX, so we're dropping the
`enable_diffhtml_preview` approach.
This commit is contained in:
David Taylor
2025-02-12 15:58:30 +00:00
committed by GitHub
parent d6d3c2316b
commit f5c2a4dbbd
13 changed files with 21 additions and 186 deletions

View File

@ -149,7 +149,6 @@ class Setup {
discourse.limitedSiteSettings = {
secureUploads: siteSettings.secure_uploads,
enableDiffhtmlPreview: siteSettings.enable_diffhtml_preview,
traditionalMarkdownLinebreaks:
siteSettings.traditional_markdown_linebreaks,
enableMarkdownLinkify: siteSettings.enable_markdown_linkify,

View File

@ -456,8 +456,8 @@ export default class ComposerEditor extends Component {
$preview.scrollTop(desired + 50);
}
_renderMentions(preview, unseen) {
unseen ||= linkSeenMentions(preview, this.siteSettings);
_renderMentions(preview) {
const unseen = linkSeenMentions(preview, this.siteSettings);
if (unseen.length > 0) {
this._renderUnseenMentions(preview, unseen);
} else {
@ -480,9 +480,9 @@ export default class ComposerEditor extends Component {
});
}
_renderHashtags(preview, unseen) {
_renderHashtags(preview) {
const context = this.site.hashtag_configurations["topic-composer"];
unseen ||= linkSeenHashtagsInContext(context, preview);
const unseen = linkSeenHashtagsInContext(context, preview);
if (unseen.length > 0) {
this._renderUnseenHashtags(preview, unseen, context);
}
@ -896,15 +896,13 @@ export default class ComposerEditor extends Component {
}
@action
previewUpdated(preview, unseenMentions, unseenHashtags) {
this._renderMentions(preview, unseenMentions);
this._renderHashtags(preview, unseenHashtags);
previewUpdated(preview) {
this._renderMentions(preview);
this._renderHashtags(preview);
this._refreshOneboxes(preview);
this._expandShortUrls(preview);
if (!this.siteSettings.enable_diffhtml_preview) {
this._decorateCookedElement(preview);
}
this._decorateCookedElement(preview);
this.composer.afterRefresh(preview);
}

View File

@ -75,9 +75,7 @@
class="d-editor-preview-wrapper {{if this.forcePreview 'force-preview'}}"
>
<div class="d-editor-preview">
{{#unless this.siteSettings.enable_diffhtml_preview}}
{{html-safe this.preview}}
{{/unless}}
{{html-safe this.preview}}
</div>
<span class="d-editor-plugin">
<PluginOutlet

View File

@ -8,12 +8,10 @@ import { classNames } from "@ember-decorators/component";
import { observes, on } from "@ember-decorators/object";
import { emojiSearch, isSkinTonableEmoji } from "pretty-text/emoji";
import { translations } from "pretty-text/emoji/data";
import { resolveCachedShortUrls } from "pretty-text/upload-short-url";
import { Promise } from "rsvp";
import TextareaEditor from "discourse/components/composer/textarea-editor";
import EmojiPickerDetached from "discourse/components/emoji-picker/detached";
import InsertHyperlink from "discourse/components/modal/insert-hyperlink";
import { ajax } from "discourse/lib/ajax";
import { SKIP } from "discourse/lib/autocomplete";
import Toolbar from "discourse/lib/composer/toolbar";
import discourseDebounce from "discourse/lib/debounce";
@ -22,11 +20,8 @@ import deprecated from "discourse/lib/deprecated";
import { isTesting } from "discourse/lib/environment";
import { getRegister } from "discourse/lib/get-owner";
import { hashtagAutocompleteOptions } from "discourse/lib/hashtag-autocomplete";
import { linkSeenHashtagsInContext } from "discourse/lib/hashtag-decorator";
import { wantsNewWindow } from "discourse/lib/intercept-click";
import { PLATFORM_KEY_MODIFIER } from "discourse/lib/keyboard-shortcuts";
import { linkSeenMentions } from "discourse/lib/link-mentions";
import { loadOneboxes } from "discourse/lib/load-oneboxes";
import loadRichEditor from "discourse/lib/load-rich-editor";
import { findRawTemplate } from "discourse/lib/raw-templates";
import { emojiUrlFor, generateCookFunction } from "discourse/lib/text";
@ -242,45 +237,6 @@ export default class DEditor extends Component {
this.set("preview", cooked);
let unseenMentions, unseenHashtags;
if (this.siteSettings.enable_diffhtml_preview) {
const previewElement = this.element.querySelector(".d-editor-preview");
const cookedElement = previewElement.cloneNode(false);
cookedElement.innerHTML = cooked;
unseenMentions = linkSeenMentions(cookedElement, this.siteSettings);
unseenHashtags = linkSeenHashtagsInContext(
this.site.hashtag_configurations["topic-composer"],
cookedElement
);
loadOneboxes(
cookedElement,
ajax,
this.topicId,
this.categoryId,
this.siteSettings.max_oneboxes_per_post,
/* refresh */ false,
/* offline */ true
);
resolveCachedShortUrls(this.siteSettings, cookedElement);
// trigger all the "api.decorateCookedElement"
this.appEvents.trigger(
"decorate-non-stream-cooked-element",
cookedElement
);
(await import("morphlex")).morph(
previewElement,
cookedElement,
this.morphingOptions
);
}
schedule("afterRender", () => {
if (
this._state !== "inDOM" ||
@ -294,7 +250,7 @@ export default class DEditor extends Component {
const previewElement = this.element.querySelector(".d-editor-preview");
if (previewElement && this.previewUpdated) {
this.previewUpdated(previewElement, unseenMentions, unseenHashtags);
this.previewUpdated(previewElement);
}
});
}

View File

@ -159,31 +159,15 @@ function _loadCachedShortUrls(uploadElements, siteSettings, opts) {
break;
case "DIV":
if (siteSettings.enable_diffhtml_preview === true) {
retrieveCachedUrl(upload, siteSettings, "orig-src", opts, (url) => {
const videoHTML = `
<video width="100%" height="100%" preload="metadata" controls style="">
<source src="${url}">
</video>`;
upload.insertAdjacentHTML("beforeend", videoHTML);
upload.classList.add("video-container");
});
} else {
retrieveCachedUrl(
upload,
siteSettings,
"orig-src-id",
opts,
(url) => {
upload.style.backgroundImage = `url('${url}')`;
retrieveCachedUrl(upload, siteSettings, "orig-src-id", opts, (url) => {
upload.style.backgroundImage = `url('${url}')`;
const placeholderIcon = upload.querySelector(
".placeholder-icon.video"
);
placeholderIcon.style.backgroundColor = "rgba(0, 0, 0, 0.3)";
}
const placeholderIcon = upload.querySelector(
".placeholder-icon.video"
);
}
placeholderIcon.style.backgroundColor = "rgba(0, 0, 0, 0.3)";
});
break;
}
});

View File

@ -2596,7 +2596,6 @@ en:
disable_watched_word_checking_in_user_fields: "disable watched word checking in user fields"
watched_words_regular_expressions: "Allows the use of regular expressions for filtering words. If enabled, this feature groups sensitive words by their case-sensitivity. It then compiles all selected words into a single regular expression, adding word boundaries for regular watched words. Consequently, this regex-based filtering method adds an extra layer of control over content moderation by supporting more sophisticated word patterns. The setting also allows to easily substitute the original text with the replacement of choice."
enable_diffhtml_preview: "Experimental feature which uses diffHTML to sync preview instead of full re-render"
enable_fast_edit: "Adds a button to the post selection menu to edit a small selection inline."
old_post_notice_days: "The number of days after which a post notice is considered old. This visually differentiates it from newer notices on the site."
new_user_notice_tl: "Minimum trust level required to see new user post notices."

View File

@ -1310,10 +1310,6 @@ posting:
watched_words_regular_expressions:
client: true
default: false
enable_diffhtml_preview:
hidden: true
default: false
client: true
enable_fast_edit:
default: true
client: true

View File

@ -75,12 +75,8 @@ module Onebox
def placeholder_html
return article_html if (is_article? || force_article_html?)
return image_html if is_image?
if !SiteSetting.enable_diffhtml_preview? && (is_video? || is_card?)
return Onebox::Helpers.video_placeholder_html
end
if !SiteSetting.enable_diffhtml_preview? && is_embedded?
return Onebox::Helpers.generic_placeholder_html
end
return Onebox::Helpers.video_placeholder_html if (is_video? || is_card?)
return Onebox::Helpers.generic_placeholder_html if is_embedded?
to_html
end

View File

@ -23,7 +23,7 @@ module Onebox
end
def placeholder_html
SiteSetting.enable_diffhtml_preview ? to_html : ::Onebox::Helpers.audio_placeholder_html
::Onebox::Helpers.audio_placeholder_html
end
end
end

View File

@ -29,7 +29,7 @@ module Onebox
end
def placeholder_html
SiteSetting.enable_diffhtml_preview ? to_html : ::Onebox::Helpers.video_placeholder_html
::Onebox::Helpers.video_placeholder_html
end
end
end

View File

@ -1,30 +0,0 @@
# frozen_string_literal: true
describe "Morphed Composer Preview", type: :system do
fab!(:user) { Fabricate(:user, refresh_auto_groups: true) }
let(:composer) { PageObjects::Components::Composer.new }
before do
SiteSetting.enable_diffhtml_preview = true
sign_in user
visit("/new-topic")
end
it "keeps details element open" do
composer.type_content <<~MD
[details=Velcro]
What a rip-off!
[/details]
MD
within(composer.preview) do
find("details").click
expect(page).to have_css("details[open]")
end
composer.move_cursor_after("rip-off!")
composer.type_content(" :person_facepalming:")
within(composer.preview) { expect(page).to have_css("details[open] img.emoji") }
end
end

View File

@ -1,41 +0,0 @@
# frozen_string_literal: true
describe "Morphed Composer Preview", type: :system do
fab!(:user) { Fabricate(:user, username: "bob", refresh_auto_groups: true) }
let(:composer) { PageObjects::Components::Composer.new }
before do
SiteSetting.enable_diffhtml_preview = true
sign_in user
visit("/new-topic")
end
it "correctly morphs code blocks" do
composer.fill_content <<~MD
```js
const = {
id: t.name,
text: t.name,
name: t.name,
```
MD
within(composer.preview) { expect(find("code.lang-js")).to have_text("const = {") }
composer.move_cursor_after("const")
composer.type_content("ant")
within(composer.preview) { expect(find("code.lang-js")).to have_text("constant = {") }
end
it "correctly morphs mentions" do
composer.fill_content("@bob text")
within(composer.preview) { expect(find("a.mention")).to have_text("@bob") }
composer.select_all
composer.type_content("@system")
within(composer.preview) { expect(find("a.mention")).to have_text("@system") }
end
end

View File

@ -137,26 +137,6 @@ describe "Uploading files in the composer", type: :system do
expect(composer).to have_no_in_progress_uploads
expect(composer.preview).to have_css(".onebox-placeholder-container")
end
it "shows video player in composer" do
SiteSetting.enable_diffhtml_preview = true
visit "/new-topic"
expect(composer).to be_opened
topic.fill_in_composer_title("Video upload test")
file_path_1 = file_from_fixtures("small.mp4", "media").path
attach_file(file_path_1) { composer.click_toolbar_button("upload") }
expect(composer).to have_no_in_progress_uploads
expect(composer.preview).to have_css(".video-container video")
expect(page).to have_css(
".video-container video source[src]",
visible: false,
wait: Capybara.default_max_wait_time,
)
end
end
context "when multiple images are uploaded" do