DEV: Refactor composer preview rendering (#31308)

- Switch to use new `<DecoratedHtml` component (including
`renderGlimmer` support)

- Updates click handling to use `{{on` modifier instead of manual event
listener setup/teardown
This commit is contained in:
David Taylor 2025-02-14 09:50:02 +00:00 committed by GitHub
parent 35084d3089
commit 54b1e3195c
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
4 changed files with 31 additions and 42 deletions

View File

@ -519,8 +519,12 @@ export default class ComposerEditor extends Component {
resolveAllShortUrls(ajax, this.siteSettings, preview);
}
_decorateCookedElement(preview) {
this.appEvents.trigger("decorate-non-stream-cooked-element", preview);
_decorateCookedElement(preview, helper) {
this.appEvents.trigger(
"decorate-non-stream-cooked-element",
preview,
helper
);
}
@debounce(DEBOUNCE_JIT_MS)
@ -896,13 +900,13 @@ export default class ComposerEditor extends Component {
}
@action
previewUpdated(preview) {
previewUpdated(preview, helper) {
this._renderMentions(preview);
this._renderHashtags(preview);
this._refreshOneboxes(preview);
this._expandShortUrls(preview);
this._decorateCookedElement(preview);
this._decorateCookedElement(preview, helper);
this.composer.afterRefresh(preview);
}

View File

@ -2,6 +2,7 @@ import { tracked } from "@glimmer/tracking";
import Component from "@ember/component";
import EmberObject, { action } from "@ember/object";
import { not } from "@ember/object/computed";
import { schedule } from "@ember/runloop";
import { service } from "@ember/service";
import { classNameBindings } from "@ember-decorators/component";
import { ajax } from "discourse/lib/ajax";
@ -70,8 +71,10 @@ export default class ComposerMessages extends Component {
return;
}
this.reset();
this.popup(EmberObject.create(info));
schedule("actions", () => {
this.reset();
this.popup(EmberObject.create(info));
});
}
// Resets all active messages.

View File

@ -71,12 +71,16 @@
</div>
</div>
{{! template-lint-disable no-invalid-interactive }}
<div
class="d-editor-preview-wrapper {{if this.forcePreview 'force-preview'}}"
{{on "click" this.handlePreviewClick}}
>
<div class="d-editor-preview">
{{html-safe this.preview}}
</div>
<DecoratedHtml
@className="d-editor-preview"
@html={{html-safe this.preview}}
@decorate={{this.previewUpdated}}
/>
<span class="d-editor-plugin">
<PluginOutlet
@name="editor-preview"

View File

@ -15,7 +15,7 @@ import InsertHyperlink from "discourse/components/modal/insert-hyperlink";
import { SKIP } from "discourse/lib/autocomplete";
import Toolbar from "discourse/lib/composer/toolbar";
import discourseDebounce from "discourse/lib/debounce";
import discourseComputed, { bind } from "discourse/lib/decorators";
import discourseComputed from "discourse/lib/decorators";
import deprecated from "discourse/lib/deprecated";
import { isTesting } from "discourse/lib/environment";
import { getRegister } from "discourse/lib/get-owner";
@ -60,6 +60,8 @@ export default class DEditor extends Component {
/** @type {TextManipulation} */
@tracked textManipulation;
@tracked preview;
ready = false;
lastSel = null;
showLink = true;
@ -105,14 +107,7 @@ export default class DEditor extends Component {
didInsertElement() {
super.didInsertElement(...arguments);
this._previewMutationObserver = this._disablePreviewTabIndex();
// disable clicking on links in the preview
this.element
.querySelector(".d-editor-preview")
.addEventListener("click", this._handlePreviewLinkClick);
``;
}
get keymap() {
@ -154,8 +149,12 @@ export default class DEditor extends Component {
return keymap;
}
@bind
_handlePreviewLinkClick(event) {
@action
handlePreviewClick(event) {
if (!event.target.closest(".d-editor-preview")) {
return;
}
if (wantsNewWindow(event)) {
return;
}
@ -184,10 +183,6 @@ export default class DEditor extends Component {
@on("willDestroyElement")
_shutDown() {
this.element
.querySelector(".d-editor-preview")
?.removeEventListener("click", this._handlePreviewLinkClick);
this._previewMutationObserver?.disconnect();
this._cachedCookFunction = null;
@ -235,24 +230,7 @@ export default class DEditor extends Component {
return;
}
this.set("preview", cooked);
schedule("afterRender", () => {
if (
this._state !== "inDOM" ||
!this.element ||
this.isDestroying ||
this.isDestroyed
) {
return;
}
const previewElement = this.element.querySelector(".d-editor-preview");
if (previewElement && this.previewUpdated) {
this.previewUpdated(previewElement);
}
});
this.preview = cooked;
}
@observes("ready", "value", "processPreview")
@ -716,7 +694,7 @@ export default class DEditor extends Component {
});
});
observer.observe(document.querySelector(".d-editor-preview"), {
observer.observe(document.querySelector(".d-editor-preview-wrapper"), {
childList: true,
subtree: true,
attributes: false,