カテゴリー: FrontEnd

JQueryとmark.jsでマークダウンのリアルタイムプレビューをつくる

はじめに

マークダウンのリアルタイムプレビュー機能を作ってみたいと思い、こちらの方の記事を参考にさせていただきました。

Railsにマークダウンのリアルタイムプレビューを実装する

ただ、そもそも使用しているライブラリ、および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に追記し、インストールします。

gem 'marked-rails'
$ bundle install

application.jsに下記を追記します。
(Rails 3.1以上であれば、Asset Pipelineによって読み込めるので、個別インストールの必要はないようです。)

//= require marked

Railsへのインストールはこれで完了です。

実際に使用してみる

marked.jsの公式ドキュメントを参考に、実際に使用してみます。
適当なビューを作成し(今回はindexとします。)、下記を記載します。

<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`メソッドがない場合は下のようになります。

document.getElementById('content').innerHTML =
'# Marked in browser\n\nRendered by **marked**.';

Markdownはきいておらず、単なる文字列として出力されています。
いくつかMarkdownを試してみましたが、基本的なところは普通に出力できました。
日本語Markdownユーザー会

オプションについて

いくつかオプションも設定できるようです。
詳しくは調べられていないので、設定のコードを記載します。
また、ハイライトについては公式ドキュメントの例では、node-pygmentize-bundledhighlight.jsと連携していました。

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で作成されるフォームを少し修正したくらいです。

<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となっています。

$(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を呼びます。

ここで詰まったことが、この変数の宣言です。
参考にさせていただいたサイト様にてこの宣言をしておりました。

var v, old = elm.value;

勝手に勘違いしておりまして、`v = old = elm.value`で読み進めておりました。
JQueryでは変数をこのように宣言できます。
(どうりでページロード時に`v`を出力させると`undefined`になるわけです。。。)

var v;
var old = elm.value;
// ↓
var v, old = elm.value;

jQueryを読むために知っておきたい6つの知識

あとはvとoldを比較して、異なれば書き換えます。

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をマークダウンに変換すれば、ちゃんと出力されます。

$("#marked-area").html(marked(str));

さいごに

マークダウンのプレビュー機能を調べている中で、RubyにもいろいろなGemがあることを知りました。
(例えば、Redcarpet

今度はサーバーサイドでのマークダウン変換についても記事にしたいと思います!

naoki85

シェア
執筆者:
naoki85
タグ: JavaScript

最近の投稿

フロントエンドで動画デコレーション&レンダリング

はじめに 今回は、以下のように…

3週間 前

Goのクエリビルダー goqu を使ってみる

はじめに 最近携わっているとあ…

4週間 前

【Xcode15】プライバシーマニフェスト対応に備えて

はじめに こんにちは、suzu…

2か月 前

FSMを使った状態管理をGoで実装する

はじめに 一般的なアプリケーシ…

3か月 前