« get me outta code hell

hsmusic-wiki - HSMusic - static wiki software cataloguing collaborative creation
about summary refs log tree commit diff
path: root/src/content/dependencies/linkExternal.js
diff options
context:
space:
mode:
Diffstat (limited to 'src/content/dependencies/linkExternal.js')
-rw-r--r--src/content/dependencies/linkExternal.js118
1 files changed, 107 insertions, 11 deletions
diff --git a/src/content/dependencies/linkExternal.js b/src/content/dependencies/linkExternal.js
index ba2dbf2..f6b47db 100644
--- a/src/content/dependencies/linkExternal.js
+++ b/src/content/dependencies/linkExternal.js
@@ -6,12 +6,17 @@ export default {
   data: (url) => ({url}),
 
   slots: {
+    content: {
+      type: 'html',
+      mutable: false,
+    },
+
     style: {
       // This awkward syntax is because the slot descriptor validator can't
       // differentiate between a function that returns a validator (the usual
       // syntax) and a function that is itself a validator.
       validate: () => isExternalLinkStyle,
-      default: 'normal',
+      default: 'platform',
     },
 
     context: {
@@ -19,22 +24,113 @@ export default {
       default: 'generic',
     },
 
+    fromContent: {
+      type: 'boolean',
+      default: false,
+    },
+
+    indicateExternal: {
+      type: 'boolean',
+      default: false,
+    },
+
     tab: {
       validate: v => v.is('default', 'separate'),
       default: 'default',
     },
   },
 
-  generate: (data, slots, {html, language}) =>
-    html.tag('a',
-      {href: data.url},
-      {class: 'nowrap'},
+  generate(data, slots, {html, language}) {
+    let urlIsValid;
+    try {
+      new URL(data.url);
+      urlIsValid = true;
+    } catch (error) {
+      urlIsValid = false;
+    }
+
+    let formattedLink;
+    if (urlIsValid) {
+      formattedLink =
+        language.formatExternalLink(data.url, {
+          style: slots.style,
+          context: slots.context,
+        });
+
+      // Fall back to platform if nothing matched the desired style.
+      if (html.isBlank(formattedLink) && slots.style !== 'platform') {
+        formattedLink =
+          language.formatExternalLink(data.url, {
+            style: 'platform',
+            context: slots.context,
+          });
+      }
+    } else {
+      formattedLink = null;
+    }
 
-      slots.tab === 'separate' &&
-        {target: '_blank'},
+    const linkAttributes = html.attributes({
+      class: 'external-link',
+    });
 
-      language.formatExternalLink(data.url, {
-        style: slots.style,
-        context: slots.context,
-      })),
+    let linkContent;
+    if (urlIsValid) {
+      linkAttributes.set('href', data.url);
+
+      if (html.isBlank(slots.content)) {
+        linkContent = formattedLink;
+      } else {
+        linkContent = slots.content;
+      }
+    } else {
+      if (html.isBlank(slots.content)) {
+        linkContent =
+          html.tag('i',
+            language.$('misc.external.invalidURL.annotation'));
+      } else {
+        linkContent =
+          language.$('misc.external.invalidURL', {
+            link: slots.content,
+            annotation:
+              html.tag('i',
+                language.$('misc.external.invalidURL.annotation')),
+          });
+      }
+    }
+
+    if (slots.fromContent) {
+      linkAttributes.add('class', 'from-content');
+    }
+
+    if (urlIsValid && slots.indicateExternal) {
+      linkAttributes.add('class', 'indicate-external');
+
+      let titleText;
+      if (slots.tab === 'separate') {
+        if (html.isBlank(slots.content)) {
+          titleText =
+            language.$('misc.external.opensInNewTab.annotation');
+        } else {
+          titleText =
+            language.$('misc.external.opensInNewTab', {
+              link: formattedLink,
+              annotation:
+                language.$('misc.external.opensInNewTab.annotation'),
+            });
+        }
+      } else if (!html.isBlank(slots.content)) {
+        titleText = formattedLink;
+      }
+
+      if (titleText) {
+        linkAttributes.set('title', titleText.toString());
+      }
+    }
+
+    if (urlIsValid && slots.tab === 'separate') {
+      linkAttributes.set('target', '_blank');
+    }
+
+    return html.tag('a', linkAttributes, linkContent);
+  },
 };