はじめに
クソアプリ Advent Calendar 2018 の3日目です。
概要
Twitterでツイートしようと思った時にふと「Markdownで書きたい」と思ったことはないでしょうか? ここに訪れている方であれば誰もがあるはずです。僕も時々そう思っていたので今回TwitterでMarkdownを使えるようにしてみました。
とりあえず完成したもの
例えば下記のようなツイートを行うと…
こんな感じで表示されます。
リンクや画像も、コードまでも思いのままです。さあ、皆さん思う存分Twitter上でMarkdownライフをエンジョイしてください!
…と、すみません、技術解説や使い方の説明が抜けていました。
技術解説
何はともあれツイート文に書かれているMarkdownを変換する必要がありますので、変換用ライブラリと、コードハイライトのライブラリを導入します。あとCSSも一緒に入れておきます。
yarn add marked highlight.js github-markdown-css
markedを初期化します。コード部分はhighlight.jsを使うように設定します。
const marked = require("marked");
import * as hljs from "highlight.js";
require("highlight.js/styles/atom-one-dark.css");
const renderer = new marked.Renderer();
renderer.code = (code, language) => {
return (
"<pre" +
'><code class="hljs">' +
hljs.highlightAuto(code).value +
"</code></pre>"
);
};
marked.setOptions({
renderer: renderer
});
各ツイートはjs-tweet-text-containerというクラスの要素に含まれているため、これでループしていきます。
document.querySelectorAll(".js-tweet-text-container").forEach(element => {
let body = element.innerHTML;
if (body.match(/<!--marked-->/)) {
return;
}
const pStartRegex = /<p[^>]+>/;
const pStart = body.match(pStartRegex);
body = body.replace(pStartRegex, "");
body = body.replace(/<\/p>/, "");
body = stripUrlTags(body);
body = stripDollarHashLinks(body);
body = body.trim();
const markdown = marked(body).replace(/<p> +/, pStart[0]);
const divStart = pStart[0]
.replace(/<p/, "<div")
.replace(/class="/, 'class="markdown-body ');
element.innerHTML = `<!--marked-->${divStart}${markdown}</div>`;
}
各要素を監視して実行してるため、同じ要素で何度も実行してしまわないように<!--marked-->
というコメントを入れてそれがあれば無視するようにしています。
あとp
とかdiv
とかをあれこれしていますが、ツイート本文はp
タグで囲まれているため、Markdownを変換後は色々なタグがそのp
タグの子要素になってしまい正常ではなくなるため、div
に変更してあります。ついでにCSSが反映されるようにmarkdown-body
クラスを追加しています。
URLの自動リンクを削除
ツイートにURLを書くと自動的にリンクされてしまいます。そのためMarkdownのリンク最初からリンクされている状態になってしまうため正常に変換できません。そのため予め自動的に付与されたリンクを削除しておきます。
function stripUrlTags(body) {
const regex = /\[([^\]]*)\]\((<a.+?twitter-timeline-link.+?>.+?<\/a>)[ …]*\)/;
let match = body.match(regex);
while (match) {
const url = match[2]
.replace(/<[^>]+>/g, "")
.replace(/[ …]/g, "")
.replace(/ /g, "")
.trim();
console.log(url);
const replaced = `[${match[1]}](${url})`;
body = body.replace(match[0], replaced);
match = body.match(regex);
}
return body;
}
ハッシュタグの自動リンクを削除
ハッシュタグと、あと$
で始まるキャッシュタグも自動リンクされてしまいます。PHPの変数を含めたコードを書きたい場合などに支障が出るためこちらも予め削除しておきます。
function stripDollarHashLinks(body) {
const lines = body.split(/\n/);
const regex = /<a.+?twitter-(c|h)ashtag.+?>.+?<\/a>/g;
let isCode = false;
lines.forEach((line, i) => {
if (line.substr(0, 3) == "```") {
isCode = !isCode;
return;
}
if (!isCode) {
return;
}
const matches = line.match(regex);
if (!matches) {
return;
}
matches.forEach(match => {
const replaced = match.replace(/<[^>]+>/g, "");
body = body.replace(match, replaced);
});
lines[i] = line;
});
return body;
}
使い方
さて、次に使い方ですが、下記のChrome拡張をインストールするだけです。これでMarkdownライフがエンジョイできます。
注意点
Chrome拡張なので当然インストールしているブラウザでしか変換されません。他の人が見るとこんな感じになっています…。
ということで全員がこのChrome拡張のインストールをお願いします!!! (あとMarkdown変換に対応したスマホ用のTwitterクライアントの開発もどなたかお願いします)