#244 Only load auto links in viewer to prevent them from being hardcoded in editor
authorAdam Dullage <redacted>
Tue, 1 Apr 2025 19:39:28 +0000 (20:39 +0100)
committerAdam Dullage <redacted>
Tue, 1 Apr 2025 19:39:28 +0000 (20:39 +0100)
client/components/toastui/ToastViewer.vue
client/components/toastui/baseOptions.js
client/components/toastui/extendedAutolinks.js [new file with mode: 0644]

index 7a12c31011c294427a0b5a0114a9112db0d3c26a..7a3bd138642c31d919fc042ece61c9a3aee940bb 100644 (file)
@@ -7,6 +7,7 @@ import Viewer from "@toast-ui/editor/dist/toastui-editor-viewer";
 import { onMounted, ref } from "vue";
 
 import baseOptions from "./baseOptions.js";
+import extendedAutolinks from "./extendedAutolinks.js";
 
 const props = defineProps({
   initialValue: String,
@@ -17,6 +18,7 @@ const viewerElement = ref();
 onMounted(() => {
   new Viewer({
     ...baseOptions,
+    extendedAutolinks,
     el: viewerElement.value,
     initialValue: props.initialValue,
   });
index c4c96af7c9593a669f71f02223a4f4dfb9ca12f9..89517ed5525b158b77757622130bcd51b1ea64a7 100644 (file)
@@ -1,103 +1,6 @@
 import codeSyntaxHighlight from "@toast-ui/editor-plugin-code-syntax-highlight/dist/toastui-editor-plugin-code-syntax-highlight-all.js";
 import router from "../../router.js";
 
-/*
- * Sourced from toast-ui. Their autolink options are
- * either override their built in functionality or
- * use their built in functionality. We'd like to have
- * both so this is the source of their parsers.
- */
-const DOMAIN = "(?:[w-]+.)*[A-Za-z0-9-]+.[A-Za-z0-9-]+";
-const PATH = "[^<\\s]*[^<?!.,:*_?~\\s]";
-const EMAIL = "[\\w.+-]+@(?:[\\w-]+\\.)+[\\w-]+";
-function trimUnmatchedTrailingParens(source) {
-  const trailingParen = /\)+$/.exec(source);
-  if (trailingParen) {
-    let count = 0;
-    for (const ch of source) {
-      if (ch === "(") {
-        if (count < 0) {
-          count = 1;
-        } else {
-          count += 1;
-        }
-      } else if (ch === ")") {
-        count -= 1;
-      }
-    }
-
-    if (count < 0) {
-      const trimCount = Math.min(-count, trailingParen[0].length);
-      return source.substring(0, source.length - trimCount);
-    }
-  }
-  return source;
-}
-
-function trimTrailingEntity(source) {
-  return source.replace(/&[A-Za-z0-9]+;$/, "");
-}
-export function parseEmailLink(source) {
-  const reEmailLink = new RegExp(EMAIL, "g");
-  const result = [];
-  let m;
-  while ((m = reEmailLink.exec(source))) {
-    const text = m[0];
-    if (!/[_-]+$/.test(text)) {
-      result.push({
-        text,
-        range: [m.index, m.index + text.length - 1],
-        url: `mailto:${text}`,
-      });
-    }
-  }
-
-  return result;
-}
-
-export function parseUrlLink(source) {
-  const reWwwAutolink = new RegExp(`(www|https?://)\.${DOMAIN}${PATH}`, "g");
-  const result = [];
-  let m;
-
-  while ((m = reWwwAutolink.exec(source))) {
-    const text = trimTrailingEntity(trimUnmatchedTrailingParens(m[0]));
-    const scheme = m[1] === "www" ? "http://" : "";
-    result.push({
-      text,
-      range: [m.index, m.index + text.length - 1],
-      url: `${scheme}${text}`,
-    });
-  }
-
-  return result;
-}
-// end of raw toast-ui source
-
-function parseWikiLink(source) {
-  const matched = source.matchAll(/\[\[(.*?)\]\]/g);
-  if (matched) {
-    return Array.from(matched).map((match) => {
-      const text = match[1];
-      return {
-        text,
-        url: `${router.resolve({ name: "note", params: { title: text.trim() } }).href}`,
-        range: [match.index, match.index + match[0].length - 1],
-      };
-    });
-  }
-
-  return null;
-}
-
-function extendedAutolinks(source) {
-  return [
-    ...parseUrlLink(source),
-    ...parseEmailLink(source),
-    ...parseWikiLink(source),
-  ].sort((a, b) => a.range[0] - b.range[0]);
-}
-
 const customHTMLRenderer = {
   // Add id attribute to headings
   heading(node, { entering, getChildrenText, origin }) {
@@ -135,7 +38,6 @@ const baseOptions = {
   plugins: [codeSyntaxHighlight],
   customHTMLRenderer: customHTMLRenderer,
   usageStatistics: false,
-  extendedAutolinks,
 };
 
 export default baseOptions;
diff --git a/client/components/toastui/extendedAutolinks.js b/client/components/toastui/extendedAutolinks.js
new file mode 100644 (file)
index 0000000..453c031
--- /dev/null
@@ -0,0 +1,100 @@
+import router from "../../router.js";
+
+/*
+ * Sourced from toast-ui. Their autolink options are
+ * either override their built in functionality or
+ * use their built in functionality. We'd like to have
+ * both so this is the source of their parsers.
+ */
+const DOMAIN = "(?:[w-]+.)*[A-Za-z0-9-]+.[A-Za-z0-9-]+";
+const PATH = "[^<\\s]*[^<?!.,:*_?~\\s]";
+const EMAIL = "[\\w.+-]+@(?:[\\w-]+\\.)+[\\w-]+";
+function trimUnmatchedTrailingParens(source) {
+  const trailingParen = /\)+$/.exec(source);
+  if (trailingParen) {
+    let count = 0;
+    for (const ch of source) {
+      if (ch === "(") {
+        if (count < 0) {
+          count = 1;
+        } else {
+          count += 1;
+        }
+      } else if (ch === ")") {
+        count -= 1;
+      }
+    }
+
+    if (count < 0) {
+      const trimCount = Math.min(-count, trailingParen[0].length);
+      return source.substring(0, source.length - trimCount);
+    }
+  }
+  return source;
+}
+
+function trimTrailingEntity(source) {
+  return source.replace(/&[A-Za-z0-9]+;$/, "");
+}
+export function parseEmailLink(source) {
+  const reEmailLink = new RegExp(EMAIL, "g");
+  const result = [];
+  let m;
+  while ((m = reEmailLink.exec(source))) {
+    const text = m[0];
+    if (!/[_-]+$/.test(text)) {
+      result.push({
+        text,
+        range: [m.index, m.index + text.length - 1],
+        url: `mailto:${text}`,
+      });
+    }
+  }
+
+  return result;
+}
+
+export function parseUrlLink(source) {
+  const reWwwAutolink = new RegExp(`(www|https?://)\.${DOMAIN}${PATH}`, "g");
+  const result = [];
+  let m;
+
+  while ((m = reWwwAutolink.exec(source))) {
+    const text = trimTrailingEntity(trimUnmatchedTrailingParens(m[0]));
+    const scheme = m[1] === "www" ? "http://" : "";
+    result.push({
+      text,
+      range: [m.index, m.index + text.length - 1],
+      url: `${scheme}${text}`,
+    });
+  }
+
+  return result;
+}
+// end of raw toast-ui source
+
+function parseWikiLink(source) {
+  const matched = source.matchAll(/\[\[(.*?)\]\]/g);
+  if (matched) {
+    return Array.from(matched).map((match) => {
+      const text = match[1];
+      return {
+        text,
+        range: [match.index, match.index + match[0].length - 1],
+        url: `${router.resolve({ name: "note", params: { title: text.trim() } }).href}`,
+      };
+    });
+  }
+
+  return null;
+}
+
+function extendedAutolinks(source) {
+  return [
+    ...parseUrlLink(source),
+    ...parseEmailLink(source),
+    ...parseWikiLink(source),
+  ].sort((a, b) => a.range[0] - b.range[0]);
+}
+
+export default extendedAutolinks;
git clone https://git.99rst.org/PROJECT