]> git.localhorst.tv Git - alttp.git/commitdiff
short circuit tech links
authorDaniel Karbach <daniel.karbach@localhorst.tv>
Wed, 4 Jan 2023 14:29:38 +0000 (15:29 +0100)
committerDaniel Karbach <daniel.karbach@localhorst.tv>
Wed, 4 Jan 2023 14:29:38 +0000 (15:29 +0100)
resources/js/components/common/RawHTML.js [new file with mode: 0644]
resources/js/components/techniques/Detail.js

diff --git a/resources/js/components/common/RawHTML.js b/resources/js/components/common/RawHTML.js
new file mode 100644 (file)
index 0000000..fb0b51e
--- /dev/null
@@ -0,0 +1,48 @@
+import PropTypes from 'prop-types';
+import React from 'react';
+import { useNavigate } from 'react-router-dom';
+
+const RawHTML = ({ html }) => {
+       const navigate = useNavigate();
+
+       const onClick = e => {
+               if (e.defaultPrevented) return;
+               if (e.metaKey || e.ctrlKey || e.shiftKey) return;
+               if (e.button !== 0) return;
+
+               let el = e.target;
+               while (el && el.nodeName !== 'A') {
+                       el = el.parentNode;
+               }
+               if (!el) return;
+
+               if (el.target && el.target !== '_self') return;
+               if (el.attributes.download) return;
+               if (el.rel && /(?:^|\s+)external(?:\s+|$)/.test(el.rel)) return;
+
+               const href = el.getAttribute('href');
+
+               if (href.startsWith('#')) return;
+               if (href.startsWith('http')) return;
+               if (href.startsWith('mailto')) return;
+               if (href.startsWith('tel')) return;
+
+               el.blur();
+               e.preventDefault();
+
+               setTimeout(() => {
+                       // scroll to top on location change
+                       scrollTo({ top: 0, behavior: 'smooth' });
+               }, 50);
+
+               navigate(href);
+       };
+
+       return <div onClick={onClick} dangerouslySetInnerHTML={{ __html: html }} />;
+};
+
+RawHTML.propTypes = {
+       html: PropTypes.string,
+};
+
+export default RawHTML;
index d955397399668d86d2d030f01c9cb2de8fb6d3b0..303921c4c919245ed5c66da8e1a7f4357d976705 100644 (file)
@@ -4,15 +4,14 @@ import { Container } from 'react-bootstrap';
 import { withTranslation } from 'react-i18next';
 
 import Outline from './Outline';
+import RawHTML from '../common/RawHTML';
 import { getTranslation } from '../../helpers/Technique';
 import i18n from '../../i18n';
 
 const Detail = ({ technique }) => <Container as="article">
        <h1>{getTranslation(technique, 'title', i18n.language)}</h1>
        <Outline technique={technique} />
-       <div dangerouslySetInnerHTML={{
-               __html: getTranslation(technique, 'description', i18n.language),
-       }} />
+       <RawHTML html={getTranslation(technique, 'description', i18n.language)} />
        {technique.chapters ? technique.chapters.map(chapter =>
                <section id={`c${chapter.id}`} key={`c${chapter.id}`}>
                        {chapter.pivot.level ?
@@ -22,9 +21,7 @@ const Detail = ({ technique }) => <Container as="article">
                                        getTranslation(chapter, 'title', i18n.language),
                                )
                        : null}
-                       <div dangerouslySetInnerHTML={{
-                               __html: getTranslation(chapter, 'description', i18n.language),
-                       }} />
+                       <RawHTML html={getTranslation(chapter, 'description', i18n.language)} />
                </section>
        ) : null}
 </Container>;