export DateSelector, fix issue about column.align and filter panel position of the last header cell.
This commit is contained in:
parent
df42221b52
commit
0b897cae8a
@ -10,6 +10,7 @@ import { GridColumn, GridInputColumn, GridDropdownColumn, GridCheckboxColumn, Gr
|
|||||||
import { Popup, createPopup, showAlert, showConfirm } from "./ui/popup";
|
import { Popup, createPopup, showAlert, showConfirm } from "./ui/popup";
|
||||||
import { createPicture, createAudio, createVideo, createFile } from './ui/media';
|
import { createPicture, createAudio, createVideo, createFile } from './ui/media';
|
||||||
import { validation, convertCssStyle } from './ui/extension';
|
import { validation, convertCssStyle } from './ui/extension';
|
||||||
|
import { createDateInput, formatDate, setDateValue, getDateValue, DateSelector } from './ui/date';
|
||||||
|
|
||||||
export {
|
export {
|
||||||
createElement,
|
createElement,
|
||||||
@ -40,6 +41,12 @@ export {
|
|||||||
createPopup,
|
createPopup,
|
||||||
showAlert,
|
showAlert,
|
||||||
showConfirm,
|
showConfirm,
|
||||||
|
// dateSelector
|
||||||
|
createDateInput,
|
||||||
|
formatDate,
|
||||||
|
setDateValue,
|
||||||
|
getDateValue,
|
||||||
|
DateSelector,
|
||||||
// media
|
// media
|
||||||
createPicture,
|
createPicture,
|
||||||
createAudio,
|
createAudio,
|
||||||
|
@ -320,7 +320,7 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.ui-check-wrapper {
|
.ui-check-wrapper {
|
||||||
display: flex;
|
display: inline-flex;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
|
|
||||||
.ui-check-inner {
|
.ui-check-inner {
|
||||||
|
71
lib/ui/date.d.ts
vendored
71
lib/ui/date.d.ts
vendored
@ -1,10 +1,11 @@
|
|||||||
/**
|
/**
|
||||||
* 创建日期选择框
|
* 创建或转换日期选择框
|
||||||
* @param min 最小可选日期
|
* @param min 最小可选日期
|
||||||
* @param max 最大可选日期
|
* @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 {
|
export class DateSelector {
|
||||||
/**
|
/**
|
||||||
* 日期发生变化时触发的事件
|
* 把父容器下所有匹配 `input[data-type="date"]` 的元素修改为统一的日期选择框<br/><br/>
|
||||||
* @param date 日期值,或者经自定义参数中格式化函数格式后的值
|
* 解析的属性为 `id`, `class`, `data-min`, `data-max`, `disabled`
|
||||||
|
* @param dom 父元素
|
||||||
|
* @param trigger 日期设置事件触发函数(上下文为触发设置日期的 `DateSelector` 实例)
|
||||||
|
* @example
|
||||||
|
* HTML:
|
||||||
|
* ```html
|
||||||
|
* <input id="dateFrom" data-type="date" data-min="1980-01-01"/>
|
||||||
|
* ```
|
||||||
|
* 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 日期选项参数
|
* @param opts 日期选项参数
|
||||||
*/
|
*/
|
||||||
constructor(opts: {
|
constructor(opts: {
|
||||||
/** 父容器元素,可以为 `string` 作为选择器 */
|
|
||||||
parent: HTMLElement | string,
|
|
||||||
/** 最小可选择日期 */
|
/** 最小可选择日期 */
|
||||||
minDate?: string,
|
minDate?: string,
|
||||||
/** 最大可选择日期 */
|
/** 最大可选择日期 */
|
||||||
maxDate?: string,
|
maxDate?: string,
|
||||||
|
/** 是否启用 */
|
||||||
|
enabled?: boolean,
|
||||||
/**
|
/**
|
||||||
* 自定义格式化函数,用于获取日期值时调用
|
* 自定义格式化函数,用于获取日期值时调用
|
||||||
* @param date 日期值
|
* @param date 日期值
|
||||||
@ -60,12 +87,40 @@ export class DateSelector {
|
|||||||
valueFormatter?: (date: Date) => any
|
valueFormatter?: (date: Date) => any
|
||||||
});
|
});
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 创建或转换日期选择框元素
|
||||||
|
* @param element 转换该元素为日期选择框
|
||||||
|
* @returns 返回创建或转换的日期选择元素
|
||||||
|
*/
|
||||||
|
create(element?: HTMLInputElement): HTMLInputElement;
|
||||||
|
|
||||||
|
/** 获取日期选择框元素 */
|
||||||
|
get element(): HTMLInputElement;
|
||||||
|
|
||||||
|
/** 获取日期选择框是否启用 */
|
||||||
get enabled(): boolean;
|
get enabled(): boolean;
|
||||||
|
/** 设置日期选择框启用状态 */
|
||||||
set enabled(flag: boolean);
|
set enabled(flag: boolean);
|
||||||
|
|
||||||
|
/** 获取设置的日期值,或经过格式化函数返回的值 */
|
||||||
get value(): Date | any;
|
get value(): Date | any;
|
||||||
|
/** 设置日期值,支持的格式参见 {@linkcode formatDate} */
|
||||||
set value(val: Date | number | string);
|
set value(val: Date | number | string);
|
||||||
|
|
||||||
|
/** 获取最小可选择日期 */
|
||||||
|
get minDate(): string;
|
||||||
|
/** 设置最小可选择日期 */
|
||||||
set minDate(date: string);
|
set minDate(date: string);
|
||||||
|
|
||||||
|
/** 获取最大可选择日期 */
|
||||||
|
get maxDate(): string;
|
||||||
|
/** 设置最大可选择日期 */
|
||||||
set maxDate(date: string);
|
set maxDate(date: string);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 日期发生变化时触发的事件
|
||||||
|
* @param date 日期值,或者经自定义参数中格式化函数格式后的值
|
||||||
|
* @eventProperty
|
||||||
|
*/
|
||||||
|
onDateChanged?: (date: Date | any) => void;
|
||||||
}
|
}
|
@ -1,7 +1,13 @@
|
|||||||
import { createElement } from "../functions";
|
import { createElement } from "../functions";
|
||||||
|
|
||||||
export function createDateInput(min, max) {
|
export function createDateInput(min, max, element) {
|
||||||
const date = createElement('input', 'ui-date-cell');
|
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.required = true;
|
||||||
date.type = 'date';
|
date.type = 'date';
|
||||||
if (min != null) {
|
if (min != null) {
|
||||||
@ -89,16 +95,15 @@ export class DateSelector {
|
|||||||
|
|
||||||
constructor(opts) {
|
constructor(opts) {
|
||||||
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.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 => {
|
el.addEventListener('blur', e => {
|
||||||
const date = this._getDate(e.target.valueAsDate);
|
const date = this._getDate(e.target.valueAsDate);
|
||||||
if (date == null) {
|
if (date == null) {
|
||||||
@ -109,9 +114,11 @@ export class DateSelector {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
this._var.el = el;
|
this._var.el = el;
|
||||||
parent.appendChild(el);
|
return el;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
get element() { return this._var.el }
|
||||||
|
|
||||||
get enabled() { return !this._var.el.disabled }
|
get enabled() { return !this._var.el.disabled }
|
||||||
set enabled(flag) {
|
set enabled(flag) {
|
||||||
this._var.el.disabled = flag === false;
|
this._var.el.disabled = flag === false;
|
||||||
@ -122,16 +129,13 @@ export class DateSelector {
|
|||||||
setDateValue(this._var.el, val);
|
setDateValue(this._var.el, val);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
get minDate() { return this._var.el.min }
|
||||||
* @param {string} date
|
|
||||||
*/
|
|
||||||
set minDate(date) {
|
set minDate(date) {
|
||||||
this._var.el.min = date;
|
this._var.el.min = date;
|
||||||
this._var.options.minDate = date;
|
this._var.options.minDate = date;
|
||||||
}
|
}
|
||||||
/**
|
|
||||||
* @param {string} date
|
get maxDate() { return this._var.el.max }
|
||||||
*/
|
|
||||||
set maxDate(date) {
|
set maxDate(date) {
|
||||||
this._var.el.max = date;
|
this._var.el.max = date;
|
||||||
this._var.options.maxDate = date;
|
this._var.options.maxDate = date;
|
||||||
@ -150,4 +154,23 @@ export class DateSelector {
|
|||||||
}
|
}
|
||||||
return null;
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
6
lib/ui/dropdown.d.ts
vendored
6
lib/ui/dropdown.d.ts
vendored
@ -47,11 +47,13 @@ export interface DropdownOptions {
|
|||||||
/** 下拉框类 */
|
/** 下拉框类 */
|
||||||
export class Dropdown {
|
export class Dropdown {
|
||||||
/**
|
/**
|
||||||
* 把父元素下的所有 `select` 元素修改为统一下拉框组件
|
* 把父元素下的所有 `select` 元素修改为统一下拉框组件<br/><br/>
|
||||||
|
* 解析的属性为 `value`, `disabled`, `tabIndex`
|
||||||
* @param dom 父元素
|
* @param dom 父元素
|
||||||
|
* @param trigger 选中事件触发函数(上下文为触发选中的 `Dropdown` 实例)
|
||||||
* @returns 返回该父元素
|
* @returns 返回该父元素
|
||||||
*/
|
*/
|
||||||
static resolve(dom?: HTMLElement): HTMLElement;
|
static resolve(dom?: HTMLElement, trigger?: (item: DropdownItem) => void): HTMLElement;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 下拉框的构造函数
|
* 下拉框的构造函数
|
||||||
|
@ -560,7 +560,7 @@ export class Dropdown {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static resolve(dom = document.body) {
|
static resolve(dom = document.body, trigger) {
|
||||||
const selects = dom.querySelectorAll('select');
|
const selects = dom.querySelectorAll('select');
|
||||||
for (let sel of selects) {
|
for (let sel of selects) {
|
||||||
const source = [...sel.children].map(it => {
|
const source = [...sel.children].map(it => {
|
||||||
@ -572,6 +572,9 @@ export class Dropdown {
|
|||||||
tabIndex: sel.tabIndex
|
tabIndex: sel.tabIndex
|
||||||
});
|
});
|
||||||
drop.source = source;
|
drop.source = source;
|
||||||
|
if (typeof trigger === 'function') {
|
||||||
|
drop.onSelected = item => trigger.call(drop, item);
|
||||||
|
}
|
||||||
sel.parentElement.replaceChild(drop.create(), sel);
|
sel.parentElement.replaceChild(drop.create(), sel);
|
||||||
}
|
}
|
||||||
return dom;
|
return dom;
|
||||||
|
@ -975,6 +975,11 @@ export class Grid {
|
|||||||
th.addEventListener('mousedown', e => this._onDragStart(e, col));
|
th.addEventListener('mousedown', e => this._onDragStart(e, col));
|
||||||
}
|
}
|
||||||
const wrapper = createElement('div');
|
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);
|
th.appendChild(wrapper);
|
||||||
if (!this.readonly && col.enabled !== false && col.allcheck && isCheckbox) {
|
if (!this.readonly && col.enabled !== false && col.allcheck && isCheckbox) {
|
||||||
const check = createCheckbox({
|
const check = createCheckbox({
|
||||||
@ -1239,6 +1244,8 @@ export class Grid {
|
|||||||
const style = col.styleFilter(item);
|
const style = col.styleFilter(item);
|
||||||
if (style != null) {
|
if (style != null) {
|
||||||
type.setStyle(element, style);
|
type.setStyle(element, style);
|
||||||
|
} else {
|
||||||
|
element.style.cssText = '';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (col.events != null) {
|
if (col.events != null) {
|
||||||
@ -1562,7 +1569,12 @@ export class Grid {
|
|||||||
const th = filter.parentElement;
|
const th = filter.parentElement;
|
||||||
const width = th.offsetWidth;
|
const width = th.offsetWidth;
|
||||||
panel.style.top = `${th.offsetHeight + this._var.el.scrollTop}px`;
|
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
|
// search
|
||||||
let searchbox;
|
let searchbox;
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
{
|
{
|
||||||
"entryPoints": [
|
"entryPoints": [
|
||||||
|
"lib/ui/date.d.ts",
|
||||||
"lib/ui/dropdown.d.ts",
|
"lib/ui/dropdown.d.ts",
|
||||||
"lib/ui/grid/column.d.ts",
|
"lib/ui/grid/column.d.ts",
|
||||||
"lib/ui/grid/grid.d.ts"
|
"lib/ui/grid/grid.d.ts"
|
||||||
|
Loading…
x
Reference in New Issue
Block a user