前回からGreasemonkeyによるアプリケーション開発の題材としてカレンダアプリケーションを挙げ,
今回はさらに二つの機能を追加したいと思います。
(1) 異なる月も表示する(2) 予定情報を登録/表示できるようにする
異なる月の表示機能
異なる月に移動できるようにするため,
「現在の月」
カレンダに追加する機能の検討
早速その実装をはじめようと思うところですが,
まず,
- 予定の年月日
- 予定の内容
予定情報の表示については,
- 予定情報が登録されている日付は色を変えて表示する
- 日付をカーソルキーなどで選択できるようにして,
選択日に予定情報が登録されていればその内容を表示する
また,
ということで,
- 「選択日」
を動かすようにする - 「選択日」
の月に応じたカレンダを表示する
という処理を実装することとします。
選択日の移動機能の実装
図1,
図1 選択日の移動処理を実装したユーザスクリプト前半部分
// ==UserScript==
// @name mini_calendar5
// @namespace http://gomaxfire.dnsdojo.com/
// @description the 5th mini calendar
// @include *
// ==/UserScript==
/* ユーティリティ関数郡の定義 */
/* 中略 */
/** document.getElementById() のエイリアス */
function $(id){
return document.getElementById(id);
}
/**
* Element#removeChild()のエイリアス
* $rmに与えた要素を削除する
*/
function $rm(element){
if(element && element.parentNode)element.parentNode.removeChild(element);
}
//----------------------------------------------------
// calendar application
//----------------------------------------------------
var calendar = (function(){ // -(1)
var frame = $div(); // -(2)
var table = null;
// calendar用処理群の中で共通利用する変数群を定義
var curDate = new Date(); //選択中の日付 -(3)
var TODAY = new Date();
var TODAY_YEAR = TODAY.getFullYear();
var TODAY_MONTH = TODAY.getMonth();
var TODAY_DATE = TODAY.getDate();
var CSS_PREFIX = "_gcal_";
function css(name){
return CSS_PREFIX + name;
}
// 選択中の日付セルを処理しやすくするために
// 日付セルにIDを付加する。そのIDをつくる関数 -(4)
function makeDateId(d){
return css([d.getFullYear(),
f(d.getMonth() + 1),
f(d.getDate())].join("-"));
function f(n){
return n < 10 ? "0" + n : n;
}
}
// calendar処理群としてまとめたので
// makeCalendarTableからmakeTableに名称変更
function makeTable(){
var DAYS = "Sunday Monday Tuesday Wednesday Thursday Friday Saturday".split(" ");
$rm($(css("")));// 別の月に変更する場合のために以前の内容を破棄 -(2)
table = $table({id:css("")}); //-(2)
$add(frame, table); //-(2)
setMonthHeader();
setDayHeader();
setDates();
setStyle();
return frame;
function setMonthHeader(){
// curDateの年/月を使う
var year = curDate.getFullYear(); // -(3)
var month = curDate.getMonth() + 1; // -(3)
$add(table,
$add($tr({className:css("header")}),
$add($th({className:css("header"), colSpan:7}), year + "/" + month)));
}
// 中略
function setDates(){
// curDate自体を動かさないように,
// curDateを複製して表示用Dateオブジェクトとして利用する
var d = new Date(curDate); // -(3)
var nextMonth = d.getMonth() < 11 ? d.getMonth() + 1 : 0;
d.setDate(1);
d.setDate(-d.getDay() + 1);
// 中略
/**
* 年月日が一致したときのみ「今日」の見栄えにする
*/
function setClassName(td, d){
var buffer = [];
if(d.getMonth() == curDate.getMonth()){ // -(3)
buffer.push(css("onDate"));
buffer.push(css(DAYS[d.getDay()]));
} else {
buffer.push(css("outDate"));
}
if(d.getDate() == TODAY_DATE &&
d.getMonth() == TODAY_MONTH &&
d.getFullYear() == TODAY_YEAR){
buffer.push(css("today"));
}
td.className = buffer.join(" ");
}
}
function setStyle(){
var style =
<><![CDATA[
//中略
#_gcal_ td._gcal_select { //-(5)
color : gold;
font-weight : bold;
border-top : 1px solid white;
border-left : 1px solid white;
border-bottom : 1px solid #666666;
border-right : 1px solid #666666;
background-color:#FFFFEE;
}
]]></>;
GM_addStyle(style);
}
}
var gPanel = null;
function toggleCalendar(){
if(!gPanel) {
gPanel = $add($div({id:"_gpanel"}), makeTable());
$add(document.body, gPanel);
selectDate(curDate);
}
with(gPanel.style){
if(display != "block"){
display = "block";
} else {
display = "none";
}
}
}
/* 図2のA部分がここにくる */
// 外部インタフェースとなるオブジェクトを返す // -(1)
return {toggle:toggleCalendar,
nextMonth:makeGoMonthOffset(1),
previousMonth:makeGoMonthOffset(-1),
goToday:goToday,
nextDate:makeGoDateOffset(1),
previousDate:makeGoDateOffset(-1),
nextWeek:makeGoDateOffset(7),
previousWeek:makeGoDateOffset(-7)
};
})();
/* 図2のB部分がここにくる */
前回からの変更点はいくつかありますが,
(1) カレンダ処理をオブジェクトにまとめたこれまでのユーザスクリプトではカレンダ処理は
「実行時の月のカレンダを表示する」 という処理一つだけだったのですが, 今回からは選択日の移動処理や月の移動処理など複数の処理を定義する必要が出てきました。それら複数の処理を定義するために, 複数の関数を定義するわけですが, それらの関数は次の二つの種類に分けられます。 (a) カレンダ処理を利用するために呼び出す関数。(b) 関数の定義のために定義した関数。カレンダ処理のために直接呼び出すことはない。
この二種類の関数定義がそのまま混在していると混乱の元ですし,
間違って (b) のタイプの関数を呼び出してしまうと意図せず (a) の処理に影響してしまう可能性もあります。そのため, (a) のタイプの関数だけを外部から呼び出せるようにし, (b) のタイプの関数を内部に閉じ込めて外部から呼び出すことができないようにするため, オブジェクトの形にまとめるようにしました。 (2) 月の変更に応じたカレンダテーブルの削除処理のため,それを囲むdiv要素を加えた 月を変更したときはカレンダを表すテーブルを一旦削除し,
改めて変更した月に応じたカレンダテーブルを生成するように処理を変更しました。そのため, 再生成したカレンダテーブルを配置する 「場所」 が必要になり, その役目をするdiv要素を置くことにしました。 (3) 選択日に応じてカレンダを生成するようにしたこれまではnew Date()によって得られる実行時の日付
(の月) に応じたカレンダを生成していましたが, 「選択日」 を変数curDateで表すこととして, その日付に応じてカレンダを生成するようにしました。 (4) 日付セルを処理しやすくするため,IDを付加するようにした 「選択日」 がどれなのか, 表示上分かりやすくするために選択日を示す日付セルのclass属性の値を変えて見栄えを変えるようにしました。この日付セルの見栄えを変更する処理のため, 見栄えを変更すべき日付セルを特定する必要が必要になるわけですが, この日付セルの特定を簡単に行えるようにするため各日付セルにID属性を付加することにしました。今回追加したユーティリティ関数 「$」 を使うことで, IDを指定すれば簡単に所望の日付セル要素を取得できるからです。 (5) 選択日のスタイル定義を追加したカレンダテーブル中の日付セルのうちどれが
「選択日」 なのか一目で分かるよう, スタイル定義を追加しました。
以上,