add: dateSelector

This commit is contained in:
2024-01-29 13:51:58 +08:00
parent 0696ecaff0
commit df42221b52
4 changed files with 230 additions and 68 deletions

View File

@ -348,7 +348,7 @@
} }
} }
.ui-grid-date-cell { .ui-date-cell {
line-height: 22px; line-height: 22px;
box-sizing: border-box; box-sizing: border-box;
padding: var(--spacing-cell); padding: var(--spacing-cell);

71
lib/ui/date.d.ts vendored Normal file
View File

@ -0,0 +1,71 @@
/**
* 创建日期选择框
* @param min 最小可选日期
* @param max 最大可选日期
* @returns 返回创建的日期选择框
*/
export function createDateInput(min?: string, max?: string): HTMLInputElement;
/**
* 格式化日期字符串
* @param date 要格式化的日期值<br/><br/>
* 支持以下几种数据类型<br/><br/>
* `"2024-01-26"`<br/>
* `"1/26/2024"`<br/>
* `"638418240000000000"`<br/>
* `new Date('2024-01-26')`<br/>
* @returns 格式化为 M/d/yyyy 的日期字符串
*/
export function formatDate(date: Date | number | string): string;
/**
* 设置显示日期
* @param element 要设置显示日期的元素
* @param val 日期值,支持格式参见 {@linkcode formatDate}
*/
export function setDateValue(element: HTMLElement, val: Date | number | string): void;
/**
* 从日期选择框获取日期值
* @param element 要获取的日期选择框
* @param formatter 自定义格式化函数,传入参数为 `Date` 类型
* @returns 默认返回日期 `ticks` 的字符串
*/
export function getDateValue(element: HTMLInputElement, formatter?: (date: Date) => string): string;
/** 日期选择框类 */
export class DateSelector {
/**
* 日期发生变化时触发的事件
* @param date 日期值,或者经自定义参数中格式化函数格式后的值
*/
onDateChanged?: (date: Date | any) => void;
/**
* 日期选择框构造函数
* @param opts 日期选项参数
*/
constructor(opts: {
/** 父容器元素,可以为 `string` 作为选择器 */
parent: HTMLElement | string,
/** 最小可选择日期 */
minDate?: string,
/** 最大可选择日期 */
maxDate?: string,
/**
* 自定义格式化函数,用于获取日期值时调用
* @param date 日期值
* @returns 返回格式化的值
*/
valueFormatter?: (date: Date) => any
});
get enabled(): boolean;
set enabled(flag: boolean);
get value(): Date | any;
set value(val: Date | number | string);
set minDate(date: string);
set maxDate(date: string);
}

153
lib/ui/date.js Normal file
View File

@ -0,0 +1,153 @@
import { createElement } from "../functions";
export function createDateInput(min, max) {
const date = createElement('input', 'ui-date-cell');
date.required = true;
date.type = 'date';
if (min != null) {
date.min = min;
}
if (max != null) {
date.max = max;
}
return date;
}
function toDateValue(dt) {
if (isNaN(dt)) {
return '';
}
const month = String(dt.getMonth() + 1).padStart(2, '0');
const date = String(dt.getDate()).padStart(2, '0');
return `${dt.getFullYear()}-${month}-${date}`;
}
function resolveDate(s) {
if (s instanceof Date) {
return s;
}
const ticks = Number(s);
if (!isNaN(ticks) && ticks > 0) {
return new Date((ticks - 621355968e9) / 1e4);
}
return new Date(s);
}
export function formatDate(date) {
date = resolveDate(date);
if (date instanceof Date && !isNaN(date)) {
return `${date.getMonth() + 1}/${date.getDate()}/${date.getFullYear()}`;
}
return '';
}
export function setDateValue(element, val) {
if (element.tagName === 'INPUT') {
if (val === '') {
element.value = '';
} else if (isNaN(val)) {
if (/^\d{4}-\d{2}-\d{2}$/.test(val)) {
element.value = val;
} else if (/^\d{1,2}\/\d{1,2}\/\d{4}$/.test(val)) {
element.value = toDateValue(new Date(val));
} else {
element.value = '';
}
} else {
if (!(val instanceof Date)) {
val = new Date((val - 621355968e9) / 1e4);
}
element.value = toDateValue(val);
}
} else {
element.innerText = formatDate(val);
}
}
export function getDateValue(element, formatter) {
const date = element?.valueAsDate;
if (date instanceof Date && !isNaN(date)) {
const year = date.getFullYear();
if (year < 1900 || year > 9999) {
return '';
}
if (typeof formatter === 'function') {
return formatter(date);
}
return String(date.getTime() * 1e4 + 621355968e9);
}
return '';
}
export class DateSelector {
_var = {
parent: null,
options: null
};
onDateChanged;
constructor(opts) {
opts ??= {};
if (typeof opts.parent === 'string') {
opts.parent = document.querySelector(opts.parent);
}
if (!(opts.parent instanceof HTMLElement)) {
throw new Error('no specified parent.');
}
this._var.options = opts;
this._var.parent = opts.parent;
const el = createDateInput(opts.minDate, opts.maxDate);
el.addEventListener('blur', e => {
const date = this._getDate(e.target.valueAsDate);
if (date == null) {
e.target.value = '';
}
if (typeof this.onDateChanged === 'function') {
this.onDateChanged(date);
}
});
this._var.el = el;
parent.appendChild(el);
}
get enabled() { return !this._var.el.disabled }
set enabled(flag) {
this._var.el.disabled = flag === false;
}
get value() { return this._getDate(this._var.el.valueAsDate) }
set value(val) {
setDateValue(this._var.el, val);
}
/**
* @param {string} date
*/
set minDate(date) {
this._var.el.min = date;
this._var.options.minDate = date;
}
/**
* @param {string} date
*/
set maxDate(date) {
this._var.el.max = date;
this._var.options.maxDate = date;
}
_getDate(date) {
if (date instanceof Date && !isNaN(date)) {
const year = date.getFullYear();
if (year < 1900 || year > 9999) {
return null;
}
if (typeof this._var.options.valueFormatter === 'function') {
return this._var.options.valueFormatter(date);
}
return date;
}
return null;
}
}

View File

@ -1,11 +1,11 @@
import { global } from "../../utility"; import { global } from "../../utility";
// import { nullOrEmpty } from "../../utility/strings";
import { createElement } from "../../functions"; import { createElement } from "../../functions";
import { createIcon } from "../icon"; import { createIcon } from "../icon";
import { createCheckbox } from "../checkbox"; import { createCheckbox } from "../checkbox";
// import { setTooltip } from "../tooltip"; // import { setTooltip } from "../tooltip";
import { Dropdown } from "../dropdown"; import { Dropdown } from "../dropdown";
import { convertCssStyle } from "../extension"; import { convertCssStyle } from "../extension";
import { createDateInput, formatDate, setDateValue, getDateValue } from "../date";
export class GridColumn { export class GridColumn {
static create() { static create() {
@ -296,87 +296,25 @@ export class GridDateColumn extends GridColumn {
if (enabled === false) { if (enabled === false) {
return super.create(); return super.create();
} }
const date = createElement('input', 'ui-grid-date-cell'); const date = createDateInput(col.dateMin, col.dateMax);
date.required = true;
date.type = 'date';
if (col.dateMin != null) {
date.min = col.dateMin;
}
if (col.dateMax != null) {
date.max = col.dateMax;
}
// date.addEventListener('change', trigger); // date.addEventListener('change', trigger);
date.addEventListener('blur', trigger); date.addEventListener('blur', trigger);
return date; return date;
} }
static setValue(element, val) { static setValue(element, val) {
if (element.tagName === 'INPUT') { setDateValue(element, val);
if (val === '') {
element.value = '';
} else if (isNaN(val)) {
if (/^\d{4}-\d{2}-\d{2}$/.test(val)) {
element.value = val;
} else if (/^\d{1,2}\/\d{1,2}\/\d{4}$/.test(val)) {
element.value = this._toDateValue(new Date(val));
} else {
element.value = '';
}
} else {
if (!(val instanceof Date)) {
val = new Date((val - 621355968e9) / 1e4);
}
element.value = this._toDateValue(val);
}
} else {
element.innerText = this.formatDate(val);
}
} }
static getValue(e, col) { static getValue(e, col) {
const date = e.target?.valueAsDate; return getDateValue(e.target, col.dateValueFormatter);
if (date instanceof Date && !isNaN(date)) {
const year = date.getFullYear();
if (year < 1900 || year > 9999) {
return '';
}
if (typeof col.dateValueFormatter === 'function') {
return col.dateValueFormatter(date);
}
return String(date.getTime() * 1e4 + 621355968e9);
}
return '';
} }
static setEnabled(element, enabled) { static setEnabled(element, enabled) {
element.disabled = enabled === false; element.disabled = enabled === false;
} }
static _toDateValue(dt) {
if (isNaN(dt)) {
return '';
}
const month = String(dt.getMonth() + 1).padStart(2, '0');
const date = String(dt.getDate()).padStart(2, '0');
return `${dt.getFullYear()}-${month}-${date}`;
}
static _resolveDate(s) {
if (s instanceof Date) {
return s;
}
const ticks = Number(s);
if (!isNaN(ticks) && ticks > 0) {
return new Date((ticks - 621355968e9) / 1e4);
}
return new Date(s);
}
static formatDate(date) { static formatDate(date) {
date = this._resolveDate(date); return formatDate(date);
if (date instanceof Date && !isNaN(date)) {
return `${date.getMonth() + 1}/${date.getDate()}/${date.getFullYear()}`;
}
return '';
} }
} }