はじめに
マークダウンのリアルタイムプレビュー機能を作ってみたいと思い、こちらの方の記事を参考にさせていただきました。
ただ、そもそも使用しているライブラリ、およびJSに対する知見がないため、メモとして残したいと思います。
記事の中では下記2つのライブラリを使用していらっしゃいます。
- marked.js
- vue.js
後述しますが、vue.jsはJavaScriptの軽量フレームワークのようなので、代わりにJQueryで実装しました。
環境
- Ruby 2.3.1
- Rails 5.0.0.1
- JQuery 1.12.4
mark.js
公式ドキュメント
marked.js自体のドキュメントはこちら。
https://github.com/chjj/marked
marked.jsのGemのドキュメントはこちらです。
https://github.com/rosscooperman/marked-rails
インストール
Gemfileに追記し、インストールします。
1 | gem'marked-rails' |
1 | $bundle install |
application.jsに下記を追記します。
(Rails 3.1以上であれば、Asset Pipelineによって読み込めるので、個別インストールの必要はないようです。)
1 | //= require marked |
Railsへのインストールはこれで完了です。
実際に使用してみる
marked.jsの公式ドキュメントを参考に、実際に使用してみます。
適当なビューを作成し(今回はindexとします。)、下記を記載します。
1 2 3 4 5 6 | <div id="content"></div> <script> console.log(marked('I am using __markdown__.')); document.getElementById('content').innerHTML= marked('# Marked in browser\n\nRendered by **marked**.'); </script> |
すでにmarkedはGemでインストールしているので、marked
メソッドが使用できます。
ブラウザで表示した結果はこちらです。
逆にmarked
メソッドがない場合は下のようになります。
1 2 | document.getElementById('content').innerHTML= '# Marked in browser\n\nRendered by **marked**.'; |
Markdownはきいておらず、単なる文字列として出力されています。
いくつかMarkdownを試してみましたが、基本的なところは普通に出力できました。
日本語Markdownユーザー会
オプションについて
いくつかオプションも設定できるようです。
詳しくは調べられていないので、設定のコードを記載します。
また、ハイライトについては公式ドキュメントの例では、node-pygmentize-bundledとhighlight.jsと連携していました。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 | marked.setOptions({ // コードのハイライト(今回は割愛) highlight:function(code,lang,callback){ require('pygmentize-bundled')({lang:lang,format:'html'}, code,function(err,result){ callback(err,result.toString()); }); }, // Githubっぽいmd形式にするか gfm:true, // Githubっぽいmdの表にするか tables:true, // Githubっぽいmdの改行形式にするか breaks:false, // Markdownのバグを修正する?(よく分からなかったので、とりあえずdefaultのfalseで) pedantic:false, // HTML文字をエスケープするか sanitize:true, // スマートなリストにするか。pedanticと関わりがあるようなので、こちらもdefaultのtrueで。 smartLists:true, // クオートやダッシュの使い方。 smartypants:false, }); |
プレビュー機能
vue.jsに関して
参考にさせていただいた記事では、vue.jsでプレビュー部分を作成していました。
私自身に知識がなかっただけなのですが、vue.jsはフレームワークでした。
他のフレームワーク(ReactやAngular)と比べ、軽量で、View層にだけ焦点を当てている分導入コストが低い、とのことです。
詳しくはドキュメントをご参照ください。
vue.jsのドキュメント
とはいえ、フレームワークであるならば、ふつうにJavaScriptやJQueryを使ってできるだろうと思い、勉強がてら作成してみました。
JQueryで書いてみたコード
とはいえ、JQueryもそこまでゴリゴリ書けるわけではないので、下記サイト様を参考にさせていただきました。
jQueryで色々なフォーム入力値をリアルタイム取得する
まずはビューのHTMLです。
Railsのscaffoldで作成されるフォームを少し修正したくらいです。
1 2 3 4 5 6 7 8 9 10 11 12 13 | <form> <%=form_for@post,:url=>{:action=>:create}do|f|%> <div class="form-group"> <%=f.text_field:title,class:'form-control',placeholder:'タイトルを入力してください'%> </div> <div class="form-group"> <div id='editor'> <textarea name="post[content]"class="form-control"rows="20"></textarea> <div id="marked-area"></div> </div> </div> <%end%> </form> |
続いて、Javascript(JQuery)側です。
最終的にはマークダウン出力したいので、関数名はreplaceMarkdownとなっています。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | $(function(){ $("#editor textarea").each(function(){ $(this).bind('keyup',replaceMarkdown(this)); }); functionreplaceMarkdown(elm){ varv,old=elm.value; returnfunction(){ if(old!=(v=elm.value)){ old=v; str=$(this).val(); $("#marked-area").html(str); } } } }); |
JSのコードに関して
まずは、対象のtextareaに関してkeyupイベントと関数をバインドさせます。
keyupはキーボードのキーが押され、上がった際に呼び出されます。
JQuery 日本語リファレンス -keyup-
keyupされたタイミングでreplaceMarkdownを呼びます。
ここで詰まったことが、この変数の宣言です。
参考にさせていただいたサイト様にてこの宣言をしておりました。
1 | varv,old=elm.value; |
勝手に勘違いしておりまして、v = old = elm.value
で読み進めておりました。
JQueryでは変数をこのように宣言できます。
(どうりでページロード時にv
を出力させるとundefined
になるわけです。。。)
1 2 3 4 | varv; varold=elm.value; // ↓ varv,old=elm.value; |
あとはvとoldを比較して、異なれば書き換えます。
1 2 3 4 5 6 7 8 9 10 | functionreplaceMarkdown(elm){ varv,old=elm.value; returnfunction(){ if(old!=(v=elm.value)){ old=v; str=$(this).val(); $("#marked-area").html(str); } } } |
なお、marked.jsを使用してstrをマークダウンに変換すれば、ちゃんと出力されます。
1 | $("#marked-area").html(marked(str)); |
さいごに
マークダウンのプレビュー機能を調べている中で、RubyにもいろいろなGemがあることを知りました。
(例えば、Redcarpet)
今度はサーバーサイドでのマークダウン変換についても記事にしたいと思います!