Qiita のスライド
Qiita にはスライドビュー機能があります。
これを使えば Qiita の記事書きと、LTなどの発表で同じものが使えて非常に効率が良いですが、実際には機能が足りず、本番で使うには辛いものがあります。
そこで、足りない機能を全て Chrome 拡張で作ってみましたので、その作り方とともに公開します。
Chrome 拡張を通じてどのような修正を行うことで、改善が達成されるものなのか、参考にしてください。
また、この Chrome拡張も、そのソースも一般公開します。
なお、この Chrome 拡張では、jQuery v2 にくわえ、 ChEx.js
という自作の秘伝のタレを使ってます。
Chrome拡張の置き場所
とりあえず入れて試したい方はこちらから入れてみてください。
https://chrome.google.com/webstore/detail/qiita-slide-%E6%94%B9/cgnhlhefahcojhfdoobggpdhpjcgfodc
(ソースコード全体は現在準備中です。近々公開します。)
- 赤 や 青 で強調したい
Qiita のスライドでは強調部分が単色で、強調が伝わりづらいですね。
そこで、**~**
や *~*
の部分に色がつくようにします。
$('body').append(`<style>
.slide_preview.markdownContent strong { color: red; }
.slide_preview.markdownContent em { color: blue; font-style: normal; font-weight: bold; }
</style>`);
-
body
に<style>~</style>
を足すことで全体的に効くスタイルを追加してます。 - この追加では既存の DOM のスタイルは変わってくれませんが、今後、新規に追加される DOM はすべてこの影響を受けることになります。
-
.slide_preview.markdownContent
は Slide の外枠で、この中にあるstrong
やem
の色を変えています。
- カーソルを大きくしたい
カーソルつかって「ここです」と示しても、カーソル小さすぎて伝わりません。
そこで、 B
キーで、カーソルを巨大化したり、もとに戻したりできるようにしましょう。
$('body').append(`<style>
.slide_preview.markdownContent.chex-big-cursor,
.slide_preview.markdownContent.chex-big-cursor pre {
cursor: url(https://waterada.github.io/chrome-ex-qiita/big-cursor.png), auto;
}
</style>`);
ChEx.keydown('B', '大きなカーソル', () => {
$('.slide_preview.markdownContent').toggleClass('chex-big-cursor');
});
-
ChEx.keydown()
という秘伝のタレを使っています。これでB
を押した場合にchex-big-cursor
がトグルするようにしてます。 -
ChEx.keydown()
の中では色々やってるのですが、要するに下記をやりたいのです。
$(document).keydown(function (e) {
if (e.which === 'B') {
$('.slide_preview.markdownContent').toggleClass('chex-big-cursor');
}
});
-
cursor
というスタイルを使ってカーソルを変えることができますが、普通大きさは変えられません。ですが画像は指定できますので、大きな画像を指定することで大きくしています。
- 行番号オン/オフ
コードの説明の際に行番号が欲しくなるときがあります。
L
キーで行番号のオン/オフできるようにしましょう。
ChEx.keydown('L', '行番号オン/オフ', () => {
let $preList = $('.slide_preview.markdownContent').find('pre');
ChEx.toggle('lineNum', () => {
$preList.each(function () {
let $pre = $(this);
let html = $pre.html();
let i = 1;
html = html.trim().replace(/^/gm, () => {
return `<span class="chex-line-num">${ChEx.padding(i++, 3)}| </span>`;
});
$pre.html(html);
});
}, () => {
$preList.find('.chex-line-num').remove();
});
});
-
ChEx.toggle()
は2つのコールバックを呼び出すたびに交互に実行してくれる便利関数です。 -
ChEx.padding()
は数値のパディングをする便利関数です。 - 置換正規表現
/^/gm
のm
フラグは見慣れないかもしれません。m
があると、^
は各行の先頭にヒットするようになります。 - 現状、各行ごとに実際に改行されているので、先頭に連番の HTML を差し込んでいます。
- 範囲選択エリアを黄色に
範囲選択して示してみても、デフォルトの色ではあまり目立ちません。
色を黄色マーカーっぽくしましょう。
$('body').append(`<style>
.slide_preview.markdownContent ::selection { background: yellow; color: black; }
.slide_preview.markdownContent .chex-line-num::selection { background: #f7f7f7; color: black; }
</style>`);
-
::selection
というセレクタを指定することで色を変えられます。 -
.chex-line-num::selection
も指定しているのは、上記で行番号を表示してる場合、番号部分は色を変えたくなかったからです。
- スライドコントローラのオン/オフ
消して画面大きく見せたいとき、ありますね。
ChEx.keydown('Q', 'スライドコントローラのオン/オフ', () => {
$('.slide_controller').toggle();
});
- keydown のヘルプ表示
keydown
で仕込んだキー、忘れてしまうことがあるので、H
キーでヘルプがでるようにしましょう。
ChEx.keydownHelp('H', $('.slide_preview.markdownContent').position());
-
ChEx.keydown()
を使っていれば、勝手にヘルプ用のテキストを作り上げてくれます。 -
$('.slide_preview.markdownContent').position()
はヘルプ枠の表示位置を決める際の基準となる位置です。
- h1で改行する
ページ内に h1 しかない場合、スライドだと、大きな文字で中央寄せで表示されるのですが、改行はできません。
そこで、半角スペース2つを書くことで改行されるようにします。
//h1で半角スペース2つなら改行
$('body').append(`<style>
/* チラツキ防止のため初め非表示 */
.slide_preview.markdownContent h1 { display: none; }
.slide_preview.markdownContent .slide_preview_firstSlide h1 { display: block; }
</style>`);
ChEx.onChangeDom($('.slide_preview.markdownContent'), function () {
$('.slide_preview.markdownContent').find('h1').each(function () {
let $h1 = $(this);
$h1.html($h1.html().replace(/ {2}/g, '<br/>')).show();
});
});
-
ChEx.onChangeDom()
は特定の DOM ノード以下で DOM の変更があった場合にイベントが発火するという便利関数です。 - 実際にやってることを簡潔に書くと次のようになります。
ChEx.onChangeDom = function ($root, callback) {
let timeoutId = 0;
$root.on("DOMNodeInserted DOMSubtreeModified", function () {
if (timeoutId) return true; //動いていたらやらない
timeoutId = setTimeout(function () {
try {
callback();
} finally {
timeoutId = 0;
}
return true;
}, 100);
});
};
-
DOMNodeInserted
、DOMSubtreeModified
というイベントにハンドラを設定しているのがわかると思います。 - このイベントは連続的に発生することが多いので、0.1秒ほど落ち着くのを待ってから発火させてます。待ってる間に発生するイベントは全て捨てちゃいます。最後の状態で1回だけ発火すれば良いので。
- なぜ DOM の変更を監視してるのかというと、スライドの各ページは表示時に毎回、メモリ上に持っている情報をベースに生成されているためです。onLoad 完了後に DOM にあるものを書き換えても、ページに表示されるものは書き換わらないのです。
-
replace(/ {2}/g, '<br/>')
で空白2個を改行に変えてます。 - 最初に
display: none;
してるのは、表示後に書き換えることになるので、改行前の文字列が一瞬表示されて美しくないからです。
最後に
2017-08-05(土) に builderscon tokyo というイベントで 「Chrome拡張を使って様々なWebサービスをハックする」 というネタで登壇します。
https://builderscon.io/tokyo/2017/session/9e8711fb-7f56-44ea-b550-0d48ff756e1d
ご興味ある方がいらっしゃいましたら、ぜひとも聞きにきてください。