concrete5のカレンダーブロックで複数月同時に表示する

前回の投稿「concrete5のカレンダーブロックカスタマイズの基本について調べてみました」に続いて、よくありそうなカスタマイズとして複数月同時に表示するカスタマイズをしてみました。

カスタマイズの準備

まず、カスタムテンプレートを作成します。
今回は「multi_calendar」という名前のカスタムテンプレートを作ります。
そして、そこに/concrete/blocks/calendar/view.phpをコピーし、これを修正します。

application
└blocks
 └calendar
  └templates
   └multi_calendar
    └view.php

カスタマイズの方針

  1. カレンダーを表示させる対象のdivタグを追加
  2. divタグの数だけFullCalendarをループで回す
  3. next/prevボタンをクリックしたときにすべてのカレンダーを同時に次月/前月に移動させる
  4. それぞれのカレンダーのヘッダーツールバーを設定できるようにする

1. divタグを追加

元の構造としては、view.phpの13行目にあるDivタグの内側にカレンダーが表示されます。

<div class="ccm-block-calendar-wrapper" data-calendar="<?=$bID?>"></div>

この下層にdivタグを追加して複数月(今回は3か月分)のカレンダーを表示させるようにします。
それぞれのdivタグにはcalendar-itemというクラスをつけます。(他の名前でも構いません)
rowcol-xs-4はbootstrapのクラスです。

<div class="ccm-block-calendar-wrapper row" data-calendar="<?=$bID?>">
<div class="calendar-item col-xs-4"></div>
<div class="calendar-item col-xs-4"></div>
<div class="calendar-item col-xs-4"></div>
</div>

2. FullCalendarをループで回す

次に、FullCalendarを表示する部分をループで回します。
セレクターに先ほど追加した下層のDivタグのクラスcalendar-itemを指定します。

(前略)
$(function() {
$('div[data-calendar=<?=$bID?>] .calendar-item').each(function(){
$(this).fullCalendar({
header: {
(中略)
}
});
}
});
(後略)

これだけですと、同じ月が3回表示されるだけですので、次の月を表示させるようにします。

defaultDateオプションを指定すると、表示月を指定することができます。
"2014-02-01"などのように指定しますが、FullCalendarは日付を扱うライブラリmoment.jsを使うことができますので、こちらを使って指定します。

(前略)
$(function() {
var m = moment();
$('div[data-calendar=<?=$bID?>] .calendar-item').each(function(){
$(this).fullCalendar({
defaultDate: m,
header: {
(中略)
}
m = m.add(1, 'month');
});
}
});
(後略)

moment()で現在時刻を取得できます。
eachループの終わりで現在時刻に1か月を加算して、次のループに移ります。
moment.jsでは、add(1, 'month')で1か月加算できます。
わかりやすいですね。

moment.jsを使うと、日付を扱いがとてもわかりやすくなります。
詳しくは下記を参照してください。
Moment.js | Docs

これで3か月分のカレンダーが下記のように表示されます。

3. すべてのカレンダーを同時に前月/次月へ移動させる

各カレンダーに前月/次月への移動ボタンが表示されていますが、クリックするとそのボタンのあるカレンダーしか移動しません。
そこで、どのカレンダーのボタンをクリックしてもすべてのカレンダーが移動するようにします。

ボタンのクリックを取得して、FullCalendarのprev/nextメソッドで前月/次月に移動します。
ただしボタンが押されたカレンダーはそれだけで移動してしまうので、ボタンが押されたカレンダーがどれかを調べてメソッドの適用をスキップします。

// click "prev" then all calendar move to the next month.
$('div[data-calendar=<?=$bID?>] .calendar-item .fc-prev-button').each(function(){
$(this).click(function() {
var PARENT = $('div[data-calendar=<?=$bID?>] .calendar-item').index($(this).closest('.calendar-item'));
$('div[data-calendar=<?=$bID?>] .calendar-item').each(function(index){
if (index != PARENT) { // desable move - calendar with button clicked.
$(this).fullCalendar('prev');
}
});
});
});

前月ボタンのクラスはfc-prev-buttonです。
eachで3か月分のカレンダーのボタンクリックを取得します。
jQueryのclosetメソッドで押されたボタンが何番目のカレンダーのものかを取得し、それ以外のカレンダーに対して、FullCalendarのprevメソッドで表示を前月に移動させます。(ボタンが押されたカレンダーはその時点で表示が前月に移動します)

次月も同様です。
次月ボタンのクラスはfc-next-buttonです。
次月に移動するメソッドはnextです。

// click "next" then all calendar move to the next month.
$('div[data-calendar=<?=$bID?>] .calendar-item .fc-next-button').each(function(){
$(this).click(function() {
var PARENT = $('div[data-calendar=<?=$bID?>] .calendar-item').index($(this).closest('.calendar-item'));
$('div[data-calendar=<?=$bID?>] .calendar-item').each(function(index){
if (index != PARENT) { // desable move - calendar with button clicked.
$(this).fullCalendar('next');
}
});
});
});

上記の2つのスクリプトを、2. のループの後に挿入します。

4. それぞれのカレンダーのヘッダーツールバーを設定できるようにする

カレンダー表示をループで回すだけでは、すべてのカレンダーに同じボタンが表示されてしまいます。
そこで、それぞれのカレンダーのヘッダー表示を変えられるようにしてみます。

今回は、最初のカレンダー/中間のカレンダー/最後のカレンダーでヘッダー表示をそれぞれ設定できるようにします。

ヘッダー表示は、hedaerオプションで指定します。
concrete5のデフォルトでは次のようになっています。

header: {
left: 'prev,next today',
center: 'title',
right: '<?= $viewTypeString ? $viewTypeString : ''; ?>'
},

left, center, rightに分けで表示オプションを設定します。
concrete5では、rightの内容を管理画面で設定できるようになっています。

headerには何でも表示できるわけではありません。
headerオプションの詳細は下記を参照してください。
header – Docs | FullCalendar

まず、headerオプションの内容を配列で設定しておきます。
最初(左側)のカレンダーは、前月ボタンとタイトル。
中間のカレンダーは、タイトルだけ。
最後(右側)のカレンダーは、タイトルと次月ボタンを設定しておきます。

// set header
var HEADER = {
default: {
left: '',
center: 'title',
right: ''
},
first: {
left: 'prev',
center: 'title',
right: ''
},
last: {
left: '',
center: 'title',
right: 'next'
},
};

カレンダー表示ループ内で、現在のカレンダーが最初/最後かどうかを調べ、カレンダー表示のheaderオプションで上記の配列を指定します。

(前略)
$(function() {
$('div[data-calendar=<?=$bID?>] .calendar-item').each(function(){
var POSITION = 'default';
if ($(this).is(":first-child")) { POSITION = 'first'; }
if ($(this).is(":last-child")) { POSITION = 'last'; }
$(this).fullCalendar({
header: HEADER [ POSITION ],
(中略)
}
});
}
});
(後略)

ようやく完成!

完成したコードはこちらで公開しています。
masakawai/Multi-Month-Calendar: concrete5 calendar block Custom template

カレンダーブロックのカスタマイズはまだまだ奥が深そう

concrete5のカレンダーブロックに採用されている「FullCalendar」は、非常に高機能なカレンダーで、カスタマイズ方法もたくさん公開されています。
ただ高機能なのが災いして、シンプルなカレンダーが欲しいときには使いづらいです。

でも、CSSを調整すれば、こんなシンプルなカレンダーも作ることができます。

次回は、シンプルなカレンダーの作り方の記事を書きたいと思っていますので、お楽しみに。

コメントを残す