カレンダーへの祝日表示の標準機能化
カレンダーには祝日を表示する機能がありません。本体を改修せずに表示する方法(CSS 方式・拡張スクリプトで祝日マスタを読む方式)は カレンダー にあります。このページは、祝日マスタを本体の機能として読み込む改修の設計メモです。本体の標準機能ではありません。
前提にした現行実装(1.5.8.1)
カレンダーの種類
| 種類 | 実装 | CalendarTypes |
|---|---|---|
| 標準 | サーバーで HTML の表を出力(HtmlCalendar.cs) | Standard = 1 |
| FullCalendar | FullCalendar(@fullcalendar/core 6.1.21)をブラウザで初期化(calendar.ts) | FullCalendar = 2 |
既定は General.json の DefaultCalendarType: 2(FullCalendar)です(SiteSettings.cs、General.json)。
標準カレンダーの日付セル
月表示の日付セル(td)に付くクラスは container、当日の today、表示月以外の other-month だけです。data-id に yyyy/M/d の日付が入ります(HtmlCalendar.cs)。曜日のクラス(sunday・saturday など、DayOfWeekCss() が DayOfWeek を小文字にしたもの)は見出しの th にだけ付きます(HtmlCalendar.cs)。
FullCalendar の初期化
calendar.ts で $p.fullCalendars[calendarSuffix] に FullCalendar.Calendar を作ります。レコードは events: getEventsData(calendarSuffix) で、隠し項目 #CalendarJson{サフィックス} の JSON から作っています(calendar.ts)。
参考にするアナウンス機能
アナウンスは Service.json の AnnouncementSiteId で指定した期限付きテーブルから、Status < CompletionCode かつ StartTime <= 現在 <= CompletionTime のレコードを IssueCollection で読み、画面上部に出します(HtmlHeaders.cs)。IssueCollection の取得は渡した条件(サイト ID・状況・日時)だけで SELECT し、権限の条件は足しません(IssueCollection.cs)。そのため、マスタのサイトに読み取り権限が無いユーザーやログイン前の画面にも表示されます。表示制御の詳細は アナウンス機能の改善 にあります。
設計
アナウンスとの対応
| 項目 | アナウンス | 祝日(追加) |
|---|---|---|
| テーブル | 期限付きテーブル | 記録テーブル |
| パラメータ | AnnouncementSiteId | HolidaySiteId(追加) |
| 日付 | StartTime / CompletionTime | DateA |
| 名称 | Title | Title |
| 有効・無効 | Status < CompletionCode | Status < CompletionCode |
| 表示先 | 画面上部 | カレンダーの日付 |
パラメータ
Implem.ParameterAccessor/Parts/Service.cs に public long HolidaySiteId { get; set; } を足し、App_Data/Parameters/Service.json に "HolidaySiteId": 0 を足します。0 なら機能は動きません。
祝日マスタ
| 項目 | 用途 | 例 |
|---|---|---|
Title | 祝日の名前 | 元日 |
DateA | 日付 | 2026/01/01 |
Status | 有効・無効 | 100 |
Status が CompletionCode(既定 900)未満のものを有効とし、レコードを消さずに 900 以上にして無効にできるようにします。複数年分を登録でき、表示中の期間で DateA を絞ります。
public static ResultCollection GetHolidays(Context context, DateTime begin, DateTime end)
{
var siteId = Parameters.Service.HolidaySiteId;
if (siteId <= 0) return null;
var ss = SiteSettingsUtilities.Get(context: context, siteId: siteId);
return new ResultCollection(
context: context,
ss: ss,
where: Rds.ResultsWhere()
.SiteId(siteId)
.Status(_operator: $"<{Parameters.General.CompletionCode}")
.DateA(begin, _operator: ">=")
.DateA(end, _operator: "<="));
}図を読み込み中…
標準カレンダー
月表示(MonthlyTable)と週表示の日付セルで、祝日の日に holiday クラスと名前の span を足します。
var holidays = GetHolidays(context, begin, end)?
.ToDictionary(
r => r.DateA.ToLocal(context: context).Date,
r => r.Title.Value);
var isHoliday = holidays?.ContainsKey(currentDate) == true;
// .Class("container" + … + (isHoliday ? " holiday" : string.Empty))
// 日付の div のあとに
// .Span(css: "holiday-name", action: () => hb.Text(holidays[currentDate]), _using: isHoliday)同じ日付の祝日が複数あると ToDictionary が失敗するので、実装では日付でまとめるか重複を除きます。
スタイルは legacy.scss と style.scss(Implem.PleasanterFrontend/wwwroot/src/styles/)に足します。
.CalendarBody .holiday {
background-color: var(--commonColor02Sub);
}
.CalendarBody .holiday .holiday-name {
display: block;
font-size: 0.75em;
color: var(--commonColor02);
}FullCalendar
FullCalendar は display: 'background' の背景イベントを持てます。祝日を別のイベントソースとして渡し、レコードのイベントとは別の層に出します。
// HtmlCalendar.cs の CalendarBody の隠し項目に追加
hb.Hidden(
controlId: $"HolidayJson{suffix}",
value: GetHolidays(context, begin, end)?
.Select(r => new
{
Title = r.Title.Value,
DateA = r.DateA.ToLocal(context: context).ToString("yyyy-MM-dd")
})
.ToJson());const getHolidayEvents = (calendarSuffix: string) => {
const json = String($(`#HolidayJson${calendarSuffix}`).val() ?? '');
if (!json) return [];
return JSON.parse(json).map((holiday: { Title: string; DateA: string }) => ({
title: holiday.Title,
start: holiday.DateA,
display: 'background',
classNames: ['holiday-event']
}));
};
// 初期化の events を eventSources にする
// eventSources: [
// { events: getEventsData(calendarSuffix) },
// { events: getHolidayEvents(calendarSuffix) }
// ]改修箇所
| ファイル | 内容 |
|---|---|
Implem.ParameterAccessor/Parts/Service.cs | HolidaySiteId |
App_Data/Parameters/Service.json | HolidaySiteId |
Libraries/HtmlParts/HtmlCalendar.cs | 祝日の取得、日付セルのクラスと名前、HolidayJson の隠し項目 |
wwwroot/src/scripts/generals/calendar.ts | 背景イベントの追加 |
wwwroot/src/styles/legacy.scss・style.scss | .holiday |
カレンダーの一部の処理は CodeDefiner のテンプレート App_Data/Definitions/Definition_Code/Model_Utilities_Calendar_Body.txt から生成されます。各モデルの *Utilities.cs 側に手を入れる場合はテンプレートも直してください(CodeDefiner)。パラメータの追加だけなら生成コードには影響しません。
考慮事項
- 件数と負荷: 祝日は年に 20 件程度なので、表示のたびに引いても負荷は小さいです。月を切り替えるたびにクエリが走るのを避けたい場合はメモリキャッシュを検討しますが、マスタを更新したときの無効化が必要になります。
- 権限: アナウンスと同じく
ResultCollectionで引くと権限の条件は入らないので、マスタのサイトの権限に関係なく全員のカレンダーに祝日が出ます。祝日は全員に見せる情報なのでこれで困りませんが、マスタの編集はサイトの権限で管理者に絞ります。権限で出し分けたい場合は、Permissions.SetPermissionsWhere()などで権限の条件を足す必要があります。 - 標準と FullCalendar の両方: 作りが違う(サーバーの HTML と、ブラウザのイベント)ので、別々に実装します。