misskey/src/mfm/to-html.ts

190 lines
4.5 KiB
TypeScript
Raw Normal View History

import { JSDOM } from 'jsdom';
2018-05-17 08:14:30 +09:00
import config from '../config';
2018-09-06 02:28:04 +09:00
import { intersperse } from '../prelude/array';
import { MfmForest, MfmTree } from './prelude';
Use PostgreSQL instead of MongoDB (#4572) * wip * Update note.ts * Update timeline.ts * Update core.ts * wip * Update generate-visibility-query.ts * wip * wip * wip * wip * wip * Update global-timeline.ts * wip * wip * wip * Update vote.ts * wip * wip * Update create.ts * wip * wip * wip * wip * wip * wip * wip * wip * wip * wip * wip * wip * Update files.ts * wip * wip * Update CONTRIBUTING.md * wip * wip * wip * wip * wip * wip * wip * wip * Update read-notification.ts * wip * wip * wip * wip * wip * wip * wip * Update cancel.ts * wip * wip * wip * Update show.ts * wip * wip * Update gen-id.ts * Update create.ts * Update id.ts * wip * wip * wip * wip * wip * wip * wip * Docker: Update files about Docker (#4599) * Docker: Use cache if files used by `yarn install` was not updated This patch reduces the number of times to installing node_modules. For example, `yarn install` step will be skipped when only ".config/default.yml" is updated. * Docker: Migrate MongoDB to Postgresql Misskey uses Postgresql as a database instead of Mongodb since version 11. * Docker: Uncomment about data persistence This patch will save a lot of databases. * wip * wip * wip * Update activitypub.ts * wip * wip * wip * Update logs.ts * wip * Update drive-file.ts * Update register.ts * wip * wip * Update mentions.ts * wip * wip * wip * Update recommendation.ts * wip * Update index.ts * wip * Update recommendation.ts * Doc: Update docker.ja.md and docker.en.md (#1) (#4608) Update how to set up misskey. * wip * :v: * wip * Update note.ts * Update postgre.ts * wip * wip * wip * wip * Update add-file.ts * wip * wip * wip * Clean up * Update logs.ts * wip * :pizza: * wip * Ad notes * wip * Update api-visibility.ts * Update note.ts * Update add-file.ts * tests * tests * Update postgre.ts * Update utils.ts * wip * wip * Refactor * wip * Refactor * wip * wip * Update show-users.ts * Update update-instance.ts * wip * Update feed.ts * Update outbox.ts * Update outbox.ts * Update user.ts * wip * Update list.ts * Update update-hashtag.ts * wip * Update update-hashtag.ts * Refactor * Update update.ts * wip * wip * :v: * clean up * docs * Update push.ts * wip * Update api.ts * wip * :v: * Update make-pagination-query.ts * :v: * Delete hashtags.ts * Update instances.ts * Update instances.ts * Update create.ts * Update search.ts * Update reversi-game.ts * Update signup.ts * Update user.ts * id * Update example.yml * :art: * objectid * fix * reversi * reversi * Fix bug of chart engine * Add test of chart engine * Improve test * Better testing * Improve chart engine * Refactor * Add test of chart engine * Refactor * Add chart test * Fix bug * コミットし忘れ * Refactoring * :v: * Add tests * Add test * Extarct note tests * Refactor * 存在しないユーザーにメンションできなくなっていた問題を修正 * Fix bug * Update update-meta.ts * Fix bug * Update mention.vue * Fix bug * Update meta.ts * Update CONTRIBUTING.md * Fix bug * Fix bug * Fix bug * Clean up * Clean up * Update notification.ts * Clean up * Add mute tests * Add test * Refactor * Add test * Fix test * Refactor * Refactor * Add tests * Update utils.ts * Update utils.ts * Fix test * Update package.json * Update update.ts * Update manifest.ts * Fix bug * Fix bug * Add test * :art: * Update endpoint permissions * Updaye permisison * Update person.ts #4299 * データベースと同期しないように * Fix bug * Fix bug * Update reversi-game.ts * Use a feature of Node v11.7.0 to extract a public key (#4644) * wip * wip * :v: * Refactoring #1540 * test * test * test * test * test * test * test * Fix bug * Fix test * :sushi: * wip * #4471 * Add test for #4335 * Refactor * Fix test * Add tests * :clock4: * Fix bug * Add test * Add test * rename * Fix bug
2019-04-07 21:50:36 +09:00
import { IMentionedRemoteUsers } from '../models/entities/note';
2020-08-07 11:27:37 +09:00
import { wellKnownServices } from '../well-known-services';
2018-08-19 00:31:25 +09:00
export function toHtml(tokens: MfmForest | null, mentionedRemoteUsers: IMentionedRemoteUsers = []) {
2018-07-01 13:46:34 +09:00
if (tokens == null) {
return null;
}
2018-03-31 19:53:30 +09:00
const { window } = new JSDOM('');
const doc = window.document;
function appendChildren(children: MfmForest, targetElement: any): void {
for (const child of children.map(t => handlers[t.node.type](t))) targetElement.appendChild(child);
2018-03-31 19:53:30 +09:00
}
const handlers: { [key: string]: (token: MfmTree) => any } = {
bold(token) {
const el = doc.createElement('b');
appendChildren(token.children, el);
return el;
},
big(token) {
const el = doc.createElement('strong');
appendChildren(token.children, el);
return el;
},
2018-12-05 20:11:54 +09:00
small(token) {
const el = doc.createElement('small');
appendChildren(token.children, el);
2018-12-05 20:11:54 +09:00
return el;
},
strike(token) {
const el = doc.createElement('del');
appendChildren(token.children, el);
return el;
},
2018-12-05 17:39:26 +09:00
italic(token) {
const el = doc.createElement('i');
appendChildren(token.children, el);
2018-12-05 17:39:26 +09:00
return el;
},
motion(token) {
const el = doc.createElement('i');
appendChildren(token.children, el);
return el;
},
2019-01-27 16:18:04 +09:00
spin(token) {
const el = doc.createElement('i');
appendChildren(token.children, el);
return el;
},
jump(token) {
const el = doc.createElement('i');
appendChildren(token.children, el);
return el;
},
2020-11-02 15:16:37 +09:00
twitch(token) {
const el = doc.createElement('i');
appendChildren(token.children, el);
return el;
},
2019-01-27 16:31:00 +09:00
flip(token) {
const el = doc.createElement('span');
appendChildren(token.children, el);
return el;
},
blockCode(token) {
const pre = doc.createElement('pre');
const inner = doc.createElement('code');
inner.innerHTML = token.node.props.code;
pre.appendChild(inner);
return pre;
},
2018-11-25 13:36:40 +09:00
center(token) {
const el = doc.createElement('div');
appendChildren(token.children, el);
2018-11-25 13:36:40 +09:00
return el;
},
emoji(token) {
return doc.createTextNode(token.node.props.emoji ? token.node.props.emoji : `\u200B:${token.node.props.name}:\u200B`);
},
hashtag(token) {
const a = doc.createElement('a');
a.href = `${config.url}/tags/${token.node.props.hashtag}`;
a.textContent = `#${token.node.props.hashtag}`;
a.setAttribute('rel', 'tag');
return a;
},
inlineCode(token) {
const el = doc.createElement('code');
el.textContent = token.node.props.code;
return el;
},
mathInline(token) {
const el = doc.createElement('code');
el.textContent = token.node.props.formula;
return el;
},
mathBlock(token) {
const el = doc.createElement('code');
el.textContent = token.node.props.formula;
return el;
},
link(token) {
const a = doc.createElement('a');
a.href = token.node.props.url;
appendChildren(token.children, a);
return a;
},
mention(token) {
const a = doc.createElement('a');
const { username, host, acct } = token.node.props;
2020-08-07 11:27:37 +09:00
const wellKnown = wellKnownServices.find(x => x[0] === host);
if (wellKnown) {
a.href = wellKnown[1](username);
} else {
const remoteUserInfo = mentionedRemoteUsers.find(remoteUser => remoteUser.username === username && remoteUser.host === host);
a.href = remoteUserInfo ? (remoteUserInfo.url ? remoteUserInfo.url : remoteUserInfo.uri) : `${config.url}/${acct}`;
a.className = 'u-url mention';
2018-12-13 01:33:18 +09:00
}
a.textContent = acct;
return a;
},
quote(token) {
const el = doc.createElement('blockquote');
appendChildren(token.children, el);
return el;
},
title(token) {
const el = doc.createElement('h1');
appendChildren(token.children, el);
return el;
},
text(token) {
const el = doc.createElement('span');
const nodes = (token.node.props.text as string).split(/\r\n|\r|\n/).map(x => doc.createTextNode(x) as Node);
for (const x of intersperse<Node | 'br'>('br', nodes)) {
2018-12-09 03:40:40 +09:00
el.appendChild(x === 'br' ? doc.createElement('br') : x);
}
return el;
},
url(token) {
const a = doc.createElement('a');
a.href = token.node.props.url;
a.textContent = token.node.props.url;
return a;
},
search(token) {
const a = doc.createElement('a');
Migrate to Vue3 (#6587) * Update reaction.vue * fix bug * wip * wip * wjio * wip * Revert "wip" This reverts commit e427f2160adf4e8a4147006e25a89854edab0033. * wip * wip * wip * Update init.ts * Update drive-window.vue * wip * wip * Use PascalCase for components * Use PascalCase for components * update dep * wip * wip * wip * Update init.ts * wip * Update paging.ts * Update test.vue * watch deep * wip * lint * wip * wip * wip * wip * wiop * wip * Update webpack.config.ts * alllow null poll * wip * wip * wip * wiop * UI redesign & refactor (#6714) * wip * wip * wip * wip * wip * Update drive.vue * Update word-mute.vue * wip * wip * wip * clean up * wip * Update default.vue * wip * Update notes.vue * Update mfm.ts * Update index.home.vue * Update post-form.vue * Update post-form-attaches.vue * wip * Update post-form.vue * Update sidebar.vue * wip * wip * Update index.vue * wip * Update default.vue * Update index.vue * Update index.vue * wip * Update post-form-attaches.vue * Update note.vue * wip * clean up * Update notes.vue * wip * wip * Update ja-JP.yml * wip * wip * Update index.vue * wip * wip * wip * wip * wip * wip * wip * wip * Update default.vue * wip * Update _dark.json5 * wip * wip * wip * clean up * wip * wip * Update index.vue * Update test.vue * wip * wip * fix * wip * wip * wip * wip * clena yop * wip * wip * Update store.ts * Update messaging-room.vue * Update default.widgets.vue * fix * wip * wip * Update modal.vue * wip * Update os.ts * Update os.ts * Update deck.vue * Update init.ts * wip * Update ja-JP.yml * v-sizeは単にwindowのresizeを監視するだけで良いかもしれない * Update modal.vue * wip * Update tooltip.ts * wip * wip * wip * wip * wip * Update image-viewer.vue * wip * wip * Update style.scss * Update style.scss * Update visitor.vue * wip * Update init.ts * Update init.ts * wip * wip * Update visitor.vue * Update visitor.vue * Update visitor.vue * Update visitor.vue * wip * wip * Update modal.vue * Update header.vue * Update menu.vue * Update about.vue * Update about-misskey.vue * wip * wip * Update visitor.vue * Update tooltip.ts * wip * Update drive.vue * wip * Update style.scss * Update header.vue * wip * wip * Update users.user.vue * Update announcements.vue * wip * wip * wip * Update emojis.vue * wip * Update emojis.vue * Update style.scss * Update users.vue * wip * Update style.scss * wip * Update welcome.entrance.vue * Update radio.vue * Update size.ts * Update emoji-edit-dialog.vue * wip * Update emojis.vue * wip * Update emojis.vue * Update emojis.vue * Update emojis.vue * wip * wip * wip * wip * Update file-dialog.vue * wip * wip * Update token-generate-window.vue * Update notification-setting-window.vue * wip * wip * Update _error_.vue * Update ja-JP.yml * wip * wip * Update store.ts * Update emojis.vue * Update emojis.vue * Update emojis.vue * Update announcements.vue * Update store.ts * wip * Update page-editor.vue * wip * wip * Update modal.vue * wip * Update select-file.ts * Update timeline.vue * Update emojis.vue * Update os.ts * wip * Update user-select.vue * Update mfm.ts * Update get-file-info.ts * Update drive.vue * Update init.ts * Update mfm.ts * wip * wip * Update window.vue * Update note.vue * wip * wip * Update user-info.vue * wip * wip * wip * wip * wip * Update header.vue * Update header.vue * wip * Update explore.vue * wip * wip * wip * Update webpack.config.ts * wip * wip * wip * wip * wip * wip * Update autocomplete.ts * wip * wip * wip * Update toast.vue * wip * Update post-form-dialog.vue * wip * wip * wip * wip * wip * Update users.vue * wip * Update explore.vue * wip * wip * wip * Update package.json * wip * Update icon-dialog.vue * wip * wip * Update user-preview.ts * wip * wip * wip * wip * wip * Update instance.vue * Update user-name.vue * Update federation.vue * Update instance.vue * wip * wip * Update tag.vue * wip * wip * wip * wip * wip * Update instance.vue * wip * Update os.ts * Update os.ts * wip * wip * wip * Update router.ts * wip * Update init.ts * Update note.vue * Update messages.vue * wip * wip * wip * wip * wip * google * wip * wip * wip * wip * Update theme-editor.vue * wip * wip * Update room.vue * Update channel-editor.vue * wip * Update window.vue * Update window.vue * wip * Update window.vue * Update window.vue * wip * Update menu.vue * wip * wip * wip * wip * Update messaging-room.vue * wip * Update post-form.vue * Update default.widgets.vue * Update window.vue * wip
2020-10-17 20:12:00 +09:00
a.href = `https://www.google.com/search?q=${token.node.props.query}`;
a.textContent = token.node.props.content;
return a;
}
};
appendChildren(tokens, doc.body);
return `<p>${doc.body.innerHTML}</p>`;
2019-01-30 16:56:27 +09:00
}