Calendario.js + MovableTypeでレスポンシブ対応カレンダーに調整してみた

案件でカレンダーを組み込みたいという要件が出てきたので、調整してみた。

MovableTypeには、[イベントカレンダープラグイン](http://www.h-fj.com/blog/archives/2014/03/25-102050.php)というプラグインがあったのですが今回の要件に「レスポンシブ」は決まっていたので、今回このプラグインを使った中で意図したレイアウトにCSSを調整するのは難しかったため、レスポンシブにも対応している[Calendario.js](https://github.com/codrops/Calendario)を使うことで対応した方法をまとめておきます。

## 要件

* レスポンシブで対応すること（スマホ表示で縦に変化する）
* td内にイベントリンクがつくようにする
* 月の遷移をファイル出力ではなく、遷移をJSで制御（どこまで先の予定が入るか不明のため）
* 同じ日にイベントが複数入る
* 日時を跨ぐイベントがある
* 日本語化されている

## 経緯

* スマホで表示されるときにtableの拡大・縮小ではNG（FullCalendar.js）
* [イベントカレンダープラグイン](http://www.h-fj.com/blog/archives/2014/03/25-102050.php)制御出来ず
* Googleカレンダーを埋め込むパターンはスマホでバグってしまう（端末によってだと思われますが。。また投稿する人が多数いるためGmailアカウントを作るのは現実的ではない。。）
* 他のプラグインで検証してみるが要件が合わず。[カレンダー実装プラグイン「Bootstrap Calendar」](http://kwski.net/jquery/1222/)・[Bootstrapを使ったカレンダーを実装「Zabuto Calendar」](http://webkaru.net/jquery-plugin/zabuto-calendar/)

### FullCalendar.jsでは予定表（スマホ切替時）を縦にならず。

はじめに、[イベントカレンダープラグイン](http://www.h-fj.com/blog/archives/2014/03/25-102050.php)で進めたかったのですが、以下の仕様だったため断念しました。

* これはFullCalendarの仕様だと思うのですが、縦表示させるのであればtdなりをdisplay:blockするなりで対応は可能だが、イベント自体の位置を制御難しい（プラグイン自体を改修するレベル）
* イベントが入る部分はtd内に入るものだと思っていたのですが、デバッグするとtableの外にイベントが入り、position指定でtableの端から位置を操作している（予想：レスポンシブだとこの位置をresizeイベントで計算をいれなければならない）

## 紆余曲折しながらCalendario.js + MovableTypeで対応することにした。

まずは[Calendario.js](https://github.com/codrops/Calendario)をダウンロードしていきます。※日本語対応はしていなかったので、調整したものをGithubにアップしておきました。

* [Calendario-Calendar-jp](https://github.com/redamoon/Calendario-Calendar-jp)

### サンプル1が今回のレイアウトイメージ（スマホ表示含め） View側について

日本語対応したリポジトリは、無駄だったサンプルは削除して本家のサンプルを入れておきました。（index.html）
※HTMLの調整は各自で行なって下さい。optionなどは本家のドキュメントに書いています。

* サンプル1では、js/data.jsにデータを格納してhtml上にsrcで呼び出して、Calendario.jsのOption（caldata :codropsEvents）で呼び出す
* ※データフォーマットをJSONで作りこんで呼びだそうと思ったのですが、簡単にはいかなかった（時間がなかったためサンプルのdata.jsに記述されている内容で対処）

### データをMTで出力させる

ここからdata.jsをMTタグを使って生成させて、記事が投稿されたらdata.jsに書き込むようにMTMLを書きました。

* Calendario.jsは、同じ日にイベントが複数あった場合はkey（日付）に対してvalueが複数入る仕様らしい（深くソースをレビューしていないが）
* サンプルのsrc="js/data.js"はMTで出力されるパスに変更する

#### オブジェクトのイメージはこのような感じで出力される

codropsEventsの変数にオブジェクト入れて、codropsEventsをCalendario.jsのoptionに渡します。
今回は```<mt:Entries>```を使ってこのような形で出力するようにしてみた。

#### 出力結果イメージ

```js
var codropsEvents = {
"05-20-2016": "テスト投稿1",
"05-17-2016": "1つ目イベントが発生 2つ目イベントが発生",
"05-16-2016": "会議があります。。",
"05-11-2016": "テスト投稿2"
}
```

#### MTML

もう少しスマートにかけないのかなって悩みましたが、以下のMTMLで動作的には対応できました。
動きとしては以下のような形になります。（インデックステンプレートで作成します。）

* ```<mt:Unless compress="3">```は、テンプレートで空行削除ができるプラグインを入れています。：参考ブログ [Movable Type テンプレートで空行削除などができるcompress modifier プラグインを公開します](http://bit-part.net/blog/2013/05/movable-type-compress-modifier.html)
* ```<$mt:EntryDate format="%m-%d-%Y" setvar="EntryDateSet"$>```日付を変数セットする
* ```<mt:EntryNext><$mt:EntryDate format="%m-%d-%Y" setvar="NextEntryDateSet"$></mt:EntryNext>```で前のエントリーの日付を参照させて変数セットする
* 同じ日のエントリーをまとめるため```<MTDateHeader>```を使用してオブジェクトのkeyを作る：参考ブログ [Movable Typeで特定のカテゴリの記事一覧を日付毎に表示させる](http://linkerdesign.github.io/journal/2012/02/movable-type-55.html)
* ```<MTIf>```で日付の比較を行なう（同じ日だった場合は、前記事のvalueの値に入る条件）
* ```<MTDateFooter>```の処理は、オブジェクトなので最後はカンマをはずす処理

```
<mt:Unless compress="3">
var codropsEvents = {
<mt:Entries>
<$mt:EntryDate format="%m-%d-%Y" setvar="EntryDateSet"$>
<mt:EntryNext><$mt:EntryDate format="%m-%d-%Y" setvar="NextEntryDateSet"$></mt:EntryNext>
<MTDateHeader>"<mt:EntryDate format="%m-%d-%Y">": "</MTDateHeader>
<MTIf name="EntryDateSet" eq="$NextEntryDateSet">
<a href=\"<mt:EntryPermalink>\"><$mt:EntryTitle$></a>
<MTElse>
<a href=\"<mt:EntryPermalink>\"><$mt:EntryTitle$></a>
</MTIf>
<MTDateFooter>"<MTIf name="__last__"><MTElse>,</MTElse></MTIf></MTDateFooter>
</mt:Entries>
}
</mt:Unless>
```

#### 満たせた要件

満たせてた要件は以下になります。

* レスポンシブで対応すること（スマホ表示で縦に変化する）
* td内にイベントリンクがつくようにする
* 月の遷移をファイル出力ではなく、遷移をJSで制御（どこまで先の予定が入るか不明のため）
* 同じ日にイベントが複数入る
* 日本語化されている ※自分でプラグイン本体いじりました。

#### 満たせなかった要件

* 日時を跨ぐイベントがある（対策としては、記事詳細に開始日と終了日を表示させる形にした）

↑仕様上難しいと思います。※深く調べていませんがJSを無理矢理操作すれば対応可能かもしれません。

## 参考記事・イベントカレンダー系プラグイン

※今回のケースには合わなかったプラグインは、次回同じようなことが起きたときのためにまとめておく
予定表の見せ方で調べてて思ったのですが、tdの中にイベントを制御する方法ばかり思っていましたが、イベントをモーダルで出すという方法を知れたのは良かったかもしれません。

* [Movable Typeで特定のカテゴリの記事一覧を日付毎に表示させる](http://linkerdesign.github.io/journal/2012/02/movable-type-55.html)
* [Movable Typeの個別のブログ記事にその記事の投稿月の前後の月別アーカイブへのリンクを表示するカスタマイズ](http://www.tinybeans.net/blog/2009/09/18-060406.html)
* [Movable Typeで前後のエントリーへのリンクを表示](http://miauler.net/blog/archives/2013/06/13_1642.html)
* [レスポンシブにも対応したカレンダーを表示する「Calendario.js」](http://kwski.net/jquery/1051/)
* [Movable Typeで記事データをJSONで吐き出すメモ](http://qiita.com/redamoon/items/a56644cfc50f38ea0d73)
* [mt:If の活用方法](https://github.com/movabletype/Documentation/wiki/Japanese-mtml-guide-3-2)
* [Calendario: A Flexible Calendar Plugin](http://tympanus.net/codrops/2012/11/27/calendario-a-flexible-calendar-plugin/)
* [MTタグで日時を比較する方法とMTDateタグとtsモディファイア](http://www.45shiki.net/blog/2010/06/b000957.htm)
* [MovableTypeで日時を比較する](http://www.home-dc.net/blog/2014/07/movabletype-compare-entry-date-and-modified-date.html)
* [MTIfで変数と変数を比較する方法がやっと分かった。](http://d.hatena.ne.jp/wonohe/20080705/1215234439)
* [Movable Type テンプレートで空行削除などができるcompress modifier プラグインを公開します](http://bit-part.net/blog/2013/05/movable-type-compress-modifier.html)
* [イベントカレンダープラグイン(その1・概要とライセンス)](http://www.h-fj.com/blog/archives/2014/03/25-102050.php)
* [カレンダー実装プラグイン「Bootstrap Calendar」](http://kwski.net/jquery/1222/)
* [Bootstrapを使ったカレンダーを実装「Zabuto Calendar」](http://webkaru.net/jquery-plugin/zabuto-calendar/)