diff --git a/app/assets/javascripts/discourse/app/components/composer-editor.hbs b/app/assets/javascripts/discourse/app/components/composer-editor.hbs index 06e394bd430..5bb55afd328 100644 --- a/app/assets/javascripts/discourse/app/components/composer-editor.hbs +++ b/app/assets/javascripts/discourse/app/components/composer-editor.hbs @@ -23,6 +23,8 @@ @editingPost={{this.composer.editingPost}} @disabled={{this.disableTextarea}} @outletArgs={{hash composer=this.composer editorType="composer"}} + @topicId={{this.composer.topic.id}} + @categoryId={{this.composer.category.id}} > {{yield}} diff --git a/app/assets/javascripts/discourse/app/components/d-editor.js b/app/assets/javascripts/discourse/app/components/d-editor.js index 34b913810e0..941eec6c5e4 100644 --- a/app/assets/javascripts/discourse/app/components/d-editor.js +++ b/app/assets/javascripts/discourse/app/components/d-editor.js @@ -17,7 +17,6 @@ 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 loadScript from "discourse/lib/load-script"; import { emojiUrlFor, generateCookFunction } from "discourse/lib/text"; import { siteDir } from "discourse/lib/text-direction"; import { @@ -413,92 +412,84 @@ export default Component.extend(TextareaTextManipulation, { return toolbar; }, - cachedCookAsync(text) { - if (this._cachedCookFunction) { - return Promise.resolve(this._cachedCookFunction(text)); - } - - const markdownOptions = this.markdownOptions || {}; - return generateCookFunction(markdownOptions).then((cook) => { - this._cachedCookFunction = cook; - return cook(text); - }); + async cachedCookAsync(text, options) { + this._cachedCookFunction ||= await generateCookFunction(options || {}); + return await this._cachedCookFunction(text); }, - _updatePreview() { - if (this._state !== "inDOM" || !this.processPreview) { + async _updatePreview() { + if ( + this._state !== "inDOM" || + !this.processPreview || + this.isDestroying || + this.isDestroyed + ) { return; } - const value = this.value; + const cooked = await this.cachedCookAsync(this.value, this.markdownOptions); - this.cachedCookAsync(value).then((cooked) => { - if (this.isDestroyed) { + if (this.preview === cooked || this.isDestroying || this.isDestroyed) { + return; + } + + this.set("preview", cooked); + + if (this.siteSettings.enable_diffhtml_preview) { + const previewElement = this.element.querySelector(".d-editor-preview"); + const cookedElement = previewElement.cloneNode(false); + cookedElement.innerHTML = cooked; + + // Same order of operation as in the "previewUpdated" method in "composer-editor.js" + linkSeenMentions(cookedElement, this.siteSettings); + + linkSeenHashtagsInContext( + this.site.hashtag_configurations["topic-composer"], + cookedElement + ); + + loadOneboxes( + cookedElement, + ajax, + this.topicId, + this.categoryId, + this.siteSettings.max_oneboxes_per_post, + false, + true + ); + + resolveCachedShortUrls(this.siteSettings, cookedElement); + + (await import("morphlex")).morph(previewElement, cookedElement); + } + + schedule("afterRender", () => { + if ( + this._state !== "inDOM" || + !this.element || + this.isDestroying || + this.isDestroyed + ) { return; } - if (this.preview === cooked) { - return; + const previewElement = this.element.querySelector(".d-editor-preview"); + + if (previewElement && this.previewUpdated) { + this.previewUpdated(previewElement); } - - this.set("preview", cooked); - - let previewPromise = Promise.resolve(); - - if (this.siteSettings.enable_diffhtml_preview) { - const cookedElement = document.createElement("div"); - cookedElement.innerHTML = cooked; - linkSeenHashtagsInContext( - this.site.hashtag_configurations["topic-composer"], - cookedElement - ); - linkSeenMentions(cookedElement, this.siteSettings); - resolveCachedShortUrls(this.siteSettings, cookedElement); - loadOneboxes( - cookedElement, - ajax, - null, - null, - this.siteSettings.max_oneboxes_per_post, - false, - true - ); - - previewPromise = loadScript("/javascripts/diffhtml.min.js").then(() => { - const previewElement = - this.element.querySelector(".d-editor-preview"); - window.diff.innerHTML(previewElement, cookedElement.innerHTML); - }); - } - - previewPromise.then(() => { - schedule("afterRender", () => { - if (this._state !== "inDOM" || !this.element) { - return; - } - - const preview = this.element.querySelector(".d-editor-preview"); - if (!preview) { - return; - } - - if (this.previewUpdated) { - this.previewUpdated(preview); - } - }); - }); }); }, @observes("ready", "value", "processPreview") - _watchForChanges() { + async _watchForChanges() { if (!this.ready) { return; } // Debouncing in test mode is complicated if (isTesting()) { - this._updatePreview(); + await this._updatePreview(); } else { discourseDebounce(this, this._updatePreview, 30); } diff --git a/app/assets/javascripts/discourse/package.json b/app/assets/javascripts/discourse/package.json index cfaa27fbd84..f00abd0206b 100644 --- a/app/assets/javascripts/discourse/package.json +++ b/app/assets/javascripts/discourse/package.json @@ -25,6 +25,7 @@ "handlebars": "^4.7.8", "highlight.js": "^11.9.0", "jspreadsheet-ce": "^4.13.4", + "morphlex": "^0.0.15", "pretty-text": "1.0.0" }, "devDependencies": { diff --git a/yarn.lock b/yarn.lock index 78bf7032d7e..8b774a46022 100644 --- a/yarn.lock +++ b/yarn.lock @@ -9776,6 +9776,11 @@ morgan@^1.10.0: on-finished "~2.3.0" on-headers "~1.0.2" +morphlex@^0.0.15: + version "0.0.15" + resolved "https://registry.yarnpkg.com/morphlex/-/morphlex-0.0.15.tgz#651eaeec36424a980f02ed8a6dada7f2785b71b3" + integrity sha512-XUJykOS7kpwA8byZYp5jYPwnx/MFDESC+rL3vXyETpWNw6Lb5icQZxaoVn/qDLpbpEaawUXielFIsxCjrz+g/g== + ms@2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/ms/-/ms-2.0.0.tgz#5608aeadfc00be6c2901df5f9861788de0d597c8"