FEATURE: Support `[description|attachment](upload://<short-sha>)` in MD. (#7603)

FEATURE: Support [description|attachment](upload://<short-sha>) in MD. (#7603)

diff --git a/app/assets/javascripts/discourse/components/composer-editor.js.es6 b/app/assets/javascripts/discourse/components/composer-editor.js.es6
index a81565c..b637219 100644
--- a/app/assets/javascripts/discourse/components/composer-editor.js.es6
+++ b/app/assets/javascripts/discourse/components/composer-editor.js.es6
@@ -36,7 +36,7 @@ import {
 import {
   cacheShortUploadUrl,
   resolveAllShortUrls
-} from "pretty-text/image-short-url";
+} from "pretty-text/upload-short-url";
 
 import {
   INLINE_ONEBOX_LOADING_CSS_CLASS,
diff --git a/app/assets/javascripts/discourse/components/cook-text.js.es6 b/app/assets/javascripts/discourse/components/cook-text.js.es6
index 9fefced..3e345df 100644
--- a/app/assets/javascripts/discourse/components/cook-text.js.es6
+++ b/app/assets/javascripts/discourse/components/cook-text.js.es6
@@ -13,7 +13,7 @@ const CookText = Ember.Component.extend({
       // pretty text may only be loaded now
       Ember.run.next(() =>
         window
-          .requireModule("pretty-text/image-short-url")
+          .requireModule("pretty-text/upload-short-url")
           .resolveAllShortUrls(ajax)
       );
     });
diff --git a/app/assets/javascripts/discourse/lib/utilities.js.es6 b/app/assets/javascripts/discourse/lib/utilities.js.es6
index c022bfd..7c1e9a3 100644
--- a/app/assets/javascripts/discourse/lib/utilities.js.es6
+++ b/app/assets/javascripts/discourse/lib/utilities.js.es6
@@ -444,15 +444,9 @@ export function getUploadMarkdown(upload) {
   ) {
     return uploadLocation(upload.url);
   } else {
-    return (
-      '<a class="attachment" href="' +
-      upload.url +
-      '">' +
-      upload.original_filename +
-      "</a> (" +
-      I18n.toHumanSize(upload.filesize) +
-      ")\n"
-    );
+    return `[${upload.original_filename} (${I18n.toHumanSize(
+      upload.filesize
+    )})|attachment](${upload.short_url})`;
   }
 }
 
diff --git a/app/assets/javascripts/markdown-it-bundle.js b/app/assets/javascripts/markdown-it-bundle.js
index 6f88c5a..2d0ec14 100644
--- a/app/assets/javascripts/markdown-it-bundle.js
+++ b/app/assets/javascripts/markdown-it-bundle.js
@@ -14,6 +14,6 @@
 //= require ./pretty-text/engines/discourse-markdown/newline
 //= require ./pretty-text/engines/discourse-markdown/html-img
 //= require ./pretty-text/engines/discourse-markdown/text-post-process
-//= require ./pretty-text/engines/discourse-markdown/image-protocol
+//= require ./pretty-text/engines/discourse-markdown/upload-protocol
 //= require ./pretty-text/engines/discourse-markdown/inject-line-number
 //= require ./pretty-text/engines/discourse-markdown/d-wrap
diff --git a/app/assets/javascripts/pretty-text-bundle.js b/app/assets/javascripts/pretty-text-bundle.js
index ed5331b..23dc012 100644
--- a/app/assets/javascripts/pretty-text-bundle.js
+++ b/app/assets/javascripts/pretty-text-bundle.js
@@ -11,4 +11,4 @@
 //= require ./pretty-text/sanitizer
 //= require ./pretty-text/oneboxer
 //= require ./pretty-text/inline-oneboxer
-//= require ./pretty-text/image-short-url
+//= require ./pretty-text/upload-short-url
diff --git a/app/assets/javascripts/pretty-text/engines/discourse-markdown-it.js.es6 b/app/assets/javascripts/pretty-text/engines/discourse-markdown-it.js.es6
index 4e503d0..3c91bf0 100644
--- a/app/assets/javascripts/pretty-text/engines/discourse-markdown-it.js.es6
+++ b/app/assets/javascripts/pretty-text/engines/discourse-markdown-it.js.es6
@@ -1,6 +1,7 @@
 import { default as WhiteLister } from "pretty-text/white-lister";
 import { sanitize } from "pretty-text/sanitizer";
 import guid from "pretty-text/guid";
+import { ATTACHMENT_CSS_CLASS } from "pretty-text/upload-short-url";
 
 function deprecate(feature, name) {
   return function() {
@@ -187,6 +188,26 @@ function setupImageDimensions(md) {
   md.renderer.rules.image = renderImage;
 }
 
+function renderAttachment(tokens, idx, options, env, slf) {
+  const linkOpenToken = tokens[idx];
+  const linkTextToken = tokens[idx + 1];
+  const split = linkTextToken.content.split("|");
+  const isValid = !linkOpenToken.attrs[
+    linkOpenToken.attrIndex("data-orig-href")
+  ];
+
+  if (isValid && split.length === 2 && split[1] === ATTACHMENT_CSS_CLASS) {
+    linkOpenToken.attrs.unshift(["class", split[1]]);
+    linkTextToken.content = split[0];
+  }
+
+  return slf.renderToken(tokens, idx, options);
+}
+
+function setupAttachments(md) {
+  md.renderer.rules.link_open = renderAttachment;
+}
+
 let Helpers;
 
 export function setup(opts, siteSettings, state) {
@@ -276,6 +297,7 @@ export function setup(opts, siteSettings, state) {
   setupUrlDecoding(opts.engine);
   setupHoister(opts.engine);
   setupImageDimensions(opts.engine);
+  setupAttachments(opts.engine);
   setupBlockBBCode(opts.engine);
   setupInlineBBCode(opts.engine);
   setupTextPostProcessRuler(opts.engine);
diff --git a/app/assets/javascripts/pretty-text/engines/discourse-markdown/image-protocol.js.es6 b/app/assets/javascripts/pretty-text/engines/discourse-markdown/image-protocol.js.es6
deleted file mode 100644
index bdcfba4..0000000
--- a/app/assets/javascripts/pretty-text/engines/discourse-markdown/image-protocol.js.es6
+++ /dev/null
@@ -1,62 +0,0 @@
-// add image to array if src has an upload
-function addImage(images, token) {
-  if (token.attrs) {
-    for (let i = 0; i < token.attrs.length; i++) {
-      if (token.attrs[i][1].indexOf("upload://") === 0) {
-        images.push([token, i]);
-        break;
-      }
-    }
-  }
-}
-
-function rule(state) {
-  let images = [];
-
-  for (let i = 0; i < state.tokens.length; i++) {
-    let blockToken = state.tokens[i];
-
-    if (blockToken.tag === "img") {
-      addImage(images, blockToken);
-    }
-
-    if (!blockToken.children) {
-      continue;
-    }
-
-    for (let j = 0; j < blockToken.children.length; j++) {
-      let token = blockToken.children[j];
-      if (token.tag === "img") {
-        addImage(images, token);
-      }
-    }
-  }
-
-  if (images.length > 0) {
-    let srcList = images.map(([token, srcIndex]) => token.attrs[srcIndex][1]);
-    let lookup = state.md.options.discourse.lookupImageUrls;
-    let longUrls = (lookup && lookup(srcList)) || {};
-
-    images.forEach(([token, srcIndex]) => {
-      let origSrc = token.attrs[srcIndex][1];
-      let mapped = longUrls[origSrc];
-      if (mapped) {
-        token.attrs[srcIndex][1] = mapped;
-      } else {
-        token.attrs[srcIndex][1] = state.md.options.discourse.getURL(
-          "/images/transparent.png"
-        );
-        token.attrs.push(["data-orig-src", origSrc]);
-      }
-    });
-  }
-}
-
-export function setup(helper) {
-  const opts = helper.getOptions();
-  if (opts.previewing) helper.whiteList(["img.resizable"]);
-  helper.whiteList(["img[data-orig-src]"]);
-  helper.registerPlugin(md => {
-    md.core.ruler.push("image-protocol", rule);
-  });
-}
diff --git a/app/assets/javascripts/pretty-text/engines/discourse-markdown/upload-protocol.js.es6 b/app/assets/javascripts/pretty-text/engines/discourse-markdown/upload-protocol.js.es6
new file mode 100644
index 0000000..27cfb91
--- /dev/null
+++ b/app/assets/javascripts/pretty-text/engines/discourse-markdown/upload-protocol.js.es6
@@ -0,0 +1,81 @@
+// add image to array if src has an upload
+function addImage(uploads, token) {
+  if (token.attrs) {
+    for (let i = 0; i < token.attrs.length; i++) {
+      if (token.attrs[i][1].indexOf("upload://") === 0) {
+        uploads.push([token, i]);
+        break;
+      }
+    }
+  }
+}
+
+function rule(state) {
+  let uploads = [];
+
+  for (let i = 0; i < state.tokens.length; i++) {
+    let blockToken = state.tokens[i];
+
+    if (blockToken.tag === "img" || blockToken.tag === "a") {
+      addImage(uploads, blockToken);
+    }
+
+    if (!blockToken.children) {
+      continue;
+    }
+
+    for (let j = 0; j < blockToken.children.length; j++) {
+      let token = blockToken.children[j];
+      if (token.tag === "img" || token.tag === "a") {
+        addImage(uploads, token);
+      }
+    }
+  }
+
+  if (uploads.length > 0) {

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

GitHub sha: b1d3c678

Quick one @pmusaraj if you are around, does this create proper post upload records? Otherwise attachments will be off to tombstone

1 Like

It doesn’t look like it, I reset my local DB and now the post_uploads table is empty.

2 Likes

I recommend reverting temporarily so we don’t deploy this

1 Like

Temporarily revert "FEATURE: Support `[description|attachment](upload://<short-sha>)` in MD. (#7603)"

@SamSaffron Oops good catch. Fixed in FEATURE: Support `[description|attachment](upload://<short-sha>)` in MD take 2.

3 Likes