はじめに
マークダウンのリアルタイムプレビュー機能を作ってみたいと思い、こちらの方の記事を参考にさせていただきました。
ただ、そもそも使用しているライブラリ、および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)); }); function replaceMarkdown(elm) { var v, old = elm.value; return function () { if (old != (v = elm.value)) { old = v; str = $(this).val(); $("#marked-area").html(str); } } } }); |
JSのコードに関して
まずは、対象のtextareaに関してkeyupイベントと関数をバインドさせます。
keyupはキーボードのキーが押され、上がった際に呼び出されます。
JQuery 日本語リファレンス -keyup-
keyupされたタイミングでreplaceMarkdownを呼びます。
ここで詰まったことが、この変数の宣言です。
参考にさせていただいたサイト様にてこの宣言をしておりました。
1 | var v, old = elm.value; |
勝手に勘違いしておりまして、
v = old = elm.value
で読み進めておりました。
JQueryでは変数をこのように宣言できます。
(どうりでページロード時に
v
を出力させると
undefined
になるわけです。。。)
1 2 3 4 | var v; var old = elm.value; // ↓ var v, old = elm.value; |
あとはvとoldを比較して、異なれば書き換えます。
1 2 3 4 5 6 7 8 9 10 | function replaceMarkdown(elm) { var v, old = elm.value; return function () { 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)
今度はサーバーサイドでのマークダウン変換についても記事にしたいと思います!