FEATURE: always insert images on new lines and add newline after (#12895)

FEATURE: always insert images on new lines and add newline after (#12895)

diff --git a/app/assets/javascripts/discourse/app/components/composer-editor.js b/app/assets/javascripts/discourse/app/components/composer-editor.js
index a50aee0..d110191 100644
--- a/app/assets/javascripts/discourse/app/components/composer-editor.js
+++ b/app/assets/javascripts/discourse/app/components/composer-editor.js
@@ -73,7 +73,13 @@ export default Component.extend({
     const filename = uploadFilenamePlaceholder
       ? uploadFilenamePlaceholder
       : clipboard;
-    return `[${I18n.t("uploading_filename", { filename })}]() `;
+
+    let placeholder = `[${I18n.t("uploading_filename", { filename })}]()\n`;
+    if (!this._cursorIsOnEmptyLine()) {
+      placeholder = `\n${placeholder}`;
+    }
+
+    return placeholder;
   },
 
   @discourseComputed("composer.requiredCategoryMissing")
@@ -888,6 +894,18 @@ export default Component.extend({
     return element.tagName === "ASIDE" && element.classList.contains("quote");
   },
 
+  _cursorIsOnEmptyLine() {
+    const textArea = this.element.querySelector(".d-editor-input");
+    const selectionStart = textArea.selectionStart;
+    if (selectionStart === 0) {
+      return true;
+    } else if (textArea.value.charAt(selectionStart - 1) === "\n") {
+      return true;
+    } else {
+      return false;
+    }
+  },
+
   actions: {
     importQuote(toolbarEvent) {
       this.importQuote(toolbarEvent);
diff --git a/app/assets/javascripts/discourse/tests/acceptance/composer-attachment-test.js b/app/assets/javascripts/discourse/tests/acceptance/composer-attachment-test.js
index 51e7b18..1413cd5 100644
--- a/app/assets/javascripts/discourse/tests/acceptance/composer-attachment-test.js
+++ b/app/assets/javascripts/discourse/tests/acceptance/composer-attachment-test.js
@@ -1,4 +1,8 @@
-import { acceptance, queryAll } from "discourse/tests/helpers/qunit-helpers";
+import {
+  acceptance,
+  query,
+  queryAll,
+} from "discourse/tests/helpers/qunit-helpers";
 import { click, fillIn, visit } from "@ember/test-helpers";
 import { test } from "qunit";
 
@@ -28,7 +32,7 @@ async function writeInComposer(assert) {
   await fillIn(".d-editor-input", "[test|attachment](upload://asdsad.png)");
 }
 
-acceptance("Composer Attachment", function (needs) {
+acceptance("Composer Attachment - Cooking", function (needs) {
   needs.user();
   needs.pretender(pretender);
 
@@ -54,3 +58,198 @@ acceptance("Composer Attachment - Secure Media Enabled", function (needs) {
     );
   });
 });
+
+acceptance("Composer Attachment - Upload Placeholder", function (needs) {
+  needs.user();
+
+  test("should insert a newline before and after an image when pasting into an empty composer", async function (assert) {
+    await visit("/");
+    await click("#create-topic");
+    const image = createImage("avatar.png", "/images/avatar.png?1", 200, 300);
+
+    await queryAll(".wmd-controls").trigger("fileuploadsend", image);
+    assert.equal(
+      queryAll(".d-editor-input").val(),
+      "[Uploading: avatar.png...]()\n"
+    );
+
+    await queryAll(".wmd-controls").trigger("fileuploaddone", image);
+    assert.equal(
+      queryAll(".d-editor-input").val(),
+      "![avatar|200x300](/images/avatar.png?1)\n"
+    );
+  });
+
+  test("should insert a newline after an image when pasting into a blank line", async function (assert) {
+    await visit("/");
+    await click("#create-topic");
+    await fillIn(".d-editor-input", "The image:\n");
+
+    const image = createImage("avatar.png", "/images/avatar.png?1", 200, 300);
+    await queryAll(".wmd-controls").trigger("fileuploadsend", image);
+
+    assert.equal(
+      queryAll(".d-editor-input").val(),
+      "The image:\n[Uploading: avatar.png...]()\n"
+    );
+
+    await queryAll(".wmd-controls").trigger("fileuploaddone", image);
+    assert.equal(
+      queryAll(".d-editor-input").val(),
+      "The image:\n![avatar|200x300](/images/avatar.png?1)\n"
+    );
+  });
+
+  test("should insert a newline before and after an image when pasting into a non blank line", async function (assert) {
+    await visit("/");
+    await click("#create-topic");
+    await fillIn(".d-editor-input", "The image:");
+
+    const image = createImage("avatar.png", "/images/avatar.png?1", 200, 300);
+    await queryAll(".wmd-controls").trigger("fileuploadsend", image);
+
+    assert.equal(
+      queryAll(".d-editor-input").val(),
+      "The image:\n[Uploading: avatar.png...]()\n"
+    );
+
+    await queryAll(".wmd-controls").trigger("fileuploaddone", image);
+    assert.equal(
+      queryAll(".d-editor-input").val(),
+      "The image:\n![avatar|200x300](/images/avatar.png?1)\n"
+    );
+  });
+
+  test("should insert a newline before and after an image when pasting with cursor in the middle of the line", async function (assert) {
+    await visit("/");
+    await click("#create-topic");
+    await fillIn(".d-editor-input", "The image Text after the image.");
+    const textArea = query(".d-editor-input");
+    textArea.selectionStart = 10;
+    textArea.selectionEnd = 10;
+
+    const image = createImage("avatar.png", "/images/avatar.png?1", 200, 300);
+    await queryAll(".wmd-controls").trigger("fileuploadsend", image);
+
+    assert.equal(
+      queryAll(".d-editor-input").val(),
+      "The image \n[Uploading: avatar.png...]()\nText after the image."
+    );
+
+    await queryAll(".wmd-controls").trigger("fileuploaddone", image);
+    assert.equal(
+      queryAll(".d-editor-input").val(),
+      "The image \n![avatar|200x300](/images/avatar.png?1)\nText after the image."
+    );
+  });
+
+  test("should insert a newline before and after an image when pasting with text selected", async function (assert) {
+    await visit("/");
+    await click("#create-topic");
+    const image = createImage("avatar.png", "/images/avatar.png?1", 200, 300);
+    await fillIn(
+      ".d-editor-input",
+      "The image [paste here] Text after the image."
+    );
+    const textArea = query(".d-editor-input");
+    textArea.selectionStart = 10;
+    textArea.selectionEnd = 23;
+
+    await queryAll(".wmd-controls").trigger("fileuploadsend", image);
+    assert.equal(
+      queryAll(".d-editor-input").val(),
+      "The image \n[Uploading: avatar.png...]()\n Text after the image."
+    );
+
+    await queryAll(".wmd-controls").trigger("fileuploaddone", image);
+    assert.equal(
+      queryAll(".d-editor-input").val(),
+      "The image \n![avatar|200x300](/images/avatar.png?1)\n Text after the image."
+    );
+  });
+
+  test("pasting several images", async function (assert) {
+    await visit("/");
+    await click("#create-topic");
+
+    const image1 = createImage("test.png", "/images/avatar.png?1", 200, 300);
+    const image2 = createImage("test.png", "/images/avatar.png?2", 100, 200);
+    const image3 = createImage("image.png", "/images/avatar.png?3", 300, 400);
+    const image4 = createImage("image.png", "/images/avatar.png?4", 300, 400);
+
+    await queryAll(".wmd-controls").trigger("fileuploadsend", image1);
+    assert.equal(
+      queryAll(".d-editor-input").val(),
+      "[Uploading: test.png...]()\n"
+    );
+
+    await queryAll(".wmd-controls").trigger("fileuploadsend", image2);
+    assert.equal(
+      queryAll(".d-editor-input").val(),
+      "[Uploading: test.png...]()\n[Uploading: test.png(1)...]()\n"
+    );
+
+    await queryAll(".wmd-controls").trigger("fileuploadsend", image4);
+    assert.equal(
+      queryAll(".d-editor-input").val(),
+      "[Uploading: test.png...]()\n[Uploading: test.png(1)...]()\n[Uploading: image.png...]()\n"
+    );
+
+    await queryAll(".wmd-controls").trigger("fileuploadsend", image3);
+    assert.equal(
+      queryAll(".d-editor-input").val(),
+      "[Uploading: test.png...]()\n[Uploading: test.png(1)...]()\n[Uploading: image.png...]()\n[Uploading: image.png(1)...]()\n"
+    );
+
+    await queryAll(".wmd-controls").trigger("fileuploaddone", image2);
+    assert.equal(
+      queryAll(".d-editor-input").val(),

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

GitHub sha: d3b05f8a

This commit appears in #12895 which was approved by eviltrout. It was merged by AndrewPrigorshnev.