googleカレンダー
Google カレンダーのようなカレンダーに色々登録したりするのが欲しかったのでjQueryの勉強がてら作ってみた。
とりあえず実装してみたレベルのなので改善点等は色々あるし、色々なブラウザで動くかどうかは試していない。それでも月移動とか、日付のボックスをクリックした時のコールバック関数も渡せるので、とりあえずは使える感じだと思う。(この上に自分なりのレンダリングをするとなると頑張る必要があるけど)
突っ込みどころは満載だと思うので色々突っ込んで貰えると嬉しいです。
ファイル構成は以下のようにする。画像(combined.gif)はGoogle本家のをダウンロードして使用した。
日付処理でDate.jsを使っているので別途ダウンロードが必要。
ディレクトリ構成
webapp +-css +-jquery.calendar.css +-image +-combined.gif +-js +-jquery.calendar.js +-date.js
画像
本家よりダウンロードしてcombined.gifとして保存する。
http://calendar.google.com/googlecalendar/images/combined_v3.gif
jquery.calendar.css
.calendar-day {
background-color: #ffffff;
position: absolute;
border-top: 1px solid #bbbbbb;
border-left: 1px solid #bbbbbb;
}
.calendar-today {
background-color: #FFFBA4;
position: absolute;
border-top: 1px solid #bbbbbb;
border-left: 1px solid #bbbbbb;
}
.calendar-target-month {
color: #6A6A6B;
}
.calendar-not-target-month {
color: #BABAC4;
}
.calendar-head {
position: absolute;
background-color: rgb(232, 238, 247);
text-align: right;
}
.calendar-hover {
background-color: #ffffee;
}
.calendar-body {
position: relative;
}
.calendar-navbutton {
cursor:pointer;
}
img.calendar-navback {
background-image:url(../image/combined.gif);
background-position:-148px -17px;
padding-left:2px;
padding-right:0;
vertical-align:middle;
}
img.calendar-navforward {
background-image:url(../image/combined.gif);
background-position:-148px 0px;
padding-left:0px;
padding-right:2px;
vertical-align:middle;
}
.calendar-dateunderlay {
color:#000000;
font-size:13px;
padding-left:5px;
white-space:nowrap;
}
jquery.calendar.js
$.fn.calendar = function(options, callback) {
if (typeof options == 'function') {
callback = options;
}
if (callback == null) {
callback = function(){};
}
options = $.extend({
width: options.width || window.innerWidth,
height: options.height || window.innerHeight,
head: options.head || 15,
target: options.target || Date.today().toString('M/1/yyyy'),
type: this.attr('type') || 'month',
navi: options.nav || function() {},
click: options.click || null
}, options || {});
var targetMonth = Date.parse(options.target).toString('yyyyM');
var now = Date.parse(options.target).last().sunday();
var endDate = Date.parse(options.target).moveToLastDayOfMonth();
// 最終日が土曜日の場合は次とやってしまうと1週間先になってしまう
if (endDate.is().sat() == false) {
endDate.next().saturday();
}
var weekOfYear = now.getWeekOfYear();
var weekcnt = endDate.getWeekOfYear() - weekOfYear + 1;
// 年をまたいだ場合はgetWeekOfYearで取れた値をそのまま使用
if (weekcnt < 0) {
weekcnt = endDate.getWeekOfYear() + 1;
}
// 位置の定数定義
var colheader = 20;
var leftmargin = 10;
var bottommargin = 10;
var navmargin = 30;
// 1つ分の日付のボックスの幅
var dayBoxWidth = (options.width - leftmargin) / 7;
// 1つ分の日付のボックスの高さ
var dayBoxHeight = (options.height - colheader - bottommargin - 1) / weekcnt;
// コンテキストパスを取得
var context = getContextPath();
// 月移動ボタン作成
$('<table/>').css({
'position': 'absolute'
, 'top': '0px'
, 'left': '0px'
}).append(
$('<tbody/>').append(
$('<tr/>').append(
$('<td/>').append(
$('<table/>').append(
$('<tbody/>').append(
$('<tr/>').append(
$('<td/>').append(
$('<img height="17" width="29" src="' + context + '/image/blank.gif"/>')
.click(function(e){
options.navi(Date.parse(options.target).add(-1).months().toString('M/1/yyyy'), e);
})
)
).append(
$('<td/>').append(
$('<img height="17" width="29" src="' + context + '/image/blank.gif"/>')
.click(function(e){
options.navi(Date.parse(options.target).add(1).months().toString('M/1/yyyy'), e);
})
)
).append(
$('<td/>').append(
// 今日ボタンは当月の場合は無効化するがそれは下でやる
$('<input type="button" value="今日" id="calendar-today" />')
.click(function(e){
options.navi(Date.now().toString('M/1/yyyy'), e);
})
)
).append(
$('<td/>').append(
$('<span/>').text(Date.parse(options.target).toString('yyyy年 M月'))
)
)
)
)
)
)
)
).appendTo(this);
// 当月は「今日」ボタンを無効化
if (targetMonth == Date.now().toString('yyyyM')) {
$('#calendar-today').attr('disabled', 'disabled');
}
// 角の丸み用div
$('<div id="top_container"/>')
.css({
'background-color': '#c3d9ff', 'margin-left': '1px', 'margin-right': '1px', 'position': 'absolute', 'top': navmargin + 'px'})
.height(1)
.width(options.width - 2)
.appendTo(this);
$('<div id="bottom_container"/>')
.css({
'background-color': '#c3d9ff', 'margin-left': '1px', 'margin-right': '1px', 'position': 'absolute', 'top': (navmargin + options.height + 1 ) + 'px'})
.height(1)
.width(options.width - 2)
.appendTo(this);
var container = $('<div id="container"/>').css({
'background-color': '#c3d9ff'
, 'position': 'absolute'
, 'top': (1 + navmargin) + 'px'
, 'float': 'left'})
.height(navmargin + options.height)
.width(options.width);
// 曜日ヘッダ作成
for (i = 0; i < 7; i++) {
$('<div />')
.width(dayBoxWidth)
.height(colheader - 1)
.css({
'position': 'absolute'
, 'top': (1 + navmargin) + 'px'
, 'left': (i * dayBoxWidth + leftmargin) + 'px'
, 'vertical-align': 'middle'
, 'color': 'rgb(17, 42, 187)'
, 'font-size': '80%'
, 'z-index': 999
})
.text(Date.CultureInfo.shortestDayNames[i])
.appendTo(this);
}
// 日付ボックス作成
while (now.compareTo(endDate) != 1) {
// カレンダの何行目か
var lineNum = now.getWeekOfYear() - weekOfYear;
// 年をまたいだ場合は負の値になってしまうのでgetWeekOfYearで取れた値をそのまま使用
if (lineNum < 0) {
lineNum = now.getWeekOfYear();
}
// 描画対象日
var day = now.getDay();
// 今日だったかどうかでスタイルを変更
var className = 'calendar-day';
if (Date.today().compareTo(now) == 0) {
className = 'calendar-today';
}
// 描画対象の月かどうかで文字のスタイルを変更
var colorClass = 'calendar-target-month';
if (targetMonth != now.toString('yyyyM')) {
colorClass = 'calendar-not-target-month';
}
var cursor = options.click ? 'pointer' : 'auto';
$('<div />')
.css({
'position': 'absolute'
, 'width': dayBoxWidth + 'px'
, 'height': dayBoxHeight + 'px'
, 'top': (dayBoxHeight * lineNum + colheader) + 'px'
, 'left': (day * dayBoxWidth + leftmargin) + 'px'
, 'cursor': cursor})
.attr('id', 'cal_' + now.toString('yyyyMMdd'))
.attr('className', className)
.hover(function() {
$(this).toggleClass('calendar-hover');
}, function() {
$(this).toggleClass('calendar-hover');
})
.click(function(e) {
if (options.click) {
options.click(Date.parseExact(this.id.substring(4), 'yyyyMMdd'), e);
}
})
.appendTo(container).append(
$('<div />').width(dayBoxWidth)
.height(options.head)
.addClass('calendar-head')
.addClass(colorClass)
.html(now.toString('d') + ' ')
)
.append(
$('<div />').width(dayBoxWidth)
.height(dayBoxHeight - options.head)
.addClass('calendar-body')
.addClass(colorClass)
.css({'top': options.head + 'px'})
);
now.addDays(1);
}
this.append(container);
// 作成が終了したらコールバック関数を呼ぶ
callback();
}
// 簡易コンテキストパス取得用関数
function getContextPath() {
var path = './';
var e = document.createElement('span');
e.innerHTML = '<a href="' + path + '" />';
url = e.firstChild.href;
var p = url.split('/');
return '/'+p[3];
}
使用サンプル
<html>
<head>
<link rel="stylesheet" href="css/jquery.calendar.css" type="text/css"></link>
<script src="http://www.google.com/jsapi"></script>
<script>
google.load("jquery", "1.2");
</script>
<script type="text/javascript" src="js/jquery.calendar.js"></script>
<script type="text/javascript" src="js/date.js"></script>
<script type="text/javascript">
$(document).ready(function() {
showCalendar(Date.now());
});
function showCalendar(targetDate) {
// カレンダ作成
$('#calendar').empty().calendar({
width: 600
, height: 400
, target: targetDate.toString('M/1/yyyy')
, nav: showCalendar
});
}
</script>
</head>
<body>
<div id="calendar"></div>
</body>
</html>

