日付項目の入力モードと表示形式の拡張
日付項目について、次の 3 つを本体に足す設計メモです。本体の標準機能ではありません。
| 追加するもの | 現行 | 改修の規模 |
|---|---|---|
| 年月だけ・年だけを選ぶ入力モード | 無い(エディタの書式は年月日・日時(分)・日時(秒)の 3 つ) | 年月: 中、年: 大 |
| 入力できる日付の範囲(今日から N 日前まで など) | 無い | 小 |
| 一覧の表示形式に任意の書式を指定する | 決まった選択肢だけ | 小 |
拡張機能だけで年月モードを付ける方法は 日付項目に年月モードを追加する にあります。
前提にした現行実装
日付ピッカーの切り替え
日付項目は、General.json の UseOldDatepicker が false(既定)でテーマが 2 世代目なら <date-field> カスタム要素(flatpickr)、それ以外は従来の jquery.datetimepicker で描画されます(HtmlControls.cs)。スマートデザインの画面では、別に Svelte の日付コンポーネントが flatpickr を使います。
<date-field> は input の data-* 属性から flatpickr のオプションを組み立てます(datefield.ts)。
| 属性 | 使い道 | 出力する場所 |
|---|---|---|
data-format | 書式。:s を含めば秒も入力 | HtmlAttributes.DataFormat(HtmlAttributes.cs) |
data-timepicker | 1 なら時刻も入力 | HtmlAttributes.DataTimepicker |
data-step | 分の刻み | HtmlAttributes.DataStep |
data-hide-current | 「現在」ボタンを隠す | HtmlAttributes.DataHideCurrent |
minDate・maxDate を渡す属性はありません。flatpickr の月選択プラグイン(monthSelectPlugin)はバンドルに含まれていません。
エディタの書式(EditorFormat)
Column.DateTimeFormat() は EditorFormat が Ymdhm・Ymdhms ならその書式、それ以外は Ymd の書式を返します(Column.cs)。テーブルの管理の選択肢も Ymd・Ymdhm・Ymdhms の 3 つです(SiteUtilities.cs)。
一覧の表示形式(GridFormat)
一覧の書式の選択肢は、App_Data/Displays/ の Type が 120(日付)の表示名すべてです(SiteUtilities.cs)。1.5.8.1 では次の 8 つです。
| GridFormat | 表示名(日本語) | 書式(日本語) |
|---|---|---|
Ymd | 年月日 | yyyy/MM/dd |
Ymda | 年月日曜 | yyyy/MM/dd ddd |
Ymdhm | 日付と時刻(分) | yyyy/MM/dd HH:mm |
Ymdhms | 日付と時刻(秒) | yyyy/MM/dd HH:mm:ss |
Ymdahm | 日付と曜日と時刻(分) | yyyy/MM/dd ddd HH:mm |
Ymdahms | 日付と曜日と時刻(秒) | yyyy/MM/dd ddd HH:mm:ss |
Ym | 年月 | yyyy/MM |
Md | 月日 | MM/dd |
表示するときは、GridFormat の値に Format を付けた ID(YmdFormat など)の表示名を .NET の書式文字列として使います(FormatExtension.cs、Column.cs)。Displays.Get は ID が見つからないとき ID の文字列をそのまま返します(Displays.cs)。
数値項目のカスタム書式(参考)
数値項目の「書式」は、ドロップダウン FormatSelector(送信しない)とテキストボックス Format(送信する)の 2 段です。選択肢に「カスタム」(キーはタブ文字 \t)があり、選ぶとテキストボックスが表示されます。定義済みの選択肢に無い値が入っていればカスタムとみなします(SiteUtilities.cs、L9267-L9276、sitesettingsevents.js)。
1. 年月だけを選ぶモード
flatpickr の monthSelectPlugin を使うと、カレンダーの代わりに 12 か月の一覧が出て、年月だけを選べます。
図を読み込み中…
- 保存する値は、選んだ月の 1 日 0 時にします。サーバーは文字列を
DateTimeとして解析するので、日を01に固定した形(Y/m/01)でinputに入れれば、サーバー側を変えずに保存できます。 datefield.tsでdata-formatが年月の書式ならplugins: [monthSelectPlugin({ dateFormat: 'Y/m/01', altFormat: 'Y/m' })]を渡します。- プラグインは flatpickr のパッケージに含まれているので、
package.jsonの変更は要りません。ビルドに取り込むためのimportを足します。
| ファイル | 内容 |
|---|---|
Libraries/Settings/Column.cs | DateTimeFormat()・DateTimepicker() に Ym を足す |
Models/Sites/SiteUtilities.cs | DateTimeOptions(editorFormat: true) に Ym を足す |
App_Data/Displays/YmDatePickerFormat.json | 年月の書式 |
Implem.PleasanterFrontend/wwwroot/src/scripts/modules/datefield.ts | monthSelectPlugin を適用する |
| スマートデザインの Svelte コンポーネント | 同上 |
2. 年だけを選ぶモード
flatpickr には年だけを選ぶ公式のプラグインがありません。
| 方法 | 内容 | 難しさ |
|---|---|---|
| flatpickr の DOM を書き換える | onReady で日付の一覧や月の選択を隠し、onYearChange で値を確定する | 大。flatpickr の内部構造に依存する |
<select> にする | 年の一覧を出すドロップダウン | 小。年の範囲を決める必要がある |
| 数値項目で年を持つ | 日付項目を使わない | 小 |
保守を考えると、日付項目で年だけを選ばせるより、<select> や数値項目で年を持つほうが現実的です。
3. 入力できる日付の範囲
flatpickr の minDate・maxDate で、選べる日付を制限できます。'today' や Date を渡せ、flatpickr が足す Date.prototype.fp_incr(n) で「今日から n 日後(負なら前)」を作れます。
| 設定値(案) | 意味 |
|---|---|
today | 今日 |
+7 | 今日から 7 日後 |
-30 | 今日から 30 日前 |
2026/01/01 | 固定の日付 |
private parseDateConstraint(value?: string) {
if (!value) return undefined;
if (value === 'today') return 'today';
const n = parseInt(value, 10);
if (/^[+-]?\d+$/.test(value) && !isNaN(n)) return new Date().fp_incr(n);
return value;
}
// initDatePicker のオプションに追加
// minDate: this.parseDateConstraint(this.inputElm.dataset.minDate),
// maxDate: this.parseDateConstraint(this.inputElm.dataset.maxDate),| ファイル | 内容 |
|---|---|
Libraries/Settings/Column.cs | 範囲の設定値を持つプロパティ |
Libraries/Html/HtmlAttributes.cs | data-min-date・data-max-date を出すメソッド |
Libraries/HtmlParts/HtmlControls.cs | 日付の入力欄に属性を出す |
datefield.ts・Svelte コンポーネント | 属性を読んで flatpickr に渡す |
ピッカーでの制限は入力補助です。手入力や API で範囲外の値が入るのを防ぐには、サーバー側の入力チェックも別に必要です。特定の日や曜日を選べなくする disable も flatpickr にありますが、サーバーから一覧を渡す仕組みが別に要ります。
4. 一覧の表示形式に任意の書式を指定する
数値項目のカスタム書式と同じ 2 段の UI にします。
if (column.TypeName == "datetime")
{
var options = DateTimeOptions(context: context); // 末尾に "\t"(カスタム)を足す
var custom = !column.GridFormat.IsNullOrEmpty()
&& !options.Keys.Contains(column.GridFormat);
hb
.FieldDropDown(
context: context,
controlId: "GridFormatSelector",
controlCss: " not-send",
labelText: Displays.GridFormat(context: context),
optionCollection: options,
selectedValue: custom ? "\t" : column.GridFormat)
.FieldTextBox(
fieldId: "CustomGridFormatField",
controlId: "GridFormat",
fieldCss: custom ? string.Empty : " hidden",
labelText: Displays.Custom(context: context),
text: custom ? column.GridFormat : string.Empty);
}sitesettingsevents.js に #GridFormatSelector の change を足し、#FormatSelector と同じくテキストボックスの表示と #GridFormat の値を切り替えます。
表示側の FormatExtension.Display は、{GridFormat}Format が表示名に無ければ(Displays.Get が ID をそのまま返したら)GridFormat を書式文字列として使うようにします。
var id = format + "Format";
var resolved = Displays.Get(context: context, id: id);
var pattern = resolved == id ? format : resolved;GridFormatは文字列なので、ColumnとSiteSettingsの変更は要りません。- 不正な書式文字列だと
DateTime.ToStringがFormatExceptionを投げるので、保存時の検証と表示時のtry-catchを入れます。 yyyy'年'MM'月'dd'日'のように引用符で任意の文字を入れられます。
| ファイル | 内容 |
|---|---|
Libraries/Extensions/FormatExtension.cs | カスタム書式のフォールバック |
Models/Sites/SiteUtilities.cs | DateTimeOptions にカスタムを足し、一覧の書式の UI を 2 段にする |
Implem.PleasanterFrontend/wwwroot/src/scripts/generals/sitesettingsevents.js | #GridFormatSelector のイベント |