sync
This commit is contained in:
parent
07f87bfb9d
commit
9ab9edb44d
@ -205,7 +205,7 @@ const SymbolDropdown = Symbol.for('ui-dropdown');
|
||||
class DropdownColumn {
|
||||
static create(col, trigger, parent) {
|
||||
const drop = new Dropdown({ ...col.dropOptions, parent });
|
||||
drop.onselected = trigger;
|
||||
drop.onSelected = trigger;
|
||||
return drop.create();
|
||||
}
|
||||
|
||||
|
@ -121,7 +121,7 @@ export default class ScheduleItem {
|
||||
{ value: '1', text: 'Weekly' },
|
||||
{ value: '2', text: 'Monthly' }
|
||||
];
|
||||
drop.onselected = item => {
|
||||
drop.onSelected = item => {
|
||||
container.querySelector('.schedule-item-weekly').style.display = item.value === '1' ? '' : 'none';
|
||||
const monthly = item.value === '2';
|
||||
container.querySelector('.schedule-item-monthly').style.display = monthly ? '' : 'none';
|
||||
|
@ -1 +0,0 @@
|
||||
.schedule-item-container fieldset{margin-top:10px;border-width:1px;border-radius:4px;border-color:var(--border-color)}.schedule-item-container fieldset legend,.schedule-item-container fieldset span{font-weight:400;font-size:var(--font-size);padding-left:8px;padding-right:6px;color:var(--color)}.schedule-item-container fieldset .ui-input{line-height:20px}.schedule-item-container fieldset .schedule-item-monthly{margin-top:5px}.schedule-item-container fieldset .schedule-item-monthly .ui-input{width:40px}.schedule-item-container fieldset.schedule-item-daily-frequency .ui-input{vertical-align:top;margin-top:5px}.schedule-item-container fieldset .schedule-item-table{width:100%}.schedule-item-container fieldset .schedule-item-line-occur-every{display:flex;align-items:flex-start}.schedule-item-container fieldset .schedule-item-line-occur-every>.schedule-item-block>.scheldule-item-line{display:flex;align-items:center;margin-top:5px}.schedule-item-container fieldset .schedule-item-line-occur-every>.schedule-item-block>.scheldule-item-line>span{flex:1 1 auto}.schedule-item-container fieldset .schedule-item-line-occur-every>.schedule-item-block>.scheldule-item-line>.ui-input{margin-top:0}.schedule-item-container fieldset .schedule-item-line-occur-every>span{line-height:36px}.schedule-item-container fieldset .schedule-item-line-occur-every .ui-input{width:70px}.schedule-item-container fieldset .schedule-item-line-duration{display:flex;align-items:center;height:36px}.schedule-item-container fieldset .schedule-item-line>.schedule-item-placeholder{flex:1 1 auto}.schedule-item-container .schedule-item-frequency{margin-top:0}
|
@ -1 +0,0 @@
|
||||
.ui-drop-wrapper{display:inline-block;border:none;border-radius:unset;-webkit-user-select:none;-moz-user-select:none;user-select:none;position:relative;font-size:var(--font-size);font-family:var(--font-family)}.ui-drop-wrapper>.ui-drop-header{background-color:var(--bg-color);display:flex;height:26px;border:1px solid var(--border-color);border-radius:var(--border-radius);transition:border-color .12s ease}.ui-drop-wrapper>.ui-drop-header:focus,.ui-drop-wrapper>.ui-drop-header:focus-visible{outline:none}.ui-drop-wrapper>.ui-drop-header:focus,.ui-drop-wrapper>.ui-drop-header:hover{border-color:var(--focus-border-color)}.ui-drop-wrapper>.ui-drop-header:disabled{border-color:var(--disabled-border-color);color:var(--disabled-color);background-color:var(--disabled-bg-color)}.ui-drop-wrapper>.ui-drop-header>.ui-drop-text{flex:1 1 auto;cursor:pointer;font-size:var(--font-size);padding:0 6px;overflow:hidden;text-overflow:ellipsis;border:none;white-space:nowrap}.ui-drop-wrapper>.ui-drop-header>.ui-drop-text:focus,.ui-drop-wrapper>.ui-drop-header>.ui-drop-text:focus-visible{outline:none}.ui-drop-wrapper>.ui-drop-header>input.ui-drop-text{cursor:initial}.ui-drop-wrapper>.ui-drop-header>input.ui-drop-text::-moz-placeholder{font-size:var(--font-smaller-size);font-style:italic}.ui-drop-wrapper>.ui-drop-header>input.ui-drop-text::placeholder{font-size:var(--font-smaller-size);font-style:italic}.ui-drop-wrapper>.ui-drop-header>.ui-drop-caret{flex:0 0 auto;width:26px;display:flex;justify-content:center;align-items:center;cursor:pointer}.ui-drop-wrapper>.ui-drop-header>.ui-drop-caret::after{display:block;content:"";border-top:4px solid;border-left:4px solid rgba(0,0,0,0);border-right:4px solid rgba(0,0,0,0);height:0;width:0}.ui-drop-wrapper>.ui-drop-header.disabled{border-color:var(--disabled-border-color);background-color:var(--disabled-bg-color);color:var(--disabled-color)}.ui-drop-wrapper>.ui-drop-header.disabled:focus{border-color:var(--disabled-border-color)}.ui-drop-wrapper>.ui-drop-header.disabled>.ui-drop-text,.ui-drop-wrapper>.ui-drop-header.disabled>.ui-drop-caret{cursor:default}.ui-drop-box{position:absolute;visibility:hidden;opacity:0;transform:scaleY(0);transform-origin:top;background-color:var(--bg-color);top:28px;z-index:2;transition:transform 120ms ease,opacity 120ms ease,visibility 120ms ease;min-width:calc(100% + 2px);box-sizing:border-box;box-shadow:0 3px 6px -4px rgba(0,0,0,.12),0 6px 16px 0 rgba(0,0,0,.08),0 9px 28px 8px rgba(0,0,0,.05);left:-1px}.ui-drop-box.slide-up{transform-origin:bottom;top:unset;bottom:28px}.ui-drop-box.active{visibility:visible;opacity:1;transform:scaleY(1)}.ui-drop-box>.ui-drop-search{box-sizing:border-box;height:36px;line-height:36px;padding:0 8px;position:relative;display:flex;align-items:center}.ui-drop-box>.ui-drop-search>input[type=text]{box-sizing:border-box;width:100%;height:26px;padding:0 6px 0 22px;color:var(--color);border:1px solid var(--border-color);border-radius:var(--border-radius);transition:border-color .12s ease}.ui-drop-box>.ui-drop-search>input[type=text]:focus,.ui-drop-box>.ui-drop-search>input[type=text]:focus-visible{outline:none}.ui-drop-box>.ui-drop-search>input[type=text]:focus,.ui-drop-box>.ui-drop-search>input[type=text]:hover{border-color:var(--focus-border-color)}.ui-drop-box>.ui-drop-search>input[type=text]:disabled{border-color:var(--disabled-border-color);color:var(--disabled-color);background-color:var(--disabled-bg-color)}.ui-drop-box>.ui-drop-search>input[type=text]::-moz-placeholder{font-style:italic}.ui-drop-box>.ui-drop-search>input[type=text]::placeholder{font-style:italic}.ui-drop-box>.ui-drop-search>svg{position:absolute;left:14px;width:13px;height:100%;cursor:text}.ui-drop-box>.ui-drop-list{margin:0;padding:0;list-style:none;max-height:210px;overflow-y:auto;font-size:var(--font-size)}.ui-drop-box>.ui-drop-list::-webkit-scrollbar{width:8px;height:8px}.ui-drop-box>.ui-drop-list::-webkit-scrollbar-thumb{background-color:rgba(168,168,168,.9);border-radius:4px}.ui-drop-box>.ui-drop-list.filtered>li:first-child{background-color:var(--hover-bg-color)}.ui-drop-box>.ui-drop-list>li{line-height:30px;height:30px;padding:0 10px;cursor:pointer;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.ui-drop-box>.ui-drop-list>li:hover,.ui-drop-box>.ui-drop-list>li.selected{background-color:var(--hover-bg-color)}.ui-drop-box>.ui-drop-list>li>.ui-check-wrapper{height:30px;display:flex}
|
File diff suppressed because one or more lines are too long
@ -95,7 +95,7 @@
|
||||
|
||||
&.sticky {
|
||||
position: sticky;
|
||||
z-index: 2;
|
||||
z-index: 3;
|
||||
}
|
||||
|
||||
>div {
|
||||
@ -190,9 +190,9 @@
|
||||
transition: background-color .12s ease;
|
||||
}
|
||||
|
||||
&:hover::after {
|
||||
background-color: var(--split-border-color);
|
||||
}
|
||||
// &:hover::after {
|
||||
// background-color: var(--split-border-color);
|
||||
// }
|
||||
}
|
||||
|
||||
>.dragger {
|
||||
@ -241,6 +241,10 @@
|
||||
padding: var(--header-filter-padding);
|
||||
}
|
||||
}
|
||||
|
||||
&:hover>th>.spliter::after {
|
||||
background-color: var(--split-border-color);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -435,7 +439,7 @@
|
||||
}
|
||||
}
|
||||
|
||||
>.ui-drop-box {
|
||||
~.ui-drop-box {
|
||||
max-width: 300px;
|
||||
}
|
||||
|
||||
|
104
lib/ui/dropdown.d.ts
vendored
104
lib/ui/dropdown.d.ts
vendored
@ -1,48 +1,118 @@
|
||||
interface DropdownItem {
|
||||
/** 下拉项接口 */
|
||||
export interface DropdownItem {
|
||||
/** 值 */
|
||||
value: string;
|
||||
/** 显示文本 */
|
||||
text: string;
|
||||
/** 源码显示内容 */
|
||||
html?: HTMLElement
|
||||
}
|
||||
|
||||
/** 下拉框选项接口 */
|
||||
export interface DropdownOptions {
|
||||
textkey?: string;
|
||||
valuekey?: string;
|
||||
htmlkey?: string;
|
||||
maxlength?: Number;
|
||||
multiselect?: boolean;
|
||||
/** 文本关键字,默认值 text */
|
||||
textKey?: string;
|
||||
/** 值关键字,默认值 value */
|
||||
valueKey?: string;
|
||||
/** 源码显示的关键字,默认值 html */
|
||||
htmlKey?: string;
|
||||
/** 最大输入长度,默认值 500 */
|
||||
maxLength?: Number;
|
||||
/** 是否允许多选 */
|
||||
multiSelect?: boolean;
|
||||
/** 选中值 */
|
||||
selected?: string;
|
||||
selectedlist?: Array<string>;
|
||||
/** 选中的数组 */
|
||||
selectedList?: Array<string>;
|
||||
/** 是否禁用 */
|
||||
disabled?: boolean;
|
||||
/** 是否支持输入 */
|
||||
input?: boolean;
|
||||
/** 是否支持搜索 */
|
||||
search?: boolean;
|
||||
searchkeys?: Array<string>;
|
||||
searchplaceholder?: string;
|
||||
tabindex?: Number;
|
||||
/** 搜索的关键字数组 */
|
||||
searchKeys?: Array<string>;
|
||||
/** 搜索提示文本,默认值取语言资源 <code>searchHolder</code> "Search..." */
|
||||
searchPlaceholder?: string;
|
||||
/** 焦点索引 */
|
||||
tabIndex?: Number;
|
||||
/** 输入框的提示文本 */
|
||||
placeholder?: string;
|
||||
slidefixed?: boolean;
|
||||
parent?: HTMLElement;
|
||||
/** 是否固定为向下展开 */
|
||||
slideFixed?: boolean;
|
||||
/** 父元素,默认添加到头元素之后 */
|
||||
wrapper?: HTMLElement;
|
||||
}
|
||||
|
||||
/** 下拉框类 */
|
||||
export class Dropdown {
|
||||
/**
|
||||
* 把父元素下的所有 <code>select</code> 元素修改为统一下拉框组件
|
||||
* @param dom 父元素
|
||||
* @returns 返回该父元素
|
||||
*/
|
||||
static resolve(dom?: HTMLElement): HTMLElement;
|
||||
|
||||
/**
|
||||
* 下拉框的构造函数
|
||||
* @param options 下拉框选项
|
||||
*/
|
||||
constructor(options?: DropdownOptions);
|
||||
|
||||
/** 根据该函数返回数据源 */
|
||||
sourceFilter: () => Array<DropdownItem | any>;
|
||||
onselected: (item: DropdownItem | any) => void;
|
||||
onselectedlist: (list: Array<DropdownItem | any>) => void;
|
||||
onexpanded: () => void;
|
||||
/**
|
||||
* 选中时触发
|
||||
* @param item 选中的条目
|
||||
*/
|
||||
onSelected: (item: DropdownItem | any) => void;
|
||||
/**
|
||||
* 选中多个时触发
|
||||
* @param list 选中的条目数组
|
||||
*/
|
||||
onSelectedList: (list: Array<DropdownItem | any>) => void;
|
||||
/** 下拉框展开时触发 */
|
||||
onExpanded: () => void;
|
||||
/** 下拉框收缩时触发 */
|
||||
onCollapsed: () => void;
|
||||
|
||||
/** 获取下拉框是否禁用 */
|
||||
get disabled(): boolean;
|
||||
/**
|
||||
* 设置下拉框禁用状态
|
||||
* @param flag 禁用状态
|
||||
*/
|
||||
set disabled(flag: boolean);
|
||||
/** 获取数据源 */
|
||||
get source(): Array<DropdownItem | any>;
|
||||
/**
|
||||
* 设置数据源
|
||||
* @param list 数据源
|
||||
*/
|
||||
set source(list: Array<DropdownItem | any>);
|
||||
|
||||
get multiselect(): boolean;
|
||||
/** 获取是否允许多选 */
|
||||
get multiSelect(): boolean;
|
||||
/** 获取选中的条目 */
|
||||
get selected(): DropdownItem | any;
|
||||
get selectedlist(): Array<DropdownItem | any>;
|
||||
/** 获取选中的条目列表 */
|
||||
get selectedList(): Array<DropdownItem | any>;
|
||||
|
||||
/**
|
||||
* 创建下拉框元素
|
||||
* @returns 返回创建的下拉框元素
|
||||
*/
|
||||
create(): HTMLElement;
|
||||
/**
|
||||
* 选中某个条目
|
||||
* @param selected 选中的值
|
||||
* @param silence 是否静默选中,即不触发 {@linkcode onSelected} 事件
|
||||
*/
|
||||
select(selected: string, silence?: boolean): void;
|
||||
/**
|
||||
* 选中条目列表
|
||||
* @param selectedlist 选中的值的列表
|
||||
* @param silence 是否静默选中,即不触发 {@linkcode onSelected} 事件
|
||||
*/
|
||||
selectlist(selectedlist: Array<string>, silence?: boolean): void;
|
||||
}
|
||||
|
@ -31,8 +31,8 @@ if (dropdownGlobal == null) {
|
||||
continue;
|
||||
}
|
||||
const dropdown = this[dropId];
|
||||
if (dropdown?.multiselect && typeof dropdown.oncollapsed === 'function') {
|
||||
dropdown.oncollapsed();
|
||||
if (dropdown?.multiSelect && typeof dropdown.onCollapsed === 'function') {
|
||||
dropdown.onCollapsed();
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -97,9 +97,10 @@ export class Dropdown {
|
||||
// _var.selectedList;
|
||||
|
||||
sourceFilter;
|
||||
onselectedlist;
|
||||
onselected;
|
||||
onexpanded;
|
||||
onSelectedList;
|
||||
onSelected;
|
||||
onExpanded;
|
||||
onCollapsed;
|
||||
|
||||
constructor(options = {}) {
|
||||
options.searchPlaceholder ??= r('searchHolder', 'Search...');
|
||||
@ -173,8 +174,8 @@ export class Dropdown {
|
||||
return;
|
||||
}
|
||||
this._dropdown(!active);
|
||||
if (!active && typeof this.onexpanded === 'function') {
|
||||
setTimeout(() => this.onexpanded(), 120);
|
||||
if (!active && typeof this.onExpanded === 'function') {
|
||||
setTimeout(() => this.onExpanded(), 120);
|
||||
}
|
||||
});
|
||||
|
||||
@ -216,7 +217,7 @@ export class Dropdown {
|
||||
return wrapper;
|
||||
}
|
||||
|
||||
get multiselect() { return this._var.options.multiSelect }
|
||||
get multiSelect() { return this._var.options.multiSelect }
|
||||
|
||||
get disabled() { return this._var.wrapper == null || this._var.wrapper.querySelector('.ui-drop-header.disabled') != null }
|
||||
|
||||
@ -257,9 +258,12 @@ export class Dropdown {
|
||||
|
||||
get selected() { return this._var.selected }
|
||||
|
||||
get selectedlist() { return this._var.selectedList || [] }
|
||||
get selectedList() { return this._var.selectedList || [] }
|
||||
|
||||
select(selected, silence) {
|
||||
if (typeof selected !== 'string') {
|
||||
selected = String(selected);
|
||||
}
|
||||
if (this._var.lastSelected === selected) {
|
||||
return false;
|
||||
}
|
||||
@ -267,7 +271,7 @@ export class Dropdown {
|
||||
const valuekey = this._var.options.valueKey;
|
||||
const textkey = this._var.options.textKey;
|
||||
const htmlkey = this._var.options.htmlKey;
|
||||
let item = this.source.find(it => it[valuekey] === selected);
|
||||
let item = this.source.find(it => String(it[valuekey]) === selected);
|
||||
if (this._var.options.input) {
|
||||
if (item == null) {
|
||||
item = { [valuekey]: selected };
|
||||
@ -304,8 +308,8 @@ export class Dropdown {
|
||||
}
|
||||
}
|
||||
this._var.selected = item;
|
||||
if (!silence && typeof this.onselected === 'function') {
|
||||
this.onselected(item);
|
||||
if (!silence && typeof this.onSelected === 'function') {
|
||||
this.onSelected(item);
|
||||
}
|
||||
}
|
||||
|
||||
@ -314,10 +318,14 @@ export class Dropdown {
|
||||
const valuekey = this._var.options.valueKey;
|
||||
const textkey = this._var.options.textKey;
|
||||
const htmlkey = this._var.options.htmlKey;
|
||||
const itemlist = selectedlist.map(v => {
|
||||
let item = source.find(it => it[valuekey] === v);
|
||||
const itemlist = selectedlist.map(a => {
|
||||
const v = typeof a === 'string' ? a : String(a);
|
||||
let item = source.find(it => String(it[valuekey]) === v);
|
||||
if (item == null) {
|
||||
item = { [valuekey]: v, [textkey]: v };
|
||||
item = {
|
||||
[valuekey]: v,
|
||||
[textkey]: v
|
||||
};
|
||||
}
|
||||
return item;
|
||||
});
|
||||
@ -328,8 +336,8 @@ export class Dropdown {
|
||||
}
|
||||
selectItems(this._var.label, itemlist, htmlkey, textkey);
|
||||
this._var.selectedList = itemlist;
|
||||
if (!silence && typeof this.onselectedlist === 'function') {
|
||||
this.onselectedlist(itemlist);
|
||||
if (!silence && typeof this.onSelectedList === 'function') {
|
||||
this.onSelectedList(itemlist);
|
||||
}
|
||||
}
|
||||
|
||||
@ -357,7 +365,7 @@ export class Dropdown {
|
||||
}
|
||||
// list
|
||||
const list = createElement('ul', 'ui-drop-list');
|
||||
if (!this.multiselect) {
|
||||
if (!this.multiSelect) {
|
||||
list.addEventListener('click', e => {
|
||||
let li = e.target;
|
||||
while (li.tagName !== 'LI') {
|
||||
@ -436,7 +444,7 @@ export class Dropdown {
|
||||
_filllist(source) {
|
||||
const list = this._var.container.querySelector('.ui-drop-list');
|
||||
list.replaceChildren();
|
||||
const multiselect = this.multiselect;
|
||||
const multiselect = this.multiSelect;
|
||||
const allchecked = this._var.allChecked;
|
||||
if (multiselect) {
|
||||
list.appendChild(
|
||||
@ -455,10 +463,13 @@ export class Dropdown {
|
||||
const textkey = this._var.options.textKey;
|
||||
const htmlkey = this._var.options.htmlKey;
|
||||
const selected = this.selected;
|
||||
const selectedlist = this.selectedlist;
|
||||
const selectedlist = this.selectedList;
|
||||
let scrolled;
|
||||
source.slice(0, 200).forEach((item, i) => {
|
||||
const val = item[valuekey];
|
||||
let val = item[valuekey];
|
||||
if (typeof val !== 'string') {
|
||||
val = String(val);
|
||||
}
|
||||
const li = createElement('li');
|
||||
li.dataset.value = val;
|
||||
li.setAttribute('title', item[textkey]);
|
||||
@ -471,7 +482,7 @@ export class Dropdown {
|
||||
label.innerHTML = html;
|
||||
}
|
||||
if (multiselect) {
|
||||
const selected = selectedlist.some(s => s[valuekey] === val);
|
||||
const selected = selectedlist.some(s => String(s[valuekey]) === val);
|
||||
if (label == null) {
|
||||
label = createElement('span');
|
||||
label.innerText = item[textkey];
|
||||
@ -492,7 +503,7 @@ export class Dropdown {
|
||||
} else {
|
||||
li.appendChild(label);
|
||||
}
|
||||
if (selected != null && selected[valuekey] === val) {
|
||||
if (selected != null && String(selected[valuekey]) === val) {
|
||||
scrolled = DropdownItemHeight * i;
|
||||
li.classList.add('selected');
|
||||
}
|
||||
@ -522,7 +533,10 @@ export class Dropdown {
|
||||
} else {
|
||||
const source = this.source;
|
||||
list = [...this._var.container.querySelectorAll('input.dataitem:checked')]
|
||||
.map(c => source.find(it => it[valuekey] === c.dataset.value))
|
||||
.map(c => {
|
||||
const v = c.dataset.value;
|
||||
return source.find(it => String(it[valuekey]) === v);
|
||||
})
|
||||
.filter(it => it != null);
|
||||
}
|
||||
} else {
|
||||
@ -530,9 +544,9 @@ export class Dropdown {
|
||||
if (this._var.allChecked) {
|
||||
this._var.allChecked = false;
|
||||
this._var.container.querySelector('input[isall="1"]').checked = false;
|
||||
list = this.source.filter(it => it[valuekey] !== val);
|
||||
list = this.source.filter(it => String(it[valuekey]) !== val);
|
||||
} else {
|
||||
list = this.selectedlist.filter(it => it[valuekey] !== val);
|
||||
list = this.selectedList.filter(it => String(it[valuekey]) !== val);
|
||||
}
|
||||
}
|
||||
if (this._var.allChecked) {
|
||||
@ -541,8 +555,8 @@ export class Dropdown {
|
||||
selectItems(this._var.label, list, htmlkey, textkey);
|
||||
}
|
||||
this._var.selectedList = list;
|
||||
if (typeof this.onselectedlist === 'function') {
|
||||
this.onselectedlist(itemlist);
|
||||
if (typeof this.onSelectedList === 'function') {
|
||||
this.onSelectedList(itemlist);
|
||||
}
|
||||
}
|
||||
|
||||
|
207
lib/ui/grid/column.d.ts
vendored
207
lib/ui/grid/column.d.ts
vendored
@ -1,69 +1,220 @@
|
||||
import { Grid, GridItem, GridItemWrapper, GridSourceItem } from "./grid";
|
||||
import { DropdownOptions } from "../dropdown";
|
||||
import { Dropdown, DropdownOptions } from "../dropdown";
|
||||
|
||||
/** 列类型枚举 */
|
||||
interface GridColumnType {
|
||||
/** 通用列 */
|
||||
0: "Common";
|
||||
/** 单行文本框列 */
|
||||
1: "Input";
|
||||
/** 下拉选择列 */
|
||||
2: "Dropdown";
|
||||
/** 复选框列 */
|
||||
3: "Checkbox";
|
||||
/** 图标列 */
|
||||
4: "Icon";
|
||||
/** 多行文本列 */
|
||||
5: "Text";
|
||||
/** 日期选择列 */
|
||||
6: "Date";
|
||||
}
|
||||
|
||||
/** 列定义接口 */
|
||||
export interface GridColumnDefinition {
|
||||
/** 列关键字,默认以该关键字从行数据中提取单元格值,行数据的关键字属性值里包含 DisplayValue 则优先显示此值 */
|
||||
key?: string;
|
||||
/** 列的类型,可以为 {@linkcode GridColumn} 的子类,或者内置类型 {@linkcode GridColumnType} */
|
||||
type?: keyof GridColumnType | typeof GridColumn;
|
||||
/** 列标题文本 */
|
||||
caption?: string;
|
||||
/** 列标题的元素样式 */
|
||||
captionStyle?: { [key: string]: string };
|
||||
/** 大于 0 则设置为该宽度,否则根据列内容自动调整列宽 */
|
||||
width?: Number;
|
||||
/** 列对齐方式 */
|
||||
align?: "left" | "center" | "right";
|
||||
/**
|
||||
* 列是否可用(可编辑),允许以下类型<br/><br/>
|
||||
* <code>boolean</code> 则直接使用该值<br/><br/>
|
||||
* <code>string</code> 则以该值为关键字从行数据中取值作为判断条件<br/><br/>
|
||||
* <code>(item: GridItem | any) => boolean</code> 则调用该函数(上下文为列定义对象),以返回值作为判断条件<br/><br/>
|
||||
*/
|
||||
enabled?: boolean | string | ((item: GridItem | any) => boolean);
|
||||
css?: { [key: string]: string };
|
||||
styleFilter?: (item: GridItem | any) => { [key: string]: string };
|
||||
visible?: boolean;
|
||||
resizable?: boolean;
|
||||
sortable?: boolean;
|
||||
orderable?: boolean;
|
||||
allcheck?: boolean;
|
||||
events?: { [event: string]: any };
|
||||
attrs?: { [key: string]: string } | ((item: GridItem | any) => { [key: string]: string });
|
||||
allowFilter?: boolean;
|
||||
/** 单元格取值采用该方法返回的值 */
|
||||
filter?: (item: GridItem | any) => any;
|
||||
sortFilter?: (a: GridItem | any, b: GridItem | any) => -1 | 0 | 1;
|
||||
bgFilter?: (item: GridItem | any) => string;
|
||||
dropOptions?: DropdownOptions;
|
||||
source?: Array<GridSourceItem | any> | ((item: GridItem | any) => Array<GridSourceItem | any> | Promise<Array<GridSourceItem | any>>);
|
||||
iconType?: string;
|
||||
iconClassName?: string | ((item: GridItem | any) => string);
|
||||
/** 单元格以该值填充内容,忽略filter与关键字属性 */
|
||||
text?: string;
|
||||
/** 列是否可见 */
|
||||
visible?: boolean;
|
||||
/** 列是否允许调整宽度 */
|
||||
resizable?: boolean;
|
||||
/** 列是否允许排序 */
|
||||
sortable?: boolean;
|
||||
/** 列是否允许重排顺序 */
|
||||
orderable?: boolean;
|
||||
/** 列为复选框类型时是否在列头增加全选复选框 */
|
||||
allcheck?: boolean;
|
||||
/** 单元格css样式对象(仅在重建行元素时读取) */
|
||||
css?: { [key: string]: string };
|
||||
/** 根据返回值填充单元格样式(填充行列数据时读取) */
|
||||
styleFilter?: (item: GridItem | any) => { [key: string]: string };
|
||||
/** 根据返回值设置单元格背景色 */
|
||||
bgFilter?: (item: GridItem | any) => string;
|
||||
/** 给单元格元素附加事件(事件函数上下文为数据行对象) */
|
||||
events?: { [event: string]: any };
|
||||
/** 根据返回值设置单元格元素的附加属性,允许直接设置对象也支持函数返回对象 */
|
||||
attrs?: { [key: string]: string } | ((item: GridItem | any) => { [key: string]: string });
|
||||
/** 是否允许进行列头过滤 */
|
||||
allowFilter?: boolean;
|
||||
/** 自定义列过滤器的数据源(函数上下文为Grid) */
|
||||
filterSource?: Array<GridItem | any> | ((col: GridColumnDefinition) => Array<GridItem | any>);
|
||||
/** 自定义列排序函数 */
|
||||
sortFilter?: (a: GridItem | any, b: GridItem | any) => -1 | 0 | 1;
|
||||
/** 列为下拉列表类型时以该值设置下拉框的参数 */
|
||||
dropOptions?: DropdownOptions;
|
||||
/** 列为下拉列表类型时以该值设置下拉列表数据源,支持函数返回,也支持返回异步对象 */
|
||||
source?: Array<GridSourceItem | any> | ((item: GridItem | any) => Array<GridSourceItem | any> | Promise<Array<GridSourceItem | any>>);
|
||||
/** 下拉列表数据源是否缓存结果(即行数据未发生变化时仅从source属性获取一次值) */
|
||||
sourceCache?: boolean;
|
||||
/** 列为图标类型时以该值设置图标样式(函数上下文为列定义对象),允许值为 <code>fa-light</code>、<code>fa-regular</code>、<code>fa-solid</code> */
|
||||
iconType?: string;
|
||||
/** 列为图标类型时以该值作为单元格元素的额外样式类型(函数上下文为列定义对象) */
|
||||
iconClassName?: string | ((item: GridItem | any) => string);
|
||||
/** 列为日期类型时以该值作为最小可选日期值 */
|
||||
dateMin?: string;
|
||||
/** 列为日期类型时以该值作为最大可选日期值 */
|
||||
dateMax?: string;
|
||||
/** 以返回值额外设置单元格的tooltip(函数上下文为列定义对象) */
|
||||
tooltip?: string | ((item: GridItem | any) => string);
|
||||
|
||||
/**
|
||||
* 列头复选框改变时触发
|
||||
* @param this 上下文为 Grid 对象
|
||||
* @param col 列定义对象
|
||||
* @param flag 是否选中
|
||||
*/
|
||||
onAllChecked?: (this: Grid, col: GridColumnDefinition, flag: boolean) => void;
|
||||
/**
|
||||
* 单元格发生变化时触发
|
||||
* @param this 上下文为 Grid 对象
|
||||
* @param item 数据行对象
|
||||
* @param value 修改后的值
|
||||
* @param oldValue 修改前的值
|
||||
* @param e 列修改事件传递过来的任意对象
|
||||
*/
|
||||
onChanged?: (this: Grid, item: GridItem | any, value: boolean | any, oldValue: any, e?: any) => void;
|
||||
/**
|
||||
* 文本单元格在输入完成时触发的事件
|
||||
* @param this 上下文为 Grid 对象
|
||||
* @param item 数据行对象
|
||||
* @param value 修改后的文本框值
|
||||
*/
|
||||
onInputEnded?: (this: Grid, item: GridItem | any, value: string) => void;
|
||||
/**
|
||||
* 列过滤点击OK时触发的事件
|
||||
* @param this 上下文为 Grid 对象
|
||||
* @param col 列定义对象
|
||||
* @param selected 选中的过滤项
|
||||
*/
|
||||
onFilterOk?: (this: Grid, col: GridColumnDefinition, selected: Array<GridItem | any>) => void;
|
||||
/**
|
||||
* 列过滤后触发的事件
|
||||
* @param this 上下文为 Grid 对象
|
||||
* @param col 列定义对象
|
||||
*/
|
||||
onFiltered?: (this: Grid, col: GridColumnDefinition) => void;
|
||||
/**
|
||||
* 列为下拉框类型时在下拉列表展开时触发的事件
|
||||
* @param this 上下文为列定义对象
|
||||
* @param item 数据行对象
|
||||
* @param drop 下拉框对象
|
||||
*/
|
||||
onDropExpanded?: (this: GridColumnDefinition, item: GridItem | any, drop: Dropdown) => void;
|
||||
}
|
||||
|
||||
/** 列定义基类 */
|
||||
export class GridColumn {
|
||||
/**
|
||||
* 创建显示单元格时调用的方法
|
||||
* @param col 列定义对象
|
||||
* @returns 返回创建的单元格元素
|
||||
*/
|
||||
static create(col: GridColumnDefinition): HTMLElement;
|
||||
/**
|
||||
* 创建编辑单元格时调用的方法<br/><br/>
|
||||
* 元素修改后设置行包装对象的 <code>__editing</code> 后,支持在离开编辑状态时及时触发 {@linkcode leaveEdit} 方法<br/>
|
||||
* 更多例子参考代码中 {@linkcode GridDropdownColumn} 的实现。
|
||||
* @param trigger 编辑事件回调函数,e 参数会传递给 {@linkcode getValue} 方法
|
||||
* @param col 列定义对象
|
||||
* @param container 父容器元素
|
||||
* @param vals 行包装对象,其 <code>values</code> 属性为行数据对象
|
||||
* @returns 返回创建的编辑状态的单元格元素
|
||||
*/
|
||||
static createEdit(trigger: (e: any) => void, col: GridColumnDefinition, container: HTMLElement, vals: GridItemWrapper): HTMLElement;
|
||||
static setValue(element: HTMLElement, val: any, vals: GridItemWrapper, col: GridColumnDefinition, grid: Grid): void;
|
||||
static getValue(e: any, col: GridColumnDefinition): any;
|
||||
/**
|
||||
* 设置单元格值时调用的方法
|
||||
* @param element 单元格元素
|
||||
* @param val 待设置的单元格值
|
||||
* @param vals 行包装对象
|
||||
* @param col 列定义对象
|
||||
* @param grid {@linkcode Grid} 对象
|
||||
*/
|
||||
static setValue(element: HTMLElement, val: string | boolean | any, vals: GridItemWrapper, col: GridColumnDefinition, grid: Grid): void;
|
||||
/**
|
||||
* 获取编辑状态单元格值时调用的方法
|
||||
* @param e 由 {@linkcode createEdit} 方法中 <code>trigger</code> 函数传递来的对象
|
||||
* @param col 列定义对象
|
||||
* @returns 返回单元格的值
|
||||
*/
|
||||
static getValue(e: any, col: GridColumnDefinition): string | boolean | any;
|
||||
/**
|
||||
* 设置单元格样式时调用的方法
|
||||
* @param element 单元格元素
|
||||
* @param style 样式对象
|
||||
*/
|
||||
static setStyle(element: HTMLElement, style: { [key: string]: string }): void;
|
||||
/**
|
||||
* 设置单元格可用性时调用的方法
|
||||
* @param element 单元格元素
|
||||
* @param enabled 启用值,为false时代表禁用
|
||||
*/
|
||||
static setEnabled(element: HTMLElement, enabled?: boolean): void;
|
||||
}
|
||||
|
||||
export class GridInputColumn extends GridColumn {
|
||||
static get editing(): boolean;
|
||||
}
|
||||
|
||||
export class GridTextColumn extends GridInputColumn { }
|
||||
|
||||
export class GridDropdownColumn extends GridColumn {
|
||||
/**
|
||||
* 单元格离开编辑元素时触发,需要由行包装对象的 <code>__editing</code> 来确定是否触发。
|
||||
* @param element 单元格元素
|
||||
* @param container 父容器元素
|
||||
*/
|
||||
static leaveEdit(element: HTMLElement, container: HTMLElement): void;
|
||||
}
|
||||
|
||||
/** 单行文本列 */
|
||||
export class GridInputColumn extends GridColumn {
|
||||
/**
|
||||
* 设置该类型是否支持触发 {@linkcode GridColumnDefinition.onInputEnded} 方法<br/>
|
||||
* 该属性返回 <code>true</code> 后,在任意事件中修改行包装对象的 <code>__editing</code> 值,则会在行列元素变动时及时触发 {@linkcode GridColumnDefinition.onInputEnded} 方法,避免例如文本框还未触发 <code>onchange</code> 事件就被移除元素而导致的问题<br/>
|
||||
* 更多例子参考代码中 {@linkcode GridInputColumn} 的实现
|
||||
*/
|
||||
static get editing(): boolean;
|
||||
}
|
||||
|
||||
/** 多行文本列 */
|
||||
export class GridTextColumn extends GridInputColumn { }
|
||||
|
||||
/** 下拉选择列 */
|
||||
export class GridDropdownColumn extends GridColumn { }
|
||||
|
||||
/** 复选框列 */
|
||||
export class GridCheckboxColumn extends GridColumn { }
|
||||
|
||||
/** 图标列 */
|
||||
export class GridIconColumn extends GridColumn { }
|
||||
|
||||
/** 日期选择列 */
|
||||
export class GridDateColumn extends GridColumn {
|
||||
/**
|
||||
* 格式化日期对象为 M/d/yyyy 格式的字符串
|
||||
* @param date 日期对象
|
||||
* @returns 返回格式化后的字符串
|
||||
*/
|
||||
static formatDate(date: Date): string;
|
||||
}
|
@ -105,13 +105,13 @@ export class GridTextColumn extends GridInputColumn {
|
||||
const SymbolDropdown = Symbol.for('ui-dropdown');
|
||||
|
||||
export class GridDropdownColumn extends GridColumn {
|
||||
static createEdit(trigger, col, wrapper, it) {
|
||||
static createEdit(trigger, col, container, it) {
|
||||
const drop = new Dropdown({
|
||||
...col.dropOptions,
|
||||
wrapper
|
||||
wrapper: container.parentElement
|
||||
});
|
||||
drop.onselected = trigger;
|
||||
drop.onexpanded = function () {
|
||||
drop.onSelected = trigger;
|
||||
drop.onExpanded = function () {
|
||||
if (it.__editing == null) {
|
||||
it.__editing = {
|
||||
[col.key]: true
|
||||
@ -211,8 +211,8 @@ export class GridDropdownColumn extends GridColumn {
|
||||
drop.disabled = enabled === false;
|
||||
}
|
||||
|
||||
static leaveEdit(element, wrapper) {
|
||||
wrapper.querySelectorAll('.ui-drop-box.active').forEach(e => {
|
||||
static leaveEdit(element, container) {
|
||||
container.parentElement.querySelectorAll('.ui-drop-box.active').forEach(e => {
|
||||
if (e != null) {
|
||||
e.classList.remove('active');
|
||||
}
|
||||
@ -221,8 +221,8 @@ export class GridDropdownColumn extends GridColumn {
|
||||
if (drop == null) {
|
||||
return;
|
||||
}
|
||||
if (drop?.multiselect && typeof drop.oncollapsed === 'function') {
|
||||
drop.oncollapsed();
|
||||
if (drop?.multiSelect && typeof drop.onCollapsed === 'function') {
|
||||
drop.onCollapsed();
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -286,7 +286,16 @@ export class GridIconColumn extends GridColumn {
|
||||
}
|
||||
|
||||
export class GridDateColumn extends GridColumn {
|
||||
static createEdit(trigger, col) {
|
||||
static createEdit(trigger, col, _container, vals) {
|
||||
let enabled = col.enabled;
|
||||
if (typeof enabled === 'string') {
|
||||
enabled = vals.values[enabled];
|
||||
} else if (typeof enabled === 'function') {
|
||||
enabled = col.enabled(vals.values);
|
||||
}
|
||||
if (enabled === false) {
|
||||
return super.create();
|
||||
}
|
||||
const date = createElement('input', 'ui-grid-date-cell');
|
||||
date.required = true;
|
||||
date.type = 'date';
|
||||
@ -306,25 +315,45 @@ export class GridDateColumn extends GridColumn {
|
||||
if (isNaN(val) || /^\d{4}-\d{2}-\d{2}$/.test(val)) {
|
||||
element.value = val;
|
||||
} else {
|
||||
val = new Date((val - 621355968e9) / 10000);
|
||||
val = new Date((val - 621355968e9) / 1e4);
|
||||
const month = String(val.getMonth() + 1).padStart(2, '0');
|
||||
const date = String(val.getDate()).padStart(2, '0');
|
||||
element.value = `${val.getFullYear()}-${month}-${date}`;
|
||||
}
|
||||
} else {
|
||||
element.innerText = val;
|
||||
element.innerText = this.formatDate(val);
|
||||
}
|
||||
}
|
||||
|
||||
static getValue(e) {
|
||||
return e.target?.value;
|
||||
const date = e.target?.valueAsDate;
|
||||
if (date instanceof Date && !isNaN(date)) {
|
||||
const year = date.getFullYear();
|
||||
if (year < 1900 || year > 9999) {
|
||||
return '';
|
||||
}
|
||||
return String(date.getTime() * 1e4 + 621355968e9);
|
||||
}
|
||||
return '';
|
||||
}
|
||||
|
||||
static setEnabled(element, enabled) {
|
||||
element.disabled = enabled === false;
|
||||
}
|
||||
|
||||
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) {
|
||||
date = this._resolveDate(date);
|
||||
if (date instanceof Date && !isNaN(date)) {
|
||||
return `${date.getMonth() + 1}/${date.getDate()}/${date.getFullYear()}`;
|
||||
}
|
||||
|
161
lib/ui/grid/grid.d.ts
vendored
161
lib/ui/grid/grid.d.ts
vendored
@ -1,93 +1,244 @@
|
||||
import { GridColumnDefinition } from "./column"
|
||||
|
||||
/** 列数据接口 */
|
||||
export interface GridItem {
|
||||
/** 值 */
|
||||
Value: any;
|
||||
/** 显示值 */
|
||||
DisplayValue: string;
|
||||
}
|
||||
|
||||
/** 列数据行包装接口 */
|
||||
export interface GridItemWrapper {
|
||||
values: Array<GridItem | any>;
|
||||
/** 真实数据对象 */
|
||||
values: { [key: string]: GridItem | any };
|
||||
/** 下拉数据源缓存对象 */
|
||||
source: { [key: string]: Array<GridSourceItem> };
|
||||
}
|
||||
|
||||
/** 下拉框列数据源接口 */
|
||||
export interface GridSourceItem {
|
||||
/** 值 */
|
||||
value: string;
|
||||
/** 显示文本 */
|
||||
text: string;
|
||||
}
|
||||
|
||||
/** 列排序枚举 */
|
||||
interface GridColumnDirection {
|
||||
/** 倒序 */
|
||||
[-1]: Number,
|
||||
/** 升序 */
|
||||
1: Number
|
||||
}
|
||||
|
||||
/** 列事件枚举 */
|
||||
interface GridColumnColumnEventMap {
|
||||
/** 重排事件 */
|
||||
"reorder": string,
|
||||
/** 宽调整事件 */
|
||||
"resize": string,
|
||||
/** 排序事件 */
|
||||
"sort": string
|
||||
}
|
||||
|
||||
/** Grid 控件基础类 */
|
||||
export class Grid {
|
||||
/** 列类型枚举 */
|
||||
static ColumnTypes: {
|
||||
/** 通用列(只读) */
|
||||
Common: 0,
|
||||
/** 单行文本列 */
|
||||
Input: 1,
|
||||
/** 下拉选择列 */
|
||||
Dropdown: 2,
|
||||
/** 复选框列 */
|
||||
Checkbox: 3,
|
||||
/** 图标列 */
|
||||
Icon: 4,
|
||||
/** 多行文本列 */
|
||||
Text: 5,
|
||||
/** 日期选择列 */
|
||||
Date: 6,
|
||||
/**
|
||||
* 判断列是否为复选框列
|
||||
* @param type 列类型
|
||||
*/
|
||||
isCheckbox(type: Number): boolean;
|
||||
};
|
||||
|
||||
/** 列定义的数组 */
|
||||
columns: Array<GridColumnDefinition>;
|
||||
/** 多语言资源对象 */
|
||||
langs?: { all: string, ok: string, reset: string };
|
||||
/** 行数大于等于该值则启用虚模式,默认值 100 */
|
||||
virtualCount?: Number;
|
||||
/** 表格行高,默认值 36 */
|
||||
rowHeight?: Number;
|
||||
/** 文本行高,默认值 24 */
|
||||
lineHeight?: Number;
|
||||
/** 列表底部留出额外行的空白,默认值 0 */
|
||||
extraRows?: Number;
|
||||
/** 过滤条件列表的行高,默认值 30 */
|
||||
filterRowHeight?: Number;
|
||||
/** 列表高度值,为 0 时列表始终显示全部内容(自增高),为非数字或者小于 0 则根据容器高度来确定虚模式的渲染行数,默认值 null */
|
||||
height?: Number;
|
||||
/** 列表是否为只读,默认值 false */
|
||||
readonly?: boolean;
|
||||
/** 是否允许多选,默认值 false */
|
||||
multiSelect?: boolean;
|
||||
/** 为 false 时只有点击在单元格内才会选中行,默认值 true */
|
||||
fullrowClick?: boolean;
|
||||
/** 单元格 tooltip 是否禁用,默认值 false */
|
||||
tooltipDisabled?: boolean;
|
||||
/** 列头是否显示,默认值 true */
|
||||
headerVisible?: boolean;
|
||||
/** 监听事件的窗口载体,默认值 window */
|
||||
window?: Window
|
||||
/** 排序列的索引,默认值 -1 */
|
||||
sortIndex?: Number;
|
||||
/** 排序方式,正数升序,负数倒序,默认值 1 */
|
||||
sortDirection?: keyof GridColumnDirection;
|
||||
|
||||
constructor(container: HTMLElement, getText?: (id: string, def?: string) => string);
|
||||
/**
|
||||
* Grid 控件构造函数
|
||||
* @param container Grid 控件所在的父容器,可以是 string 表示选择器,也可以是 HTMLElement 对象<br/><br/>
|
||||
* <i>构造时可以不进行赋值,但是调用 init 函数时则必须进行赋值</i>
|
||||
* @param getText (可选参数)获取多语言文本的函数代理
|
||||
*/
|
||||
constructor(container: string | HTMLElement, getText?: (id: string, def?: string) => string);
|
||||
|
||||
/**
|
||||
* 即将选中行时触发,返回 false、null、undefined、0 等则取消选中动作
|
||||
* @param index 即将选中的行索引
|
||||
* @param colIndex 即将选中的列索引
|
||||
*/
|
||||
willSelect?: (index: Number, colIndex: Number) => boolean;
|
||||
/**
|
||||
* 单元格单击时触发,colIndex 为 -1 则表示点击的是行的空白处,返回 false 则取消事件冒泡
|
||||
* @param index 点击的行索引
|
||||
* @param colIndex 点击的列索引
|
||||
*/
|
||||
cellClicked?: (index: Number, colIndex: Number) => boolean;
|
||||
|
||||
/**
|
||||
* 选中行发生变化时触发的事件
|
||||
* @param index 选中的行索引
|
||||
*/
|
||||
onSelectedRowChanged?: (index?: Number) => void;
|
||||
/**
|
||||
* 单元格双击时触发的事件,colIndex 为 -1 则表示点击的是行的空白处
|
||||
* @param index 双击的行索引
|
||||
* @param colIndex 双击的列索引
|
||||
*/
|
||||
onCellDblClicked?: (index: Number, colIndex: Number) => void;
|
||||
/**
|
||||
* 行双击时触发的事件
|
||||
* @param index 双击的行索引
|
||||
*/
|
||||
onRowDblClicked?: (index: Number) => void;
|
||||
onColumnChanged?: <K extends keyof GridColumnColumnEventMap>(type: K, index: Number, value: Number | keyof GridColumnDirection) => void;
|
||||
/**
|
||||
* 列发生变化时触发的事件
|
||||
* @param type 事件类型<br/><br/>
|
||||
* "reorder" 为发生列重排事件,此时 value 为目标列索引<br/>
|
||||
* "resize" 为发生列宽调整事件,此时 value 为列宽度值<br/>
|
||||
* "sort" 为发生列排序事件,此时 value 为 1(升序)或 -1(倒序)
|
||||
* @param colIndex 发生变化事件的列索引
|
||||
* @param value 变化的值
|
||||
*/
|
||||
onColumnChanged?: (type: keyof GridColumnColumnEventMap, colIndex: Number, value: Number | keyof GridColumnDirection) => void;
|
||||
/**
|
||||
* 列滚动时触发的事件
|
||||
* @param e 滚动事件对象
|
||||
*/
|
||||
onBodyScrolled?: (e: Event) => void;
|
||||
|
||||
/** 获取数据数组 */
|
||||
get source(): Array<GridItem | any>;
|
||||
/** 设置数据,并刷新列表 */
|
||||
set source(list: Array<GridItem | any>);
|
||||
/** 获取当前选中的行索引的数组 */
|
||||
get selectedIndexes(): Array<Number>;
|
||||
/** 设置当前选中的行索引的数组,并刷新列表 */
|
||||
set selectedIndexes(indexes: Array<Number>);
|
||||
/** 获取 Grid 当前是否处于加载状态 */
|
||||
get loading(): boolean;
|
||||
/** 使 Grid 进入加载状态 */
|
||||
set loading(flag: boolean);
|
||||
/** 获取 Grid 当前滚动的偏移量 */
|
||||
get scrollTop(): Number;
|
||||
/** 设置 Grid 滚动偏移量 */
|
||||
set scrollTop(top: Number);
|
||||
|
||||
get element(): HTMLElement
|
||||
/** 获取 Grid 的页面元素 */
|
||||
get element(): HTMLElement;
|
||||
/** 获取当前 Grid 是否已发生改变 */
|
||||
get changed(): boolean;
|
||||
/** 获取当前是否为虚模式状态 */
|
||||
get virtual(): boolean;
|
||||
/** 获取当前排序的列关键字,为 null 则当前无排序列 */
|
||||
get sortKey(): string | undefined;
|
||||
/** 获取当前选中行的索引,为 -1 则当前没有选中行 */
|
||||
get selectedIndex(): Number | -1;
|
||||
|
||||
/**
|
||||
* 初始化Grid控件
|
||||
* @param container 父容器元素,若未传值则采用构造方法中传入的父容器元素
|
||||
*/
|
||||
init(container?: HTMLElement): void;
|
||||
/**
|
||||
* 设置数据列表,该方法为 set source 属性的语法糖
|
||||
* @param source 待设置的数据列表
|
||||
*/
|
||||
setData(source: Array<GridItem | any>): void;
|
||||
/**
|
||||
* 设置单行数据
|
||||
* @param index 行索引
|
||||
* @param item 待设置的行数据值
|
||||
*/
|
||||
setItem(index: Number, item: GridItem | any): void;
|
||||
/**
|
||||
* 添加行数据
|
||||
* @param item 待添加的行数据值
|
||||
* @param index 待添加的行索引
|
||||
*/
|
||||
addItem(item: GridItem | any, index?: Number): void;
|
||||
/**
|
||||
* 删除行数据
|
||||
* @param index 待删除的行索引
|
||||
*/
|
||||
removeItem(index: Number): void;
|
||||
/**
|
||||
* 滚动到指定行的位置
|
||||
* @param index 待滚动至的行索引
|
||||
*/
|
||||
scrollToIndex(index: Number): void;
|
||||
resize(force?: boolean): void;
|
||||
/**
|
||||
* 调整 Grid 元素的大小,一般需要在宽度变化时(如页面大小发生变化时)调用
|
||||
* @param force 是否强制reload,默认只有待渲染的行数发生变化时才会调用reload
|
||||
* @param keep 是否保持当前滚动位置
|
||||
*/
|
||||
resize(force?: boolean, keep?: boolean): void;
|
||||
/**
|
||||
* 重新计算需要渲染的行,并载入元素,一般需要在高度变化时调用
|
||||
* @param keep 是否保持当前滚动位置
|
||||
*/
|
||||
reload(keep?: boolean): void;
|
||||
/**
|
||||
* 重新填充Grid单元格数据
|
||||
*/
|
||||
refresh(): void;
|
||||
/**
|
||||
* 把所有行重置为未修改的状态
|
||||
*/
|
||||
resetChange(): void;
|
||||
/**
|
||||
* 根据当前排序字段进行列排序
|
||||
* @param reload 为 true 则在列排序后调用 reload 方法
|
||||
*/
|
||||
sortColumn(reload?: boolean): void;
|
||||
/**
|
||||
* 清除列头复选框的选中状态
|
||||
*/
|
||||
clearHeaderCheckbox(): void;
|
||||
}
|
@ -133,6 +133,14 @@ export class Grid {
|
||||
|
||||
get element() { return this._var.el }
|
||||
|
||||
get changed() {
|
||||
const source = this._var.source;
|
||||
if (source == null) {
|
||||
return false;
|
||||
}
|
||||
return source.filter(r => r.__changed).length > 0;
|
||||
}
|
||||
|
||||
get source() { return this._var.source?.map(s => s.values) }
|
||||
set source(list) {
|
||||
if (this._var.el == null) {
|
||||
@ -148,11 +156,32 @@ export class Grid {
|
||||
|
||||
setItem(index, item) {
|
||||
if (this._var.source == null) {
|
||||
return;
|
||||
throw new Error('no source');
|
||||
}
|
||||
const it = this._var.source[index];
|
||||
delete it.source;
|
||||
it.values = item;
|
||||
this.refresh();
|
||||
}
|
||||
|
||||
addItem(item, index) {
|
||||
if (this._var.source == null) {
|
||||
throw new Error('no source');
|
||||
}
|
||||
if (index >= 0) {
|
||||
this._var.source.splice(index, 0, { values: item });
|
||||
} else {
|
||||
this._var.source.push({ values: item });
|
||||
}
|
||||
this.reload();
|
||||
}
|
||||
|
||||
removeItem(index) {
|
||||
if (this._var.source == null) {
|
||||
throw new Error('no source');
|
||||
}
|
||||
this._var.source.splice(index, 1);
|
||||
this.reload();
|
||||
}
|
||||
|
||||
_refreshSource(list) {
|
||||
@ -344,7 +373,7 @@ export class Grid {
|
||||
this._var.el.scrollTop = top;
|
||||
}
|
||||
|
||||
resize(force) {
|
||||
resize(force, keep) {
|
||||
if (this._var.rendering || this._var.el == null) {
|
||||
return;
|
||||
}
|
||||
@ -360,7 +389,7 @@ export class Grid {
|
||||
const count = truncate((height - 1) / (this.rowHeight + 1)) + (RedumCount * 2) + 1;
|
||||
if (force || count !== this._var.rowCount) {
|
||||
this._var.rowCount = count;
|
||||
this.reload(true);
|
||||
this.reload(keep);
|
||||
}
|
||||
this._var.bodyClientWidth = body.clientWidth;
|
||||
}
|
||||
@ -760,11 +789,11 @@ export class Grid {
|
||||
}
|
||||
if (type.editing) {
|
||||
val = type.getValue({ target: cell.children[0] }, col);
|
||||
this._onRowChanged(null, startIndex + i, col, val, cell, true);
|
||||
this._onRowChanged(null, i, col, val, cell, true);
|
||||
}
|
||||
}
|
||||
element = selected ?
|
||||
type.createEdit(e => this._onRowChanged(e, startIndex + i, col, type.getValue(e, col), cell), col, this._var.el, vals) :
|
||||
type.createEdit(e => this._onRowChanged(e, i, col, type.getValue(e, col), cell), col, this._var.el, vals) :
|
||||
type.create(col);
|
||||
cell.replaceChildren(element);
|
||||
} else {
|
||||
@ -1179,7 +1208,7 @@ export class Grid {
|
||||
const key = e.currentTarget.value.toLowerCase();
|
||||
const items = key.length === 0 ? array : array.filter(i => {
|
||||
const displayValue = i?.DisplayValue ?? i;
|
||||
return String(displayValue ?? '').includes(key);
|
||||
return String(displayValue ?? '').toLowerCase().includes(key);
|
||||
});
|
||||
this._fillFilterList(col, itemlist, items, itemall);
|
||||
});
|
||||
@ -1288,7 +1317,7 @@ export class Grid {
|
||||
}
|
||||
const content = list.querySelector('.filter-content');
|
||||
content.replaceChildren();
|
||||
this._doFillFilterList(content, array, list.querySelector('.filter-all>input'));
|
||||
this._doFillFilterList(content, array, list.querySelector('.filter-all'));
|
||||
content.style.top = `${top + rowHeight}px`;
|
||||
}
|
||||
}
|
||||
|
@ -2,7 +2,8 @@ const svgns = 'http://www.w3.org/2000/svg';
|
||||
|
||||
function createUse(type, id) {
|
||||
const c = typeof consts !== 'undefined' ? consts : {};
|
||||
const path = c.path || '';
|
||||
const netroot = typeof _network !== 'undefined' ? _network.root : '';
|
||||
const path = c.path || netroot;
|
||||
const ver = c.resver == null ? '' : `?${c.resver}`;
|
||||
const use = document.createElementNS(svgns, 'use');
|
||||
use.setAttributeNS('http://www.w3.org/1999/xlink', 'xlink:href', `${path}fonts/${type}.svg${ver}#${id}`);
|
||||
|
47
package-lock.json
generated
47
package-lock.json
generated
@ -11,6 +11,7 @@
|
||||
"postcss-preset-env": "^8.2.0",
|
||||
"sass": "^1.60.0",
|
||||
"typedoc": "^0.24.8",
|
||||
"typedoc-theme-hierarchy": "^4.1.2",
|
||||
"vite": "^4.0.4",
|
||||
"vite-plugin-externals": "^0.6.2"
|
||||
}
|
||||
@ -1592,9 +1593,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/nanoid": {
|
||||
"version": "3.3.6",
|
||||
"resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.6.tgz",
|
||||
"integrity": "sha512-BGcqMMJuToF7i1rt+2PWSNVnWIkGCU78jBG3RxO/bZlnZPK2Cmi2QaffxGO/2RvWi9sL+FAiRiXMgsyxQ1DIDA==",
|
||||
"version": "3.3.7",
|
||||
"resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.7.tgz",
|
||||
"integrity": "sha512-eSRppjcPIatRIMC1U6UngP8XFcz8MQWGQdt1MTBQ7NaAmvXDfvNxbvWV3x2y6CdEUciCSsDHDQZbhYaB8QEo2g==",
|
||||
"dev": true,
|
||||
"funding": [
|
||||
{
|
||||
@ -1652,9 +1653,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/postcss": {
|
||||
"version": "8.4.27",
|
||||
"resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.27.tgz",
|
||||
"integrity": "sha512-gY/ACJtJPSmUFPDCHtX78+01fHa64FaU4zaaWfuh1MhGJISufJAH4cun6k/8fwsHYeK4UQmENQK+tRLCFJE8JQ==",
|
||||
"version": "8.4.33",
|
||||
"resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.33.tgz",
|
||||
"integrity": "sha512-Kkpbhhdjw2qQs2O2DGX+8m5OVqEcbB9HRBvuYM9pgrjEFUg30A9LmXNlTAUj4S9kgtGyrMbTzVjH7E+s5Re2yg==",
|
||||
"dev": true,
|
||||
"funding": [
|
||||
{
|
||||
@ -1671,7 +1672,7 @@
|
||||
}
|
||||
],
|
||||
"dependencies": {
|
||||
"nanoid": "^3.3.6",
|
||||
"nanoid": "^3.3.7",
|
||||
"picocolors": "^1.0.0",
|
||||
"source-map-js": "^1.0.2"
|
||||
},
|
||||
@ -2397,6 +2398,32 @@
|
||||
"typescript": "4.6.x || 4.7.x || 4.8.x || 4.9.x || 5.0.x || 5.1.x"
|
||||
}
|
||||
},
|
||||
"node_modules/typedoc-theme-hierarchy": {
|
||||
"version": "4.1.2",
|
||||
"resolved": "https://registry.npmjs.org/typedoc-theme-hierarchy/-/typedoc-theme-hierarchy-4.1.2.tgz",
|
||||
"integrity": "sha512-X3H+zaDkg7wLNoaPJoqXs3rnMfZ9BZjmlXRwplWDciaPfn2hojHxJJ+yVKdqqmojgiHJgg7MYWGDVpOfNlOJ5A==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"fs-extra": "11.1.1"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"typedoc": "^0.24.0 || ^0.25.0"
|
||||
}
|
||||
},
|
||||
"node_modules/typedoc-theme-hierarchy/node_modules/fs-extra": {
|
||||
"version": "11.1.1",
|
||||
"resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-11.1.1.tgz",
|
||||
"integrity": "sha512-MGIE4HOvQCeUCzmlHs0vXpih4ysz4wg9qiSAu6cd42lVwPbTM1TjV7RusoyQqMmk/95gdQZX72u+YW+c3eEpFQ==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"graceful-fs": "^4.2.0",
|
||||
"jsonfile": "^6.0.1",
|
||||
"universalify": "^2.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=14.14"
|
||||
}
|
||||
},
|
||||
"node_modules/typescript": {
|
||||
"version": "5.1.6",
|
||||
"resolved": "https://registry.npmjs.org/typescript/-/typescript-5.1.6.tgz",
|
||||
@ -2457,9 +2484,9 @@
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/vite": {
|
||||
"version": "4.4.9",
|
||||
"resolved": "https://registry.npmjs.org/vite/-/vite-4.4.9.tgz",
|
||||
"integrity": "sha512-2mbUn2LlUmNASWwSCNSJ/EG2HuSRTnVNaydp6vMCm5VIqJsjMfbIWtbH2kDuwUVW5mMUKKZvGPX/rqeqVvv1XA==",
|
||||
"version": "4.5.2",
|
||||
"resolved": "https://registry.npmjs.org/vite/-/vite-4.5.2.tgz",
|
||||
"integrity": "sha512-tBCZBNSBbHQkaGyhGCDUGqeo2ph8Fstyp6FMSvTtsXeZSPpSMGlviAOav2hxVTqFcx8Hj/twtWKsMJXNY0xI8w==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"esbuild": "^0.18.10",
|
||||
|
@ -28,6 +28,7 @@
|
||||
"postcss-preset-env": "^8.2.0",
|
||||
"sass": "^1.60.0",
|
||||
"typedoc": "^0.24.8",
|
||||
"typedoc-theme-hierarchy": "^4.1.2",
|
||||
"vite": "^4.0.4",
|
||||
"vite-plugin-externals": "^0.6.2"
|
||||
}
|
||||
|
Binary file not shown.
@ -1,17 +1,12 @@
|
||||
{
|
||||
"entryPoints": [
|
||||
"lib/functions.d.ts",
|
||||
"lib/ui/checkbox.d.ts",
|
||||
"lib/ui/dropdown.d.ts",
|
||||
"lib/ui/icon.d.ts",
|
||||
"lib/ui/popup.d.ts",
|
||||
"lib/ui/tooltip.d.ts",
|
||||
"lib/ui/grid/column.d.ts",
|
||||
"lib/ui/grid/grid.d.ts",
|
||||
"lib/ui/media.d.ts"
|
||||
"lib/ui/grid/grid.d.ts"
|
||||
],
|
||||
"out": "./docs",
|
||||
"readme": "README.md",
|
||||
"name": "UI Library",
|
||||
"disableSources": true,
|
||||
"cleanOutputDir": true
|
||||
}
|
@ -23,70 +23,9 @@ const libraries = [
|
||||
}
|
||||
},
|
||||
sourcemap: true,
|
||||
outDir: '../../../../IronIntel/Contractor2.0/Contractor/Site/js/lib',
|
||||
emptyOutDir: false
|
||||
}
|
||||
},
|
||||
{
|
||||
clearScreen: false,
|
||||
css: {
|
||||
postcss: {
|
||||
plugins: [postcssPresetEnv()]
|
||||
}
|
||||
},
|
||||
build: {
|
||||
lib: {
|
||||
entry: './lib/app.js',
|
||||
name: 'lib-app',
|
||||
formats: ['umd'],
|
||||
fileName: (_format, name) => `${name}.min.js`
|
||||
},
|
||||
rollupOptions: {
|
||||
output: {
|
||||
assetFileNames: info => info.name === 'style.css' ? 'app.min.css' : info.name
|
||||
}
|
||||
},
|
||||
sourcemap: true,
|
||||
outDir: '../../../../IronIntel/Contractor2.0/Contractor/Site/js/lib',
|
||||
emptyOutDir: false
|
||||
},
|
||||
plugins: [
|
||||
viteExternalsPlugin({
|
||||
'../../ui': 'lib-ui',
|
||||
'../../utility': 'lib-utility'
|
||||
})
|
||||
]
|
||||
},
|
||||
{
|
||||
clearScreen: false,
|
||||
css: {
|
||||
postcss: {
|
||||
plugins: [postcssPresetEnv()]
|
||||
}
|
||||
},
|
||||
build: {
|
||||
lib: {
|
||||
entry: './lib/element.js',
|
||||
name: 'lib-element',
|
||||
formats: ['umd'],
|
||||
fileName: (_format, name) => `${name}.min.js`
|
||||
},
|
||||
rollupOptions: {
|
||||
output: {
|
||||
assetFileNames: info => info.name === 'style.css' ? 'element.min.css' : info.name
|
||||
}
|
||||
},
|
||||
sourcemap: true,
|
||||
outDir: '../../../../IronIntel/Contractor2.0/Contractor/Site/js/lib',
|
||||
emptyOutDir: false
|
||||
},
|
||||
plugins: [
|
||||
viteExternalsPlugin({
|
||||
'../ui': 'lib-ui',
|
||||
'../utility': 'lib-utility'
|
||||
})
|
||||
]
|
||||
},
|
||||
{
|
||||
clearScreen: false,
|
||||
build: {
|
||||
|
Loading…
x
Reference in New Issue
Block a user