カレンダー実装をするために色々探してたんですが、jqueryプラグインとかgem使ったらいじりにくいし、これってのがなく、しょうがなく色々参考にしながら1から作りました。
誰かのお役に立てば幸いです。
見た目はこんな感じです。
さっそくコード
先ずはカレンダーの箱
ちょっと一工夫いるのは条件によって
を出したり消したりしてるとこですね。そこだけです。
基本的に見れば分かるコードだと思うので解説は割愛します。
ちなみに
を参考にしてます。
html.erb
<div class="event-calendar">
<table>
<caption>2016年9月</caption>
<tbody>
<tr>
<th>日</th>
<th>月</th>
<th>火</th>
<th>水</th>
<th>木</th>
<th>金</th>
<th>土</th>
</tr>
<% @calendar_days.each_with_index do |day, i| %>
<% if i == 0 || i % 7 == 0 %>
<tr>
<% end %>
<td>
<p>
<%= day %>
</p>
<div>
<!-- ここにカレンダー1日単位で情報埋める -->
</div>
</td>
<% if i != 0 && (i + 1) % 7 == 0 %>
</tr>
<% end %>
<% end %>
</tbody>
</table>
</div>
で、次に@calendar_daysに突っ込む値です
ちょっとめんどくさいアルゴリズム
けっこう苦肉りながら書いたので、もっといい方法あるだろって感じですが一旦こんな感じです。
全体としては、月の最初の日より前の部分と、月の最後の日より後の、よくカレンダーでグレーになってる過不足部分(なんて呼ぶんでしょうあれ)を、integerのarrayにして、最終的に当月の1~30日の配列と足してます。
def get_calendar_dates(date)
get_pre_shortage_days(date) + (1..date.end_of_month.day).to_a + get_post_shortage_days(date)
end
# その月の、"29 30" 1 のようなカレンダー不足分
def get_pre_shortage_days(date)
beginning_day = date.beginning_of_month
return 0 if beginning_day.wday == 0
pre_shortage_day = beginning_day - beginning_day.wday.days
return (pre_shortage_day.day..pre_shortage_day.end_of_month.day).to_a
end
def get_post_shortage_days(date)
end_day = date.end_of_month
return 0 if end_day.wday == 6
post_shortage_day = end_day + -(end_day.wday - 6).days
return (1..post_shortage_day.day).to_a
end
end
部分的な解説
配列の足し算、便利です。
[1, 2, 3] + [4, 5, 6]
=> [1, 2, 3, 4, 5, 6]
肝になったのは以下の処理です。
これで日曜日〜土曜日までが0~6でとれるので、それで日を前後させてます。
Date.today.wday
ちなみに前後させるのに使ってる処理ですが、以下のように日付って足し引きできて便利です。
Date.today + 6.days
あとはrange型をarray型に変えるのも重宝しました。最初からarrayでもっと簡単にできそうな気配しかないですが。
(1..2).to_a
=> [1, 2]
scssについて
あるサイトを参考にして以下のようなscssを書きました。
div.event-calendar {
float: left;
table {
width: 325px;
margin-right: 5px;
caption {
font-size: 14px;
color: #479384;
border: 1px solid #b9b9b9;
border-bottom: none;
padding: 14px 0 12px;
text-align: center;
}
tbody {
display: table-row-group;
vertical-align: middle;
border-color: inherit;
tr {
display: table-row-group;
vertical-align: inherit;
border-color: inherit;
th {
width: 325px;
text-align: center;
vertical-align: top;
color: #479384;
background-color: #ecf7f5;
border: 1px solid #b9b9b9;
padding: 6px;
}
td {
text-align: center;
border: 1px solid #b9b9b9;
font-size: 11px;
width: 14%;
height: 60px;
i {
font-size: 20px;
}
}
}
}
}
}
稚拙な説明が極まってますが、誰かのお役に立てれば幸いです。