aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorEugene Sokolov <eug-vs@keemail.me>2020-04-09 16:42:12 +0300
committerGitHub <noreply@github.com>2020-04-09 16:42:12 +0300
commitad42e742c04c8302c2bcaf67c07ef215bba04f3b (patch)
treeda29af275ec03232d81938e77c36d894c7093c2f
parentb808381b02097a25eb51b14246f7a239a785b347 (diff)
parentd1bcd3348c67cfbcd83178c9710cc54de9f776e8 (diff)
downloadreact-benzin-ad42e742c04c8302c2bcaf67c07ef215bba04f3b.tar.gz
Merge pull request #9 from eug-vs/md-improve
Markdown extensive features
-rw-r--r--src/lib/Markdown/Content.tsx22
-rw-r--r--src/lib/Markdown/Markdown.tsx12
-rw-r--r--src/lib/Markdown/Section.tsx8
-rw-r--r--src/lib/Markdown/SyntacticSpan.tsx7
4 files changed, 36 insertions, 13 deletions
diff --git a/src/lib/Markdown/Content.tsx b/src/lib/Markdown/Content.tsx
index aaea100..5816214 100644
--- a/src/lib/Markdown/Content.tsx
+++ b/src/lib/Markdown/Content.tsx
@@ -6,11 +6,10 @@ import { ParserPropTypes } from './types';
const denotesCodeBlock = (line: string): boolean => {
- return line.match(/^```.*$/) !== null;
-}
+ return line.match(/^\s*```.*$/) !== null; }
const denotesDottedList = (line: string): boolean => {
- return line.match(/^ ?- .*$/) !== null;
+ return line.match(/^ ?[-*] .*$/) !== null;
}
const denotesOpenHtml= (line: string): string => {
@@ -29,6 +28,10 @@ const denotesSelfClosingHtml = (line: string): string[] | null => {
return line.match(regex);
}
+const declaresNoLineBreak = (line: string): boolean => {
+ return line.match(/\\\|$/) !== null;
+}
+
const Content: React.FC<ParserPropTypes> = ({ rawLines }) => {
if (!rawLines.length) return null;
@@ -46,14 +49,13 @@ const Content: React.FC<ParserPropTypes> = ({ rawLines }) => {
buffer = <ul>{dottedListLines.map(li => <li><Text line={li.slice(2)} /></li>)}</ul>;
} else if ((buffer = denotesOpenHtml(line))) {
const tag = buffer;
- const closeIndex = rawLines.findIndex(line => denotesClosingHtml(line, tag));
- const htmlLines = rawLines.splice(0, closeIndex + 1).slice(0, closeIndex);
+ const closeIndex = denotesClosingHtml(line, tag) ? -1 : rawLines.findIndex(line => denotesClosingHtml(line, tag));
+ const htmlLines = rawLines.splice(0, closeIndex + 1);
htmlLines.unshift(line);
buffer = <div dangerouslySetInnerHTML={{ __html: htmlLines.join('\n') }}></div>;
} else if ((buffer = denotesSelfClosingHtml(line)) !== null) {
const match = buffer[0];
const [before, after] = line.split(match);
- console.log({ line, match, before, after});
buffer = (
<>
<Text line={before} />
@@ -61,6 +63,14 @@ const Content: React.FC<ParserPropTypes> = ({ rawLines }) => {
<Text line={after} />
</>
);
+ } else if (declaresNoLineBreak(line)) {
+ const closeIndex = rawLines.findIndex(line => !declaresNoLineBreak(line));
+ const lineBreakLines = rawLines.splice(0, closeIndex).map(line => line.slice(0, -2));
+ lineBreakLines.unshift(line.slice(0, -2));
+ lineBreakLines.push(rawLines.splice(0, 1)[0]);
+ buffer = <p>{lineBreakLines.map(lineBreakLine => <Text line={lineBreakLine} />)}</p>;
+ } else if (denotesClosingHtml(line, '')) {
+ buffer = null;
} else {
buffer = <p><Text line={line} /></p>
}
diff --git a/src/lib/Markdown/Markdown.tsx b/src/lib/Markdown/Markdown.tsx
index 09ad54a..82e889c 100644
--- a/src/lib/Markdown/Markdown.tsx
+++ b/src/lib/Markdown/Markdown.tsx
@@ -8,15 +8,23 @@ interface PropTypes {
url?: string;
}
+const resolveUrls = (line: string, baseUrl: string): string => {
+ return line.replace(/src="(?!http)(.*)"[\s>]/, (match, url, offset, string) => `src="${baseUrl}/${url}?sanitize=true"`)
+ .replace(/\[(.*\]?.*)\]\((?!http)(.+?)\)/, (match, text, url, offset, string) => `[${text}](${baseUrl}/${url})`);
+}
+
const Markdown: React.FC<PropTypes> = ({ data, url }) => {
const [markdown, setMarkdown] = useState<string>(data || '');
+ if (url) axios.get(url).then(response => setMarkdown(response.data));
+
useEffect(() => {
if (!url) setMarkdown(data || '');
}, [data, url]);
- if (url) axios.get(url).then(response => setMarkdown(response.data));
- return <Section rawLines={markdown.split('\n')} />
+ const baseUrl = url?.slice(0, url.lastIndexOf('/')) || '';
+ const lines = markdown.split(/\r?\n/).map(line => resolveUrls(line, baseUrl));
+ return <Section rawLines={lines} />
};
diff --git a/src/lib/Markdown/Section.tsx b/src/lib/Markdown/Section.tsx
index 5ce8954..1fcc46f 100644
--- a/src/lib/Markdown/Section.tsx
+++ b/src/lib/Markdown/Section.tsx
@@ -1,5 +1,6 @@
import React from 'react';
import ContentSection from '../ContentSection/ContentSection';
+import { Typography } from '@material-ui/core';
import Content from './Content';
import { ParserPropTypes } from './types';
@@ -30,7 +31,12 @@ const Section: React.FC<PropTypes> = ({ rawLines, level = 0 }) => {
const deeperLevelIndex = rawLines.findIndex(line => line.match(`^#{${level + 1},} .*$`));
const rawContent = rawLines.splice(0, (deeperLevelIndex < 0) ? rawLines.length : deeperLevelIndex);
- if (!level) return <ChildrenSections rawLines={rawLines} level={getHeaderLevel(rawLines[0])}/>;
+ if (!level) return (
+ <>
+ <Typography> <Content rawLines={rawContent} /> </Typography>
+ <ChildrenSections rawLines={rawLines} level={getHeaderLevel(rawLines[0])}/>
+ </>
+ )
const sectionName = rawContent.splice(0, 1)[0].slice(level).trim();
const deeperLevel = getHeaderLevel(rawLines[0]);
diff --git a/src/lib/Markdown/SyntacticSpan.tsx b/src/lib/Markdown/SyntacticSpan.tsx
index 299bf87..f3c2125 100644
--- a/src/lib/Markdown/SyntacticSpan.tsx
+++ b/src/lib/Markdown/SyntacticSpan.tsx
@@ -24,8 +24,8 @@ const enclosureRegex = (e: string): RegexPair => ({
const regex: Record<string, RegexPair> = {
conceal: {
- global: /(!?\[.+?\]\(.+?\))/g,
- local: /!?\[(.+?)\]\((.+?)\)/
+ global: /(!?\[.+?\]\(.+?\))(?!])/g,
+ local: /!?\[(.*\]?.*)\]\((.+?)\)/
},
rawLink: {
global: /((?:(?:[A-Za-z]{3,9}:(?:\/\/)?)(?:[-;:&=+$,\w]+@)?[A-Za-z0-9.-]+|(?:www\.|[-;:&=+$,\w]+@)[A-Za-z0-9.-]+)(?:(?:\/[+~%/.\w-_]*)?\??(?:[-+=&;%@.\w_]*)#?(?:[.!/\\\w]*))?)/,
@@ -42,7 +42,6 @@ const splitter = new RegExp(Object.values(regex).map(pair => pair.global.source)
const emojiList: Emoji[] = [];
Object.keys(emojiLib).forEach(name => emojiList.push({ name, char: emojiLib[name].char }));
-console.log({emojiList})
const useStyles = makeStyles(theme => ({
code: {
@@ -64,7 +63,7 @@ const SyntacticSpan: React.FC<PropTypes> = ({ span }) => {
const matchConceal = regex.conceal.local.exec(span);
if (matchConceal) {
if (span[0] === '!') return <img src={matchConceal[2]} alt={matchConceal[1]} className={classes.image} />;
- return <Link href={matchConceal[2]}>{matchConceal[1]}</Link>;
+ return <Link href={matchConceal[2]}><SyntacticSpan span={matchConceal[1]} /></Link>;
}
const matchEmoji = span.match(regex.emoji.local);