FEATURE: Review posts with media. (#10693)

FEATURE: Review posts with media. (#10693)

To check if a post contains any embedded media, we look if the “image_sizes” attribute is present in the new post manager arguments.

We want to see one boxed links, but we only store the raw content of the post. To work around this, I extracted the onebox logic from the composer editor into a module.

diff --git a/app/assets/javascripts/discourse/app/components/composer-editor.js b/app/assets/javascripts/discourse/app/components/composer-editor.js
index 4288f9f..9507830 100644
--- a/app/assets/javascripts/discourse/app/components/composer-editor.js
+++ b/app/assets/javascripts/discourse/app/components/composer-editor.js
@@ -16,8 +16,6 @@ import {
   fetchUnseenHashtags,
 } from "discourse/lib/link-hashtags";
 import Composer from "discourse/models/composer";
-import { load, LOADING_ONEBOX_CSS_CLASS } from "pretty-text/oneboxer";
-import { applyInlineOneboxes } from "pretty-text/inline-oneboxer";
 import { ajax } from "discourse/lib/ajax";
 import EmberObject from "@ember/object";
 import { findRawTemplate } from "discourse-common/lib/raw-templates";
@@ -43,6 +41,7 @@ import {
   resolveAllShortUrls,
 } from "pretty-text/upload-short-url";
 import { isTesting } from "discourse-common/config/environment";
+import { loadOneboxes } from "discourse/lib/load-oneboxes";
 
 const REBUILD_SCROLL_MAP_EVENTS = ["composer:resized", "composer:typed-reply"];
 
@@ -531,36 +530,6 @@ export default Component.extend({
     }
   },
 
-  _loadInlineOneboxes(inline) {
-    applyInlineOneboxes(inline, ajax, {
-      categoryId: this.get("composer.category.id"),
-      topicId: this.get("composer.topic.id"),
-    });
-  },
-
-  _loadOneboxes(oneboxes) {
-    const post = this.get("composer.post");
-    let refresh = false;
-
-    // If we are editing a post, we'll refresh its contents once.
-    if (post && !post.get("refreshedPost")) {
-      refresh = true;
-      post.set("refreshedPost", true);
-    }
-
-    Object.values(oneboxes).forEach((onebox) => {
-      onebox.forEach(($onebox) => {
-        load({
-          elem: $onebox,
-          refresh,
-          ajax,
-          categoryId: this.get("composer.category.id"),
-          topicId: this.get("composer.topic.id"),
-        });
-      });
-    });
-  },
-
   _warnMentionedGroups($preview) {
     schedule("afterRender", () => {
       var found = this.warnedGroupMentions || [];
@@ -934,50 +903,28 @@ export default Component.extend({
       }
 
       // Paint oneboxes
-      debounce(
-        this,
-        () => {
-          const oneboxes = {};
-          const inlineOneboxes = {};
-
-          // Oneboxes = `a.onebox` -> `a.onebox-loading` -> `aside.onebox`
-          // Inline Oneboxes = `a.inline-onebox-loading` -> `a.inline-onebox`
-
-          let loadedOneboxes = $preview.find(
-            `aside.onebox, a.${LOADING_ONEBOX_CSS_CLASS}, a.inline-onebox`
-          ).length;
-
-          $preview.find(`a.onebox, a.inline-onebox-loading`).each((_, link) => {
-            const $link = $(link);
-            const text = $link.text();
-            const isInline = $link.attr("class") === "inline-onebox-loading";
-            const m = isInline ? inlineOneboxes : oneboxes;
-
-            if (loadedOneboxes < this.siteSettings.max_oneboxes_per_post) {
-              if (m[text] === undefined) {
-                m[text] = [];
-                loadedOneboxes++;
-              }
-              m[text].push(link);
-            } else {
-              if (m[text] !== undefined) {
-                m[text].push(link);
-              } else if (isInline) {
-                $link.removeClass("inline-onebox-loading");
-              }
-            }
-          });
+      const paintFunc = () => {
+        const post = this.get("composer.post");
+        let refresh = false;
 
-          if (Object.keys(oneboxes).length > 0) {
-            this._loadOneboxes(oneboxes);
-          }
+        //If we are editing a post, we'll refresh its contents once.
+        if (post && !post.get("refreshedPost")) {
+          refresh = true;
+        }
 
-          if (Object.keys(inlineOneboxes).length > 0) {
-            this._loadInlineOneboxes(inlineOneboxes);
-          }
-        },
-        450
-      );
+        const paintedCount = loadOneboxes(
+          $preview[0],
+          ajax,
+          this.get("composer.topic.id"),
+          this.get("composer.category.id"),
+          this.siteSettings.max_oneboxes_per_post,
+          refresh
+        );
+
+        if (refresh && paintedCount > 0) post.set("refreshedPost", true);
+      };
+
+      debounce(this, paintFunc, 450);
 
       // Short upload urls need resolution
       resolveAllShortUrls(ajax, this.siteSettings, $preview[0]);
diff --git a/app/assets/javascripts/discourse/app/components/cook-text.js b/app/assets/javascripts/discourse/app/components/cook-text.js
index e5088b2..c6c4e14 100644
--- a/app/assets/javascripts/discourse/app/components/cook-text.js
+++ b/app/assets/javascripts/discourse/app/components/cook-text.js
@@ -2,6 +2,7 @@ import Component from "@ember/component";
 import { afterRender } from "discourse-common/utils/decorators";
 import { ajax } from "discourse/lib/ajax";
 import { cookAsync } from "discourse/lib/text";
+import { loadOneboxes } from "discourse/lib/load-oneboxes";
 import { resolveAllShortUrls } from "pretty-text/upload-short-url";
 
 const CookText = Component.extend({
@@ -11,11 +12,26 @@ const CookText = Component.extend({
     this._super(...arguments);
     cookAsync(this.rawText).then((cooked) => {
       this.set("cooked", cooked);
+      if (this.paintOneboxes) this._loadOneboxes();
       this._resolveUrls();
     });
   },
 
   @afterRender
+  _loadOneboxes() {
+    const refresh = false;
+
+    loadOneboxes(
+      this.element,
+      ajax,
+      this.topicId,
+      this.categoryId,
+      this.siteSettings.max_oneboxes_per_post,
+      refresh
+    );
+  },
+
+  @afterRender
   _resolveUrls() {
     resolveAllShortUrls(ajax, this.siteSettings, this.element, this.opts);
   },
diff --git a/app/assets/javascripts/discourse/app/lib/load-oneboxes.js b/app/assets/javascripts/discourse/app/lib/load-oneboxes.js
new file mode 100644
index 0000000..c07d6ab
--- /dev/null
+++ b/app/assets/javascripts/discourse/app/lib/load-oneboxes.js
@@ -0,0 +1,78 @@
+import { applyInlineOneboxes } from "pretty-text/inline-oneboxer";
+import { load, LOADING_ONEBOX_CSS_CLASS } from "pretty-text/oneboxer";
+
+export function loadOneboxes(
+  container,
+  ajax,
+  topicId,
+  categoryId,
+  maxOneboxes,
+  refresh
+) {
+  const oneboxes = {};
+  const inlineOneboxes = {};
+
+  // Oneboxes = `a.onebox` -> `a.onebox-loading` -> `aside.onebox`
+  // Inline Oneboxes = `a.inline-onebox-loading` -> `a.inline-onebox`
+
+  let loadedOneboxes = container.querySelectorAll(
+    `aside.onebox, a.${LOADING_ONEBOX_CSS_CLASS}, a.inline-onebox`
+  ).length;
+
+  container
+    .querySelectorAll(`a.onebox, a.inline-onebox-loading`)
+    .forEach((link) => {
+      const text = link.textContent;
+      const isInline = link.getAttribute("class") === "inline-onebox-loading";
+      const m = isInline ? inlineOneboxes : oneboxes;
+
+      if (loadedOneboxes < maxOneboxes) {
+        if (m[text] === undefined) {
+          m[text] = [];
+          loadedOneboxes++;
+        }
+        m[text].push(link);
+      } else {
+        if (m[text] !== undefined) {
+          m[text].push(link);
+        } else if (isInline) {
+          link.classList.remove("inline-onebox-loading");
+        }
+      }
+    });
+
+  let newBoxes = 0;
+
+  if (Object.keys(oneboxes).length > 0) {
+    _loadOneboxes(oneboxes, ajax, newBoxes, topicId, categoryId, refresh);
+  }
+
+  if (Object.keys(inlineOneboxes).length > 0) {
+    _loadInlineOneboxes(inlineOneboxes, ajax, topicId, categoryId);
+  }
+
+  return newBoxes;
+}
+
+function _loadInlineOneboxes(inline, ajax, topicId, categoryId) {
+  applyInlineOneboxes(inline, ajax, {
+    categoryId: topicId,
+    topicId: categoryId,
+  });
+}
+
+function _loadOneboxes(oneboxes, ajax, count, topicId, categoryId, refresh) {
+  Object.values(oneboxes).forEach((onebox) => {
+    onebox.forEach((o) => {
+      load({
+        elem: o,
+        refresh,
+        ajax,
+        categoryId: categoryId,
+        topicId: topicId,
+      });
+

[... diff too long, it was truncated ...]

GitHub sha: f85f73be

This commit appears in #10693 which was approved by eviltrout. It was merged by romanrizzi.