diff --git a/src/core/MString.js b/src/core/MString.js
index 9af28695..18a27a5c 100644
--- a/src/core/MString.js
+++ b/src/core/MString.js
@@ -106,10 +106,75 @@ export default class MString {
return (chr === ' ' || chr === '\t' || chr === '\n');
}
+ /*
+ * check if the current '[' is part of a [y](z) enclosure
+ * returns [y, z] if it is enclosure, null otherwise
+ * moves iter to last closing braked if it is enclosure
+ */
+ checkIfEnclosure(zIsLink) {
+ const yStart = this.iter + 1;
+
+ let yEnd = yStart;
+ while (this.txt[yEnd] !== ']') {
+ const chr = this.txt[yEnd];
+ if (yEnd >= this.txt.length
+ || chr === '\n'
+ || chr === '['
+ || chr === '('
+ ) {
+ return null;
+ }
+ yEnd += 1;
+ }
+
+ let zStart = yEnd + 1;
+ if (this.txt[zStart] !== '(') {
+ return null;
+ }
+ zStart += 1;
+
+ let zEnd = zStart;
+ let z = null;
+ while (this.txt[zEnd] !== ')') {
+ const chr = this.txt[zEnd];
+ if (zEnd >= this.txt.length
+ || chr === '\n'
+ || chr == '['
+ || chr == '('
+ ) {
+ return null;
+ }
+ if (zIsLink && chr === ':') {
+ // set this.iter temporarily to be able to use thischeckIfLink
+ const oldIter = this.iter;
+ this.iter = zEnd;
+ z = this.checkIfLink();
+ zEnd = this.iter;
+ this.iter = oldIter;
+ if (z === null) {
+ return null;
+ }
+ continue;
+ }
+ zEnd += 1;
+ }
+ if (zEnd < zStart + 1 || ( !z && zIsLink )) {
+ return null;
+ }
+
+ if (!zIsLink) {
+ z = this.txt.slice(zStart, zEnd);
+ }
+ const y = this.txt.slice(yStart, yEnd);
+
+ this.iter = zEnd;
+ return [y, z];
+ }
+
/*
* Convoluted way to check if the current ':' is part of a link
* we do not check for a 'http' because we might support application links
- * like telegram://... or discord://..
+ * like tg://... or discord://..
* returns the link or false if there is none
* moves iter forward to after the link, if there's one
*/
@@ -126,26 +191,14 @@ export default class MString {
linkStart += 1;
cIter += 3;
- /* just some most basic test */
- let dots = 0;
- let slashes = 0;
for (; cIter < this.txt.length
&& !MString.isWhiteSpace(this.txt[cIter])
&& this.txt[cIter] !== ')'; cIter += 1
- ) {
- if (this.txt[cIter] === '.') {
- if (slashes !== 0) {
- return null;
- }
- dots += 1;
- } else if (this.txt[cIter] === '/') {
- slashes += 1;
- }
- }
- if (!dots || (!slashes && this.txt[cIter - 1] === '.')) {
+ );
+ if (cIter < this.iter + 4) {
return null;
}
-
+
/* special case where someone pasted a http link after a text
* without space in between
*/
diff --git a/src/core/MarkdownParser.js b/src/core/MarkdownParser.js
index 272f72e5..16f86f5a 100644
--- a/src/core/MarkdownParser.js
+++ b/src/core/MarkdownParser.js
@@ -75,15 +75,45 @@ function parseMParagraph(text, opts, breakChar) {
* pure link
*/
const link = text.checkIfLink();
- if (link) {
+ if (link !== null) {
const startLink = text.iter - link.length;
if (pStart < startLink) {
pArray.push(text.slice(pStart, startLink));
}
- pArray.push(['l', link, link]);
+ pArray.push(['l', null, link]);
pStart = text.iter;
continue;
}
+ } else if (chr === '[') {
+ /*
+ * x[y](z) enclosure
+ */
+ let oldPos = text.iter;
+ let x = null;
+ if (text.iter > 0) {
+ text.move(-1);
+ x = text.getChar();
+ text.setIter(oldPos);
+ }
+ /*
+ * x decides what element it is
+ * defaults to ordinary link
+ */
+ let tag = 'l'
+ let zIsLink = true;
+ if (x === '!') {
+ tag = 'img';
+ oldPos -= 1;
+ }
+
+ const encArr = text.checkIfEnclosure(zIsLink);
+ if (encArr !== null) {
+ if (pStart < oldPos) {
+ pArray.push(text.slice(pStart, oldPos));
+ }
+ pArray.push([tag, encArr[0], encArr[1]]);
+ pStart = text.iter + 1;
+ }
}
text.moveForward();
diff --git a/utils/markdown-test/Markdown.jsx b/utils/markdown-test/Markdown.jsx
index 3bef6742..839be6f4 100644
--- a/utils/markdown-test/Markdown.jsx
+++ b/utils/markdown-test/Markdown.jsx
@@ -3,6 +3,34 @@
*/
import React from 'react';
+/*
+ * gets a descriptive text of the domain of the link
+ * Example:
+ * https://www.youtube.com/watch?v=G8APgeFfkAk returns 'youtube'
+ * http://www.google.at returns 'google.at'
+ * (www. and .com are split)
+ */
+function getLinkDesc(link) {
+ let domainStart = link.indexOf('://') + 3;
+ if (domainStart < 3) {
+ domainStart = 0;
+ }
+ if (link.startsWith('www.', domainStart)) {
+ domainStart += 4;
+ }
+ let domainEnd = link.indexOf('/', domainStart);
+ if (domainEnd === -1) {
+ domainEnd = link.length;
+ }
+ if (link.endsWith('.com', domainEnd)) {
+ domainEnd -= 4;
+ }
+ if (domainEnd <= domainStart) {
+ return link;
+ }
+ return link.slice(domainStart, domainEnd);
+}
+
const MarkdownParagraph = ({ pArray }) => pArray.map((part) => {
if (!Array.isArray(part)) {
return part;
@@ -35,19 +63,32 @@ const MarkdownParagraph = ({ pArray }) => pArray.map((part) => {
);
- case 'l':
+ case 'l': {
+ let title = getLinkDesc(part[2]);
+ if (part[1]) {
+ title += ` | ${part[1]}`;
+ }
return (
- {part[1]}
+ {title}
);
+ }
+ case 'img': {
+ let title = getLinkDesc(part[2]);
+ if (part[1]) {
+ title += ` | ${part[1]}`;
+ }
+ return (
+
+ );
+ }
default:
return type;
}
});
-const Markdown = ({ mdArray }) => {
- return mdArray.map((part) => {
+const Markdown = ({ mdArray }) => mdArray.map((part) => {
const type = part[0];
switch (type) {
/* Heading */
@@ -127,7 +168,7 @@ const Markdown = ({ mdArray }) => {
default:
return part[0];
}
-})};
+});
const MarkdownArticle = ({ mdArray }) => (
diff --git a/utils/markdown-test/README.md b/utils/markdown-test/README.md
index 14b01cba..138d37f0 100644
--- a/utils/markdown-test/README.md
+++ b/utils/markdown-test/README.md
@@ -1,3 +1,5 @@
# Markdown parser testing
Code to test markdown parsing, run `npx webpack` to build and open index.html
+
+No npm install in this folder neccessary, it takes the packages from the parent project
diff --git a/utils/markdown-test/webpack.config.js b/utils/markdown-test/webpack.config.js
index ac2e291d..0092ae76 100644
--- a/utils/markdown-test/webpack.config.js
+++ b/utils/markdown-test/webpack.config.js
@@ -22,7 +22,7 @@ var babelPlugins = [
module.exports = {
name: 'script',
target: 'web',
- mode: 'production',
+ mode: 'development',
entry: [ path.resolve(__dirname, './mdtest.js') ],