diff --git a/lib/ui.js b/lib/ui.js
index 4a8167d..92c96ec 100644
--- a/lib/ui.js
+++ b/lib/ui.js
@@ -10,6 +10,7 @@ import { GridColumn, GridInputColumn, GridDropdownColumn, GridCheckboxColumn, Gr
import { Popup, createPopup, showAlert, showConfirm } from "./ui/popup";
import { createPicture, createAudio, createVideo, createFile } from './ui/media';
import { validation, convertCssStyle } from './ui/extension';
+import { createDateInput, formatDate, setDateValue, getDateValue, DateSelector } from './ui/date';
export {
createElement,
@@ -40,6 +41,12 @@ export {
createPopup,
showAlert,
showConfirm,
+ // dateSelector
+ createDateInput,
+ formatDate,
+ setDateValue,
+ getDateValue,
+ DateSelector,
// media
createPicture,
createAudio,
diff --git a/lib/ui/css/grid.scss b/lib/ui/css/grid.scss
index 762c4be..5c492aa 100644
--- a/lib/ui/css/grid.scss
+++ b/lib/ui/css/grid.scss
@@ -320,7 +320,7 @@
}
.ui-check-wrapper {
- display: flex;
+ display: inline-flex;
justify-content: center;
.ui-check-inner {
diff --git a/lib/ui/date.d.ts b/lib/ui/date.d.ts
index 557062e..e5e3715 100644
--- a/lib/ui/date.d.ts
+++ b/lib/ui/date.d.ts
@@ -1,10 +1,11 @@
/**
- * 创建日期选择框
+ * 创建或转换日期选择框
* @param min 最小可选日期
* @param max 最大可选日期
- * @returns 返回创建的日期选择框
+ * @param element 转换该元素为日期选择框
+ * @returns 返回创建或转换的日期选择框
*/
-export function createDateInput(min?: string, max?: string): HTMLInputElement;
+export function createDateInput(min?: string, max?: string, element?: HTMLInputElement): HTMLInputElement;
/**
* 格式化日期字符串
@@ -36,22 +37,48 @@ export function getDateValue(element: HTMLInputElement, formatter?: (date: Date)
/** 日期选择框类 */
export class DateSelector {
/**
- * 日期发生变化时触发的事件
- * @param date 日期值,或者经自定义参数中格式化函数格式后的值
+ * 把父容器下所有匹配 `input[data-type="date"]` 的元素修改为统一的日期选择框
+ * 解析的属性为 `id`, `class`, `data-min`, `data-max`, `disabled`
+ * @param dom 父元素
+ * @param trigger 日期设置事件触发函数(上下文为触发设置日期的 `DateSelector` 实例)
+ * @example
+ * HTML:
+ * ```html
+ *
+ * ```
+ * js:
+ * ```js
+ * const libUI = window['lib-ui'];
+ * const DateSelector = libUI.DateSelector;
+ * const formatDate = libUI.formatDate;
+ *
+ *
+ * // 解析 document.body 下所有符合条件的元素,转换为日期选择框,第二个参数可选
+ * DateSelector.resolve(document.body, function (date) {
+ * console.log(`element(#${this.element.id}), date changed to: ${formatDate(date)}`);
+ * // 当日期选择改变时,控制台将会输出:element(#dateFrom), date changed to: 1/30/2024
+ * });
+ *
+ *
+ * // 在其他地方调用时
+ * const value = document.querySelector('#dateFrom').value;
+ * console.log(`dateFrom.value = '${value}', formatted: '${formatDate(value)}'`);
+ * // 控制台会输出:dateFrom.value = '2024-01-30', formatted: '1/30/2024'
+ * ```
*/
- onDateChanged?: (date: Date | any) => void;
+ static resolve(dom?: HTMLElement, trigger?: (date: Date) => void): HTMLElement;
/**
* 日期选择框构造函数
* @param opts 日期选项参数
*/
constructor(opts: {
- /** 父容器元素,可以为 `string` 作为选择器 */
- parent: HTMLElement | string,
/** 最小可选择日期 */
minDate?: string,
/** 最大可选择日期 */
maxDate?: string,
+ /** 是否启用 */
+ enabled?: boolean,
/**
* 自定义格式化函数,用于获取日期值时调用
* @param date 日期值
@@ -60,12 +87,40 @@ export class DateSelector {
valueFormatter?: (date: Date) => any
});
+ /**
+ * 创建或转换日期选择框元素
+ * @param element 转换该元素为日期选择框
+ * @returns 返回创建或转换的日期选择元素
+ */
+ create(element?: HTMLInputElement): HTMLInputElement;
+
+ /** 获取日期选择框元素 */
+ get element(): HTMLInputElement;
+
+ /** 获取日期选择框是否启用 */
get enabled(): boolean;
+ /** 设置日期选择框启用状态 */
set enabled(flag: boolean);
+ /** 获取设置的日期值,或经过格式化函数返回的值 */
get value(): Date | any;
+ /** 设置日期值,支持的格式参见 {@linkcode formatDate} */
set value(val: Date | number | string);
+ /** 获取最小可选择日期 */
+ get minDate(): string;
+ /** 设置最小可选择日期 */
set minDate(date: string);
+
+ /** 获取最大可选择日期 */
+ get maxDate(): string;
+ /** 设置最大可选择日期 */
set maxDate(date: string);
+
+ /**
+ * 日期发生变化时触发的事件
+ * @param date 日期值,或者经自定义参数中格式化函数格式后的值
+ * @eventProperty
+ */
+ onDateChanged?: (date: Date | any) => void;
}
\ No newline at end of file
diff --git a/lib/ui/date.js b/lib/ui/date.js
index e01375a..018efd2 100644
--- a/lib/ui/date.js
+++ b/lib/ui/date.js
@@ -1,7 +1,13 @@
import { createElement } from "../functions";
-export function createDateInput(min, max) {
- const date = createElement('input', 'ui-date-cell');
+export function createDateInput(min, max, element) {
+ let date;
+ if (element instanceof HTMLInputElement) {
+ date = element;
+ date.classList.add('ui-date-cell');
+ } else {
+ date = createElement('input', 'ui-date-cell');
+ }
date.required = true;
date.type = 'date';
if (min != null) {
@@ -89,16 +95,15 @@ export class DateSelector {
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);
+ create(element) {
+ const opts = this._var.options;
+ const el = createDateInput(opts.minDate, opts.maxDate, element);
+ if (element == null) {
+ el.disabled = opts.enabled === false;
+ }
el.addEventListener('blur', e => {
const date = this._getDate(e.target.valueAsDate);
if (date == null) {
@@ -109,9 +114,11 @@ export class DateSelector {
}
});
this._var.el = el;
- parent.appendChild(el);
+ return el;
}
+ get element() { return this._var.el }
+
get enabled() { return !this._var.el.disabled }
set enabled(flag) {
this._var.el.disabled = flag === false;
@@ -122,16 +129,13 @@ export class DateSelector {
setDateValue(this._var.el, val);
}
- /**
- * @param {string} date
- */
+ get minDate() { return this._var.el.min }
set minDate(date) {
this._var.el.min = date;
this._var.options.minDate = date;
}
- /**
- * @param {string} date
- */
+
+ get maxDate() { return this._var.el.max }
set maxDate(date) {
this._var.el.max = date;
this._var.options.maxDate = date;
@@ -150,4 +154,23 @@ export class DateSelector {
}
return null;
}
+
+ static resolve(dom = document.body, trigger) {
+ const dates = dom.querySelectorAll('input[data-type="date"]');
+ for (let dat of dates) {
+ const val = dat.value;
+ const dateSelector = new DateSelector({
+ minDate: dat.getAttribute('data-min'),
+ maxDate: dat.getAttribute('data-max')
+ });
+ if (typeof trigger === 'function') {
+ dateSelector.onDateChanged = date => trigger.call(dateSelector, date);
+ }
+ dat.removeAttribute('data-type');
+ dat.removeAttribute('data-min');
+ dat.removeAttribute('data-max');
+ dateSelector.create(dat);
+ dateSelector.value = val;
+ }
+ }
}
\ No newline at end of file
diff --git a/lib/ui/dropdown.d.ts b/lib/ui/dropdown.d.ts
index 14da60f..b69dbcc 100644
--- a/lib/ui/dropdown.d.ts
+++ b/lib/ui/dropdown.d.ts
@@ -47,11 +47,13 @@ export interface DropdownOptions {
/** 下拉框类 */
export class Dropdown {
/**
- * 把父元素下的所有 `select` 元素修改为统一下拉框组件
+ * 把父元素下的所有 `select` 元素修改为统一下拉框组件
+ * 解析的属性为 `value`, `disabled`, `tabIndex`
* @param dom 父元素
+ * @param trigger 选中事件触发函数(上下文为触发选中的 `Dropdown` 实例)
* @returns 返回该父元素
*/
- static resolve(dom?: HTMLElement): HTMLElement;
+ static resolve(dom?: HTMLElement, trigger?: (item: DropdownItem) => void): HTMLElement;
/**
* 下拉框的构造函数
diff --git a/lib/ui/dropdown.js b/lib/ui/dropdown.js
index 26e93e3..58e27ba 100644
--- a/lib/ui/dropdown.js
+++ b/lib/ui/dropdown.js
@@ -560,7 +560,7 @@ export class Dropdown {
}
}
- static resolve(dom = document.body) {
+ static resolve(dom = document.body, trigger) {
const selects = dom.querySelectorAll('select');
for (let sel of selects) {
const source = [...sel.children].map(it => {
@@ -572,6 +572,9 @@ export class Dropdown {
tabIndex: sel.tabIndex
});
drop.source = source;
+ if (typeof trigger === 'function') {
+ drop.onSelected = item => trigger.call(drop, item);
+ }
sel.parentElement.replaceChild(drop.create(), sel);
}
return dom;
diff --git a/lib/ui/grid/grid.js b/lib/ui/grid/grid.js
index e94587d..0cd2ce9 100644
--- a/lib/ui/grid/grid.js
+++ b/lib/ui/grid/grid.js
@@ -975,6 +975,11 @@ export class Grid {
th.addEventListener('mousedown', e => this._onDragStart(e, col));
}
const wrapper = createElement('div');
+ if (col.align === 'right') {
+ wrapper.style.justifyContent = 'flex-end';
+ } else if (col.align === 'center') {
+ wrapper.style.justifyContent = 'center';
+ }
th.appendChild(wrapper);
if (!this.readonly && col.enabled !== false && col.allcheck && isCheckbox) {
const check = createCheckbox({
@@ -1239,6 +1244,8 @@ export class Grid {
const style = col.styleFilter(item);
if (style != null) {
type.setStyle(element, style);
+ } else {
+ element.style.cssText = '';
}
}
if (col.events != null) {
@@ -1562,7 +1569,12 @@ export class Grid {
const th = filter.parentElement;
const width = th.offsetWidth;
panel.style.top = `${th.offsetHeight + this._var.el.scrollTop}px`;
- panel.style.left = (th.offsetLeft + (width > FilterPanelWidth ? width - FilterPanelWidth : 0)) + 'px';
+ const offsetLeft = th.offsetLeft;
+ const totalWidth = th.parentElement.offsetWidth;
+ const left = offsetLeft + FilterPanelWidth > totalWidth ?
+ totalWidth - FilterPanelWidth :
+ offsetLeft + (width > FilterPanelWidth ? width - FilterPanelWidth : 0);
+ panel.style.left = `${left}px`;
// search
let searchbox;
diff --git a/typedoc.json b/typedoc.json
index 32db27f..53db88a 100644
--- a/typedoc.json
+++ b/typedoc.json
@@ -1,5 +1,6 @@
{
"entryPoints": [
+ "lib/ui/date.d.ts",
"lib/ui/dropdown.d.ts",
"lib/ui/grid/column.d.ts",
"lib/ui/grid/grid.d.ts"