UX: pasting links on a selection will apply a link format

UX: pasting links on a selection will apply a link format

diff --git a/app/assets/javascripts/discourse/app/mixins/textarea-text-manipulation.js b/app/assets/javascripts/discourse/app/mixins/textarea-text-manipulation.js
index 0256352..7e59a34 100644
--- a/app/assets/javascripts/discourse/app/mixins/textarea-text-manipulation.js
+++ b/app/assets/javascripts/discourse/app/mixins/textarea-text-manipulation.js
@@ -242,7 +242,8 @@ export default Mixin.create({
     let html = clipboard.getData("text/html");
     let handled = false;
 
-    const { pre, lineVal } = this._getSelected(null, { lineVal: true });
+    const selected = this._getSelected(null, { lineVal: true });
+    const { pre, value: selectedValue, lineVal } = selected;
     const isInlinePasting = pre.match(/[^\n]$/);
     const isCodeBlock = isInside(pre, /(^|\n)`‍``/g);
 
@@ -272,6 +273,19 @@ export default Mixin.create({
       }
     }
 
+    if (plainText && !handled && selected.end > selected.start) {
+      let isURL;
+      try {
+        isURL = !!new URL(plainText);
+      } catch {
+        isURL = false;
+      }
+      if (isURL) {
+        this._addText(selected, `[${selectedValue}](${plainText})`);
+        handled = true;
+      }
+    }
+
     if (canPasteHtml && !handled) {
       let markdown = toMarkdown(html);
 
diff --git a/app/assets/javascripts/discourse/tests/integration/components/d-editor-test.js b/app/assets/javascripts/discourse/tests/integration/components/d-editor-test.js
index aa37f57..3b090b1 100644
--- a/app/assets/javascripts/discourse/tests/integration/components/d-editor-test.js
+++ b/app/assets/javascripts/discourse/tests/integration/components/d-editor-test.js
@@ -729,10 +729,11 @@ third line`
   });
 
   async function paste(element, text) {
-    let e = new Event("paste");
+    let e = new Event("paste", { cancelable: true });
     e.clipboardData = { getData: () => text };
     element.dispatchEvent(e);
     await settled();
+    return e;
   }
 
   componentTest("paste table", {
@@ -763,6 +764,47 @@ third line`
     },
   });
 
+  testCase(
+    `pasting a link into a selection applies a link format`,
+    async function (assert, textarea) {
+      this.set("value", "See discourse in action");
+      setTextareaSelection(textarea, 4, 13);
+      const element = query(".d-editor");
+      const event = await paste(element, "https://www.discourse.org/");
+      assert.strictEqual(
+        this.value,
+        "See [discourse](https://www.discourse.org/) in action"
+      );
+      assert.strictEqual(event.defaultPrevented, true);
+    }
+  );
+
+  testCase(
+    `pasting other text into a selection will replace text value`,
+    async function (assert, textarea) {
+      this.set("value", "good morning");
+      setTextareaSelection(textarea, 5, 12);
+      const element = query(".d-editor");
+      const event = await paste(element, "evening");
+      // Synthetic paste events do not manipulate document content.
+      assert.strictEqual(this.value, "good morning");
+      assert.strictEqual(event.defaultPrevented, false);
+    }
+  );
+
+  testCase(
+    `pasting a url without a selection will insert the url`,
+    async function (assert, textarea) {
+      this.set("value", "a link example:");
+      jumpEnd(textarea);
+      const element = query(".d-editor");
+      const event = await paste(element, "https://www.discourse.org/");
+      // Synthetic paste events do not manipulate document content.
+      assert.strictEqual(this.value, "a link example:");
+      assert.strictEqual(event.defaultPrevented, false);
+    }
+  );
+
   (() => {
     // Tests to check cursor/selection after replace-text event.
     const BEFORE = "red green blue";

GitHub sha: 0009498901ee43bd9b7c7ca6d3c4f1e93628a164

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