summaryrefslogtreecommitdiff
path: root/src/mfm/html.ts
diff options
context:
space:
mode:
authorsyuilo <Syuilotan@yahoo.co.jp>2018-11-21 05:11:00 +0900
committerGitHub <noreply@github.com>2018-11-21 05:11:00 +0900
commit79ffbf95db9d0cc019d06ab93b1bfa6ba0d4f9ae (patch)
tree884a18e6735f8557eb392929fcfa2dc1ae09cb6d /src/mfm/html.ts
parentRefactor checkMongoDb (#3339) (diff)
downloadmisskey-79ffbf95db9d0cc019d06ab93b1bfa6ba0d4f9ae.tar.gz
misskey-79ffbf95db9d0cc019d06ab93b1bfa6ba0d4f9ae.tar.bz2
misskey-79ffbf95db9d0cc019d06ab93b1bfa6ba0d4f9ae.zip
Improve MFM parser (#3337)
* wip * wip * Refactor * Refactor * wip * wip * wip * wip * Refactor * Refactor * wip * wip * wip * wip * wip * wip * wip * wip * wip * wip * wip * wip * wip * wip * wip * wip * wip * wip * wip * Clean up * Update misskey-flavored-markdown.ts * wip * wip * wip * wip * Update parser.ts * wip * Add new test * wip * Add new test * Add new test * wip * Refactor * Update parse.ts * Refactor * Update parser.ts * wip
Diffstat (limited to 'src/mfm/html.ts')
-rw-r--r--src/mfm/html.ts212
1 files changed, 110 insertions, 102 deletions
diff --git a/src/mfm/html.ts b/src/mfm/html.ts
index cb7c7e2855..d45cc13af4 100644
--- a/src/mfm/html.ts
+++ b/src/mfm/html.ts
@@ -1,127 +1,135 @@
-const { lib: emojilib } = require('emojilib');
const jsdom = require('jsdom');
const { JSDOM } = jsdom;
import config from '../config';
import { INote } from '../models/note';
-import { TextElement } from './parse';
+import { Node } from './parser';
import { intersperse } from '../prelude/array';
-const handlers: { [key: string]: (window: any, token: any, mentionedRemoteUsers: INote['mentionedRemoteUsers']) => void } = {
- bold({ document }, { bold }) {
- const b = document.createElement('b');
- b.textContent = bold;
- document.body.appendChild(b);
- },
+export default (tokens: Node[], mentionedRemoteUsers: INote['mentionedRemoteUsers'] = []) => {
+ if (tokens == null) {
+ return null;
+ }
- big({ document }, { big }) {
- const b = document.createElement('strong');
- b.textContent = big;
- document.body.appendChild(b);
- },
+ const { window } = new JSDOM('');
- motion({ document }, { big }) {
- const b = document.createElement('strong');
- b.textContent = big;
- document.body.appendChild(b);
- },
+ const doc = window.document;
- code({ document }, { code }) {
- const pre = document.createElement('pre');
- const inner = document.createElement('code');
- inner.innerHTML = code;
- pre.appendChild(inner);
- document.body.appendChild(pre);
- },
+ function dive(nodes: Node[]): any[] {
+ return nodes.map(n => handlers[n.name](n));
+ }
- emoji({ document }, { content, emoji }) {
- const found = emojilib[emoji];
- const node = document.createTextNode(found ? found.char : content);
- document.body.appendChild(node);
- },
+ const handlers: { [key: string]: (token: Node) => any } = {
+ bold(token) {
+ const el = doc.createElement('b');
+ dive(token.children).forEach(child => el.appendChild(child));
+ return el;
+ },
- hashtag({ document }, { hashtag }) {
- const a = document.createElement('a');
- a.href = `${config.url}/tags/${hashtag}`;
- a.textContent = `#${hashtag}`;
- a.setAttribute('rel', 'tag');
- document.body.appendChild(a);
- },
+ big(token) {
+ const el = doc.createElement('strong');
+ dive(token.children).forEach(child => el.appendChild(child));
+ return el;
+ },
- 'inline-code'({ document }, { code }) {
- const element = document.createElement('code');
- element.textContent = code;
- document.body.appendChild(element);
- },
+ motion(token) {
+ const el = doc.createElement('i');
+ dive(token.children).forEach(child => el.appendChild(child));
+ return el;
+ },
- math({ document }, { formula }) {
- const element = document.createElement('code');
- element.textContent = formula;
- document.body.appendChild(element);
- },
+ blockCode(token) {
+ const pre = doc.createElement('pre');
+ const inner = doc.createElement('code');
+ inner.innerHTML = token.props.code;
+ pre.appendChild(inner);
+ return pre;
+ },
- link({ document }, { url, title }) {
- const a = document.createElement('a');
- a.href = url;
- a.textContent = title;
- document.body.appendChild(a);
- },
+ emoji(token) {
+ return doc.createTextNode(token.props.emoji ? token.props.emoji : `:${token.props.name}:`);
+ },
- mention({ document }, { content, username, host }, mentionedRemoteUsers) {
- const a = document.createElement('a');
- const remoteUserInfo = mentionedRemoteUsers.find(remoteUser => remoteUser.username === username && remoteUser.host === host);
- a.href = remoteUserInfo ? remoteUserInfo.uri : `${config.url}/${content}`;
- a.textContent = content;
- document.body.appendChild(a);
- },
+ hashtag(token) {
+ const a = doc.createElement('a');
+ a.href = `${config.url}/tags/${token.props.hashtag}`;
+ a.textContent = `#${token.props.hashtag}`;
+ a.setAttribute('rel', 'tag');
+ return a;
+ },
- quote({ document }, { quote }) {
- const blockquote = document.createElement('blockquote');
- blockquote.textContent = quote;
- document.body.appendChild(blockquote);
- },
+ inlineCode(token) {
+ const el = doc.createElement('code');
+ el.textContent = token.props.code;
+ return el;
+ },
- title({ document }, { content }) {
- const h1 = document.createElement('h1');
- h1.textContent = content;
- document.body.appendChild(h1);
- },
+ math(token) {
+ const el = doc.createElement('code');
+ el.textContent = token.props.formula;
+ return el;
+ },
- text({ document }, { content }) {
- const nodes = (content as string).split('\n').map(x => document.createTextNode(x));
- for (const x of intersperse('br', nodes)) {
- if (x === 'br') {
- document.body.appendChild(document.createElement('br'));
- } else {
- document.body.appendChild(x);
- }
- }
- },
+ link(token) {
+ const a = doc.createElement('a');
+ a.href = token.props.url;
+ dive(token.children).forEach(child => a.appendChild(child));
+ return a;
+ },
- url({ document }, { url }) {
- const a = document.createElement('a');
- a.href = url;
- a.textContent = url;
- document.body.appendChild(a);
- },
+ mention(token) {
+ const a = doc.createElement('a');
+ const { username, host, acct } = token.props;
+ const remoteUserInfo = mentionedRemoteUsers.find(remoteUser => remoteUser.username === username && remoteUser.host === host);
+ a.href = remoteUserInfo ? remoteUserInfo.uri : `${config.url}/${acct}`;
+ a.textContent = acct;
+ return a;
+ },
- search({ document }, { content, query }) {
- const a = document.createElement('a');
- a.href = `https://www.google.com/?#q=${query}`;
- a.textContent = content;
- document.body.appendChild(a);
- }
-};
+ quote(token) {
+ const el = doc.createElement('blockquote');
+ dive(token.children).forEach(child => el.appendChild(child));
+ return el;
+ },
-export default (tokens: TextElement[], mentionedRemoteUsers: INote['mentionedRemoteUsers'] = []) => {
- if (tokens == null) {
- return null;
- }
+ title(token) {
+ const el = doc.createElement('h1');
+ dive(token.children).forEach(child => el.appendChild(child));
+ return el;
+ },
- const { window } = new JSDOM('');
+ text(token) {
+ const el = doc.createElement('span');
+ const nodes = (token.props.text as string).split('\n').map(x => doc.createTextNode(x));
- for (const token of tokens) {
- handlers[token.type](window, token, mentionedRemoteUsers);
- }
+ for (const x of intersperse('br', nodes)) {
+ if (x === 'br') {
+ el.appendChild(doc.createElement('br'));
+ } else {
+ el.appendChild(x);
+ }
+ }
+
+ return el;
+ },
+
+ url(token) {
+ const a = doc.createElement('a');
+ a.href = token.props.url;
+ a.textContent = token.props.url;
+ return a;
+ },
+
+ search(token) {
+ const a = doc.createElement('a');
+ a.href = `https://www.google.com/?#q=${token.props.query}`;
+ a.textContent = token.props.content;
+ return a;
+ }
+ };
+
+ dive(tokens).forEach(x => {
+ doc.body.appendChild(x);
+ });
- return `<p>${window.document.body.innerHTML}</p>`;
+ return `<p>${doc.body.innerHTML}</p>`;
};