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
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
13 changed files with 21 additions and 186 deletions

View File

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

View File

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

View File

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

View File

@ -8,12 +8,10 @@ import { classNames } from "@ember-decorators/component";
import { observes, on } from "@ember-decorators/object"; import { observes, on } from "@ember-decorators/object";
import { emojiSearch, isSkinTonableEmoji } from "pretty-text/emoji"; import { emojiSearch, isSkinTonableEmoji } from "pretty-text/emoji";
import { translations } from "pretty-text/emoji/data"; import { translations } from "pretty-text/emoji/data";
import { resolveCachedShortUrls } from "pretty-text/upload-short-url";
import { Promise } from "rsvp"; import { Promise } from "rsvp";
import TextareaEditor from "discourse/components/composer/textarea-editor"; import TextareaEditor from "discourse/components/composer/textarea-editor";
import EmojiPickerDetached from "discourse/components/emoji-picker/detached"; import EmojiPickerDetached from "discourse/components/emoji-picker/detached";
import InsertHyperlink from "discourse/components/modal/insert-hyperlink"; import InsertHyperlink from "discourse/components/modal/insert-hyperlink";
import { ajax } from "discourse/lib/ajax";
import { SKIP } from "discourse/lib/autocomplete"; import { SKIP } from "discourse/lib/autocomplete";
import Toolbar from "discourse/lib/composer/toolbar"; import Toolbar from "discourse/lib/composer/toolbar";
import discourseDebounce from "discourse/lib/debounce"; import discourseDebounce from "discourse/lib/debounce";
@ -22,11 +20,8 @@ import deprecated from "discourse/lib/deprecated";
import { isTesting } from "discourse/lib/environment"; import { isTesting } from "discourse/lib/environment";
import { getRegister } from "discourse/lib/get-owner"; import { getRegister } from "discourse/lib/get-owner";
import { hashtagAutocompleteOptions } from "discourse/lib/hashtag-autocomplete"; import { hashtagAutocompleteOptions } from "discourse/lib/hashtag-autocomplete";
import { linkSeenHashtagsInContext } from "discourse/lib/hashtag-decorator";
import { wantsNewWindow } from "discourse/lib/intercept-click"; import { wantsNewWindow } from "discourse/lib/intercept-click";
import { PLATFORM_KEY_MODIFIER } from "discourse/lib/keyboard-shortcuts"; 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 loadRichEditor from "discourse/lib/load-rich-editor";
import { findRawTemplate } from "discourse/lib/raw-templates"; import { findRawTemplate } from "discourse/lib/raw-templates";
import { emojiUrlFor, generateCookFunction } from "discourse/lib/text"; import { emojiUrlFor, generateCookFunction } from "discourse/lib/text";
@ -242,45 +237,6 @@ export default class DEditor extends Component {
this.set("preview", cooked); 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", () => { schedule("afterRender", () => {
if ( if (
this._state !== "inDOM" || this._state !== "inDOM" ||
@ -294,7 +250,7 @@ export default class DEditor extends Component {
const previewElement = this.element.querySelector(".d-editor-preview"); const previewElement = this.element.querySelector(".d-editor-preview");
if (previewElement && this.previewUpdated) { if (previewElement && this.previewUpdated) {
this.previewUpdated(previewElement, unseenMentions, unseenHashtags); this.previewUpdated(previewElement);
} }
}); });
} }

View File

@ -159,31 +159,15 @@ function _loadCachedShortUrls(uploadElements, siteSettings, opts) {
break; break;
case "DIV": case "DIV":
if (siteSettings.enable_diffhtml_preview === true) { retrieveCachedUrl(upload, siteSettings, "orig-src-id", opts, (url) => {
retrieveCachedUrl(upload, siteSettings, "orig-src", opts, (url) => { upload.style.backgroundImage = `url('${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}')`;
const placeholderIcon = upload.querySelector( const placeholderIcon = upload.querySelector(
".placeholder-icon.video" ".placeholder-icon.video"
);
placeholderIcon.style.backgroundColor = "rgba(0, 0, 0, 0.3)";
}
); );
} placeholderIcon.style.backgroundColor = "rgba(0, 0, 0, 0.3)";
});
break; break;
} }
}); });

View File

@ -2596,7 +2596,6 @@ en:
disable_watched_word_checking_in_user_fields: "disable watched word checking in user fields" 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." 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." 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." 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." 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: watched_words_regular_expressions:
client: true client: true
default: false default: false
enable_diffhtml_preview:
hidden: true
default: false
client: true
enable_fast_edit: enable_fast_edit:
default: true default: true
client: true client: true

View File

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

View File

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

View File

@ -29,7 +29,7 @@ module Onebox
end end
def placeholder_html def placeholder_html
SiteSetting.enable_diffhtml_preview ? to_html : ::Onebox::Helpers.video_placeholder_html ::Onebox::Helpers.video_placeholder_html
end end
end 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).to have_no_in_progress_uploads
expect(composer.preview).to have_css(".onebox-placeholder-container") expect(composer.preview).to have_css(".onebox-placeholder-container")
end 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 end
context "when multiple images are uploaded" do context "when multiple images are uploaded" do