fixed: column drag issue.
optimized: documentation.
This commit is contained in:
parent
0b9b322b80
commit
984496e08e
16
lib/ui/dropdown.d.ts
vendored
16
lib/ui/dropdown.d.ts
vendored
@ -32,7 +32,7 @@ export interface DropdownOptions {
|
||||
search?: boolean;
|
||||
/** 搜索的关键字数组 */
|
||||
searchKeys?: Array<string>;
|
||||
/** 搜索提示文本,默认值取语言资源 <code>searchHolder</code> "Search..." */
|
||||
/** 搜索提示文本,默认值取语言资源 `searchHolder` "Search..." */
|
||||
searchPlaceholder?: string;
|
||||
/** 焦点索引 */
|
||||
tabIndex?: Number;
|
||||
@ -47,7 +47,7 @@ export interface DropdownOptions {
|
||||
/** 下拉框类 */
|
||||
export class Dropdown {
|
||||
/**
|
||||
* 把父元素下的所有 <code>select</code> 元素修改为统一下拉框组件
|
||||
* 把父元素下的所有 `select` 元素修改为统一下拉框组件
|
||||
* @param dom 父元素
|
||||
* @returns 返回该父元素
|
||||
*/
|
||||
@ -64,16 +64,24 @@ export class Dropdown {
|
||||
/**
|
||||
* 选中时触发
|
||||
* @param item 选中的条目
|
||||
* @eventProperty
|
||||
*/
|
||||
onSelected: (item: DropdownItem) => void;
|
||||
/**
|
||||
* 选中多个时触发
|
||||
* @param list 选中的条目数组
|
||||
* @eventProperty
|
||||
*/
|
||||
onSelectedList: (list: Array<DropdownItem>) => void;
|
||||
/** 下拉框展开时触发 */
|
||||
/**
|
||||
* 下拉框展开时触发
|
||||
* @eventProperty
|
||||
*/
|
||||
onExpanded: () => void;
|
||||
/** 下拉框收缩时触发 */
|
||||
/**
|
||||
* 下拉框收缩时触发
|
||||
* @eventProperty
|
||||
*/
|
||||
onCollapsed: () => void;
|
||||
|
||||
/** 获取下拉框是否禁用 */
|
||||
|
173
lib/ui/grid/column.d.ts
vendored
173
lib/ui/grid/column.d.ts
vendored
@ -35,13 +35,18 @@ export interface GridColumnDefinition {
|
||||
align?: "left" | "center" | "right";
|
||||
/**
|
||||
* 列是否可用(可编辑),允许以下类型<br/><br/>
|
||||
* <code>boolean</code> 则直接使用该值<br/><br/>
|
||||
* <code>string</code> 则以该值为关键字从行数据中取值作为判断条件<br/><br/>
|
||||
* <code>(item: GridItem) => boolean</code> 则调用该函数(上下文为列定义对象),以返回值作为判断条件<br/><br/>
|
||||
* `boolean` 则直接使用该值<br/><br/>
|
||||
* `string` 则以该值为关键字从行数据中取值作为判断条件<br/><br/>
|
||||
* `(item: GridItem) => boolean` 则调用该函数(上下文为列定义对象),以返回值作为判断条件<br/><br/>
|
||||
*/
|
||||
enabled?: boolean | string | ((item: GridItem) => boolean);
|
||||
/** 单元格取值采用该方法返回的值 */
|
||||
filter?: (item: GridItem) => any;
|
||||
/**
|
||||
* 单元格取值采用该方法返回的值
|
||||
* @param item 行数据对象
|
||||
* @param editing 是否处于编辑状态
|
||||
* @param body Grid 控件的 `<tbody>` 部分
|
||||
*/
|
||||
filter?: (item: GridItem, editing: boolean, body?: HTMLElement) => any;
|
||||
/** 单元格以该值填充内容,忽略filter与关键字属性 */
|
||||
text?: string;
|
||||
/** 列是否可见 */
|
||||
@ -76,8 +81,8 @@ export interface GridColumnDefinition {
|
||||
source?: Array<GridSourceItem> | ((item: GridItem) => Array<GridSourceItem> | Promise<Array<GridSourceItem>>);
|
||||
/** 下拉列表数据源是否缓存结果(即行数据未发生变化时仅从source属性获取一次值) */
|
||||
sourceCache?: boolean;
|
||||
/** 列为图标类型时以该值设置图标样式(函数上下文为列定义对象),允许值为 <code>fa-light</code>、<code>fa-regular</code>、<code>fa-solid</code> */
|
||||
iconType?: string;
|
||||
/** 列为图标类型时以该值设置图标样式(函数上下文为列定义对象),默认值 `fa-light` */
|
||||
iconType?: "fa-light" | "fa-regular" | "fa-solid";
|
||||
/** 列为图标类型时以该值作为单元格元素的额外样式类型(函数上下文为列定义对象) */
|
||||
iconClassName?: string | ((item: GridItem) => string);
|
||||
/** 列为日期类型时以该值作为最小可选日期值 */
|
||||
@ -92,6 +97,7 @@ export interface GridColumnDefinition {
|
||||
* @param this 上下文为 Grid 对象
|
||||
* @param col 列定义对象
|
||||
* @param flag 是否选中
|
||||
* @eventProperty
|
||||
*/
|
||||
onAllChecked?: (this: Grid, col: GridColumnDefinition, flag: boolean) => void;
|
||||
/**
|
||||
@ -101,6 +107,7 @@ export interface GridColumnDefinition {
|
||||
* @param value 修改后的值
|
||||
* @param oldValue 修改前的值
|
||||
* @param e 列修改事件传递过来的任意对象
|
||||
* @eventProperty
|
||||
*/
|
||||
onChanged?: (this: Grid, item: GridItem, value: boolean | string | Number, oldValue: boolean | string | Number, e?: any) => void;
|
||||
/**
|
||||
@ -108,6 +115,7 @@ export interface GridColumnDefinition {
|
||||
* @param this 上下文为 Grid 对象
|
||||
* @param item 数据行对象
|
||||
* @param value 修改后的文本框值
|
||||
* @eventProperty
|
||||
*/
|
||||
onInputEnded?: (this: Grid, item: GridItem, value: string) => void;
|
||||
/**
|
||||
@ -115,12 +123,14 @@ export interface GridColumnDefinition {
|
||||
* @param this 上下文为 Grid 对象
|
||||
* @param col 列定义对象
|
||||
* @param selected 选中的过滤项
|
||||
* @eventProperty
|
||||
*/
|
||||
onFilterOk?: (this: Grid, col: GridColumnDefinition, selected: Array<GridItem>) => void;
|
||||
/**
|
||||
* 列过滤后触发的事件
|
||||
* @param this 上下文为 Grid 对象
|
||||
* @param col 列定义对象
|
||||
* @eventProperty
|
||||
*/
|
||||
onFiltered?: (this: Grid, col: GridColumnDefinition) => void;
|
||||
/**
|
||||
@ -128,6 +138,7 @@ export interface GridColumnDefinition {
|
||||
* @param this 上下文为列定义对象
|
||||
* @param item 数据行对象
|
||||
* @param drop 下拉框对象
|
||||
* @eventProperty
|
||||
*/
|
||||
onDropExpanded?: (this: GridColumnDefinition, item: GridItem, drop: Dropdown) => void;
|
||||
}
|
||||
@ -138,19 +149,28 @@ export class GridColumn {
|
||||
* 创建显示单元格时调用的方法
|
||||
* @param col 列定义对象
|
||||
* @returns 返回创建的单元格元素
|
||||
* @virtual
|
||||
*/
|
||||
static create(col: GridColumnDefinition): HTMLElement;
|
||||
/**
|
||||
* 创建编辑单元格时调用的方法<br/><br/>
|
||||
* 元素修改后设置行包装对象的 <code>__editing</code> 后,支持在离开编辑状态时及时触发 {@linkcode leaveEdit} 方法<br/>
|
||||
* 元素修改后设置行包装对象的 `__editing` 后,支持在离开编辑状态时及时触发 {@linkcode leaveEdit} 方法<br/>
|
||||
* 更多例子参考代码中 {@linkcode GridDropdownColumn} 的实现。
|
||||
* @param trigger 编辑事件回调函数,e 参数会传递给 {@linkcode getValue} 方法
|
||||
* @param col 列定义对象
|
||||
* @param container 父容器元素
|
||||
* @param vals 行包装对象,其 <code>values</code> 属性为行数据对象
|
||||
* @param vals 行包装对象,其 `values` 属性为行数据对象
|
||||
* @returns 返回创建的编辑状态的单元格元素
|
||||
* @virtual
|
||||
*/
|
||||
static createEdit(trigger: (e: any) => void, col: GridColumnDefinition, container: HTMLElement, vals: GridItemWrapper): HTMLElement;
|
||||
/**
|
||||
* 创建列头时调用的方法
|
||||
* @param col 列定义对象
|
||||
* @returns 返回创建的列头元素
|
||||
* @virtual
|
||||
*/
|
||||
static createCaption?(col: GridColumnDefinition): HTMLElement;
|
||||
/**
|
||||
* 设置单元格值时调用的方法
|
||||
* @param element 单元格元素
|
||||
@ -158,59 +178,178 @@ export class GridColumn {
|
||||
* @param vals 行包装对象
|
||||
* @param col 列定义对象
|
||||
* @param grid {@linkcode Grid} 对象
|
||||
* @virtual
|
||||
*/
|
||||
static setValue(element: HTMLElement, val: string | boolean | Number, vals: GridItemWrapper, col: GridColumnDefinition, grid: Grid): void;
|
||||
/**
|
||||
* 获取编辑状态单元格值时调用的方法
|
||||
* @param e 由 {@linkcode createEdit} 方法中 <code>trigger</code> 函数传递来的对象
|
||||
* @param e 由 {@linkcode createEdit} 方法中 `trigger` 函数传递来的对象
|
||||
* @param col 列定义对象
|
||||
* @returns 返回单元格的值
|
||||
* @virtual
|
||||
*/
|
||||
static getValue(e: any, col: GridColumnDefinition): string | boolean | Number;
|
||||
/**
|
||||
* 设置单元格样式时调用的方法
|
||||
* @param element 单元格元素
|
||||
* @param style 样式对象
|
||||
* @virtual
|
||||
*/
|
||||
static setStyle(element: HTMLElement, style: { [key: string]: string }): void;
|
||||
/**
|
||||
* 设置单元格可用性时调用的方法
|
||||
* @param element 单元格元素
|
||||
* @param enabled 启用值,为false时代表禁用
|
||||
* @virtual
|
||||
*/
|
||||
static setEnabled(element: HTMLElement, enabled?: boolean): void;
|
||||
/**
|
||||
* 单元格离开编辑元素时触发,需要由行包装对象的 <code>__editing</code> 来确定是否触发。
|
||||
* 单元格离开编辑元素时触发,需要由行包装对象的 `__editing` 来确定是否触发。
|
||||
* @param element 单元格元素
|
||||
* @param container 父容器元素
|
||||
* @virtual
|
||||
*/
|
||||
static leaveEdit(element: HTMLElement, container: HTMLElement): void;
|
||||
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/>
|
||||
* 该属性返回 `true` 后,在任意事件中修改行包装对象的 `__editing` 值,则会在行列元素变动时及时触发 {@linkcode GridColumnDefinition.onInputEnded} 方法,避免例如文本框还未触发 `onchange` 事件就被移除元素而导致的问题<br/>
|
||||
* 更多例子参考代码中 {@linkcode GridInputColumn} 的实现
|
||||
*/
|
||||
static get editing(): boolean;
|
||||
/**
|
||||
* @inheritdoc GridColumn.createEdit
|
||||
* @override
|
||||
*/
|
||||
static createEdit(trigger: (e: any) => void, col: GridColumnDefinition, container: HTMLElement, vals: GridItemWrapper): HTMLElement;
|
||||
/**
|
||||
* @inheritdoc GridColumn.setValue
|
||||
* @override
|
||||
*/
|
||||
static setValue(element: HTMLElement, val: string, vals: GridItemWrapper, col: GridColumnDefinition, grid: Grid): void;
|
||||
/**
|
||||
* @inheritdoc GridColumn.getValue
|
||||
* @override
|
||||
*/
|
||||
static getValue(e: any): string;
|
||||
/**
|
||||
* @inheritdoc GridColumn.setEnabled
|
||||
* @override
|
||||
*/
|
||||
static setEnabled(element: HTMLElement, enabled?: boolean): void;
|
||||
}
|
||||
|
||||
/** 多行文本列 */
|
||||
export class GridTextColumn extends GridInputColumn { }
|
||||
export class GridTextColumn extends GridInputColumn {
|
||||
/**
|
||||
* @inheritdoc GridInputColumn.createEdit
|
||||
* @override
|
||||
*/
|
||||
static createEdit(trigger: (e: any) => void, col: GridColumnDefinition, container: HTMLElement, vals: GridItemWrapper): HTMLElement;
|
||||
/**
|
||||
* @inheritdoc GridInputColumn.setValue
|
||||
* @override
|
||||
*/
|
||||
static setValue(element: HTMLElement, val: string, vals: GridItemWrapper, col: GridColumnDefinition, grid: Grid): void;
|
||||
}
|
||||
|
||||
/** 下拉选择列 */
|
||||
export class GridDropdownColumn extends GridColumn { }
|
||||
export class GridDropdownColumn extends GridColumn {
|
||||
/**
|
||||
* @inheritdoc GridColumn.createEdit
|
||||
* @override
|
||||
*/
|
||||
static createEdit(trigger: (e: any) => void, col: GridColumnDefinition, container: HTMLElement, vals: GridItemWrapper): HTMLElement;
|
||||
/**
|
||||
* @inheritdoc GridColumn.setValue
|
||||
* @override
|
||||
*/
|
||||
static setValue(element: HTMLElement, val: string, vals: GridItemWrapper, col: GridColumnDefinition): void;
|
||||
/**
|
||||
* @inheritdoc GridColumn.getValue
|
||||
* @override
|
||||
*/
|
||||
static getValue(e: any, col: GridColumnDefinition): string;
|
||||
/**
|
||||
* @inheritdoc GridColumn.setEnabled
|
||||
* @override
|
||||
*/
|
||||
static setEnabled(element: HTMLElement, enabled?: boolean): void;
|
||||
/**
|
||||
* @inheritdoc GridColumn.leaveEdit
|
||||
* @override
|
||||
*/
|
||||
static leaveEdit?(element: HTMLElement, container: HTMLElement): void;
|
||||
}
|
||||
|
||||
/** 复选框列 */
|
||||
export class GridCheckboxColumn extends GridColumn { }
|
||||
export class GridCheckboxColumn extends GridColumn {
|
||||
/**
|
||||
* @inheritdoc GridColumn.createEdit
|
||||
* @override
|
||||
*/
|
||||
static createEdit(trigger: (e: any) => void): HTMLElement;
|
||||
/**
|
||||
* @inheritdoc GridColumn.setValue
|
||||
* @override
|
||||
*/
|
||||
static setValue(element: HTMLElement, val: boolean): void;
|
||||
/**
|
||||
* @inheritdoc GridColumn.getValue
|
||||
* @override
|
||||
*/
|
||||
static getValue(e: any): boolean;
|
||||
/**
|
||||
* @inheritdoc GridColumn.setEnabled
|
||||
* @override
|
||||
*/
|
||||
static setEnabled(element: HTMLElement, enabled?: boolean): void;
|
||||
}
|
||||
|
||||
/** 图标列 */
|
||||
export class GridIconColumn extends GridColumn { }
|
||||
export class GridIconColumn extends GridColumn {
|
||||
/**
|
||||
* @inheritdoc GridColumn.create
|
||||
* @override
|
||||
*/
|
||||
static create(): HTMLElement;
|
||||
/**
|
||||
* @inheritdoc GridColumn.setValue
|
||||
* @override
|
||||
*/
|
||||
static setValue(element: HTMLElement, val: string, vals: GridItemWrapper, col: GridColumnDefinition): void;
|
||||
/**
|
||||
* @inheritdoc GridColumn.setEnabled
|
||||
* @override
|
||||
*/
|
||||
static setEnabled(element: HTMLElement, enabled?: boolean): void;
|
||||
}
|
||||
|
||||
/** 日期选择列 */
|
||||
export class GridDateColumn extends GridColumn {
|
||||
/**
|
||||
* @inheritdoc GridColumn.createEdit
|
||||
* @override
|
||||
*/
|
||||
static createEdit(trigger: (e: any) => void, col: GridColumnDefinition, container: HTMLElement, vals: GridItemWrapper): HTMLElement;
|
||||
/**
|
||||
* @inheritdoc GridColumn.setValue
|
||||
* @override
|
||||
*/
|
||||
static setValue(element: HTMLElement, val: string | Number): void;
|
||||
/**
|
||||
* @inheritdoc GridColumn.getValue
|
||||
* @override
|
||||
*/
|
||||
static getValue(e: any): string | Number;
|
||||
/**
|
||||
* @inheritdoc GridColumn.setEnabled
|
||||
* @override
|
||||
*/
|
||||
static setEnabled(element: HTMLElement, enabled?: boolean): void;
|
||||
/**
|
||||
* 格式化日期对象为 M/d/yyyy 格式的字符串
|
||||
* @param date 日期对象
|
||||
|
@ -250,7 +250,7 @@ export class GridCheckboxColumn extends GridColumn {
|
||||
export class GridIconColumn extends GridColumn {
|
||||
static create() { return createElement('span', 'col-icon') }
|
||||
|
||||
static setValue(element, val, item, col, _grid) {
|
||||
static setValue(element, val, item, col) {
|
||||
let className = col.iconClassName;
|
||||
if (typeof className === 'function') {
|
||||
className = className.call(col, item.values);
|
||||
@ -264,7 +264,7 @@ export class GridIconColumn extends GridColumn {
|
||||
if (typeof type === 'function') {
|
||||
type = type.call(col, item.values);
|
||||
}
|
||||
type ??= 'fa-regular';
|
||||
type ??= 'fa-light';
|
||||
if (element.dataset.type !== type || element.dataset.icon !== val) {
|
||||
const icon = createIcon(type, val);
|
||||
// const layer = element.children[0];
|
||||
|
25
lib/ui/grid/grid.d.ts
vendored
25
lib/ui/grid/grid.d.ts
vendored
@ -24,6 +24,22 @@ interface GridSourceItem {
|
||||
text: string;
|
||||
}
|
||||
|
||||
/** Grid 语言资源接口 */
|
||||
interface GridLanguages {
|
||||
/**
|
||||
* “所有”文本
|
||||
*
|
||||
* @default `( All )`
|
||||
*/
|
||||
all: string;
|
||||
/** “确定”文本,默认值 OK */
|
||||
ok: string;
|
||||
/** “重置”文本,默认值 Reset */
|
||||
reset: string;
|
||||
/** “空”文本,默认值 ( Null ) */
|
||||
null: string
|
||||
}
|
||||
|
||||
/** 列排序枚举 */
|
||||
declare enum GridColumnDirection {
|
||||
/** 倒序 */
|
||||
@ -70,7 +86,7 @@ export class Grid {
|
||||
/** 列定义的数组 */
|
||||
columns: Array<GridColumnDefinition>;
|
||||
/** 多语言资源对象 */
|
||||
langs?: { all: string, ok: string, reset: string };
|
||||
langs?: GridLanguages;
|
||||
/** 行数大于等于该值则启用虚模式,默认值 100 */
|
||||
virtualCount?: Number;
|
||||
/** 表格行高,默认值 36 */
|
||||
@ -112,29 +128,34 @@ export class Grid {
|
||||
* 即将选中行时触发,返回 false、null、undefined、0 等则取消选中动作
|
||||
* @param index 即将选中的行索引
|
||||
* @param colIndex 即将选中的列索引
|
||||
* @eventProperty
|
||||
*/
|
||||
willSelect?: (index: Number, colIndex: Number) => boolean;
|
||||
/**
|
||||
* 单元格单击时触发,colIndex 为 -1 则表示点击的是行的空白处,返回 false 则取消事件冒泡
|
||||
* @param index 点击的行索引
|
||||
* @param colIndex 点击的列索引
|
||||
* @eventProperty
|
||||
*/
|
||||
cellClicked?: (index: Number, colIndex: Number) => boolean;
|
||||
|
||||
/**
|
||||
* 选中行发生变化时触发的事件
|
||||
* @param index 选中的行索引
|
||||
* @eventProperty
|
||||
*/
|
||||
onSelectedRowChanged?: (index?: Number) => void;
|
||||
/**
|
||||
* 单元格双击时触发的事件,colIndex 为 -1 则表示点击的是行的空白处
|
||||
* @param index 双击的行索引
|
||||
* @param colIndex 双击的列索引
|
||||
* @eventProperty
|
||||
*/
|
||||
onCellDblClicked?: (index: Number, colIndex: Number) => void;
|
||||
/**
|
||||
* 行双击时触发的事件
|
||||
* @param index 双击的行索引
|
||||
* @eventProperty
|
||||
*/
|
||||
onRowDblClicked?: (index: Number) => void;
|
||||
/**
|
||||
@ -145,11 +166,13 @@ export class Grid {
|
||||
* "sort" 为发生列排序事件,此时 value 为 1(升序)或 -1(倒序)
|
||||
* @param colIndex 发生变化事件的列索引
|
||||
* @param value 变化的值
|
||||
* @eventProperty
|
||||
*/
|
||||
onColumnChanged?: (type: GridColumnColumnEvent, colIndex: Number, value: Number | GridColumnDirection) => void;
|
||||
/**
|
||||
* 列滚动时触发的事件
|
||||
* @param e 滚动事件对象
|
||||
* @eventProperty
|
||||
*/
|
||||
onBodyScrolled?: (e: Event) => void;
|
||||
|
||||
|
@ -17,7 +17,7 @@ const ColumnChangedType = {
|
||||
const RefreshInterval = isMobile() ? 32 : 0;
|
||||
const HoverInternal = 200;
|
||||
const RedumCount = 4;
|
||||
const MiniDragOffset = 4;
|
||||
const MiniDragOffset = 10;
|
||||
const MiniColumnWidth = 50;
|
||||
const FilterPanelWidth = 200;
|
||||
|
||||
@ -29,15 +29,6 @@ function getClientX(e) {
|
||||
return cx ?? e.clientX;
|
||||
}
|
||||
|
||||
function getOffsetLeftFromWindow(element) {
|
||||
let left = 0;
|
||||
while (element != null) {
|
||||
left += element.offsetLeft;
|
||||
element = element.offsetParent;
|
||||
}
|
||||
return left;
|
||||
}
|
||||
|
||||
function indexOfParent(target) {
|
||||
// return [...target.parentElement.children].indexOf(target);
|
||||
return Array.prototype.indexOf.call(target.parentElement.children, target);
|
||||
@ -127,7 +118,8 @@ export class Grid {
|
||||
this.langs = {
|
||||
all: r('allItem', '( All )'),
|
||||
ok: r('ok', 'OK'),
|
||||
reset: r('reset', 'Reset')
|
||||
reset: r('reset', 'Reset'),
|
||||
null: r('null', '( Null )')
|
||||
};
|
||||
}
|
||||
|
||||
@ -190,7 +182,7 @@ export class Grid {
|
||||
this._var.currentSource = list.filter(it => {
|
||||
for (let col of this.columns) {
|
||||
if (Array.isArray(col.filterValues)) {
|
||||
const v = this._getItemValue(it.values, col.key, col.filter);
|
||||
const v = this._getItemProp(it.values, false, col);
|
||||
if (col.filterValues.indexOf(v) < 0) {
|
||||
return false;
|
||||
}
|
||||
@ -485,8 +477,8 @@ export class Grid {
|
||||
direction = 1;
|
||||
}
|
||||
comparer = (a, b) => {
|
||||
a = this._getItemValue(a.values, col.key, col.filter);
|
||||
b = this._getItemValue(b.values, col.key, col.filter);
|
||||
a = this._getItemProp(a.values, true, col);
|
||||
b = this._getItemProp(b.values, true, col);
|
||||
if (a == null && typeof b === 'number') {
|
||||
a = 0;
|
||||
} else if (typeof a === 'number' && b == null) {
|
||||
@ -533,7 +525,7 @@ export class Grid {
|
||||
let left = 0;
|
||||
for (let col of this.columns) {
|
||||
if (col.visible === false) {
|
||||
const hidden = createElement('th');
|
||||
const hidden = createElement('th', 'column');
|
||||
hidden.style.display = 'none';
|
||||
if (col.sortable !== false) {
|
||||
hidden.dataset.key = col.key;
|
||||
@ -544,7 +536,17 @@ export class Grid {
|
||||
}
|
||||
// style
|
||||
const isCheckbox = Grid.ColumnTypes.isCheckbox(col.type);
|
||||
if (col.width > 0) {
|
||||
let type = this._var.colTypes[col.key];
|
||||
if (type == null) {
|
||||
if (isNaN(col.type)) {
|
||||
type = col.type;
|
||||
} else {
|
||||
type = ColumnTypes[col.type];
|
||||
}
|
||||
type ??= GridColumn;
|
||||
this._var.colTypes[col.key] = type;
|
||||
}
|
||||
if (col.width > 0 || typeof type.createCaption === 'function') {
|
||||
// col.autoResize = false;
|
||||
} else {
|
||||
this._set(col.key, 'autoResize', true);
|
||||
@ -600,12 +602,19 @@ export class Grid {
|
||||
});
|
||||
wrapper.appendChild(check);
|
||||
}
|
||||
const caption = createElement('span');
|
||||
if (col.captionStyle != null) {
|
||||
caption.style.cssText = convertCssStyle(col.captionStyle);
|
||||
let caption;
|
||||
if (typeof type.createCaption === 'function') {
|
||||
caption = type.createCaption(col);
|
||||
} else {
|
||||
caption = createElement('span');
|
||||
caption.innerText = col.caption ?? '';
|
||||
}
|
||||
if (caption instanceof HTMLElement) {
|
||||
if (col.captionStyle != null) {
|
||||
caption.style.cssText = convertCssStyle(col.captionStyle);
|
||||
}
|
||||
wrapper.appendChild(caption);
|
||||
}
|
||||
caption.innerText = col.caption ?? '';
|
||||
wrapper.appendChild(caption);
|
||||
// order arrow
|
||||
if (col.sortable) {
|
||||
th.appendChild(createElement('layer', 'arrow'));
|
||||
@ -906,13 +915,15 @@ export class Grid {
|
||||
}
|
||||
}
|
||||
|
||||
_changingColumnOrder(index, offset, x, offsetLeft, scrollLeft) {
|
||||
_changingColumnOrder(index, offset, mouse, draggerCellLeft) {
|
||||
const children = this._var.refs.header.children;
|
||||
let element = children[index];
|
||||
this._var.refs.dragger.style.cssText = `left: ${element.offsetLeft - offsetLeft + offset}px; width: ${element.style.width}; display: block`;
|
||||
offset = x + scrollLeft - element.offsetLeft; // getOffsetLeftFromWindow(element);
|
||||
this._var.refs.dragger.style.cssText = `left: ${element.offsetLeft - draggerCellLeft + offset}px; width: ${element.style.width}; display: block`;
|
||||
// offset = x + gridScrollLeft - element.offsetLeft; // getOffsetLeftFromWindow(element);
|
||||
offset += mouse;
|
||||
let idx;
|
||||
if (offset < 0) {
|
||||
const toLeft = offset < 0;
|
||||
if (toLeft) {
|
||||
offset = -offset;
|
||||
for (let i = index - 1; i >= 0 && offset >= 0; i -= 1) {
|
||||
element = children[i];
|
||||
@ -943,13 +954,27 @@ export class Grid {
|
||||
}
|
||||
idx ??= count - 1;
|
||||
}
|
||||
if (idx !== this._var.colAttrs.__orderIndex) {
|
||||
this._var.colAttrs.__orderIndex = idx;
|
||||
if (idx !== this._var.colAttrs.__orderIndex || this._var.refs.draggerCursor.style.display !== 'block') {
|
||||
element = children[idx];
|
||||
if (element == null) {
|
||||
return;
|
||||
}
|
||||
this._var.refs.draggerCursor.style.cssText = `left: ${element.offsetLeft - offsetLeft}px; display: block`;
|
||||
this._var.colAttrs.__orderIndex = idx;
|
||||
// avoid `offsetLeft` of hidden header to be 0
|
||||
let left;
|
||||
if (element.style.display === 'none') {
|
||||
left = 0;
|
||||
while (left === 0 && (element = children[++idx]) != null) {
|
||||
left = element.offsetLeft;
|
||||
}
|
||||
if (!toLeft && left === 0) {
|
||||
left = draggerCellLeft;
|
||||
}
|
||||
} else {
|
||||
left = element.offsetLeft;
|
||||
}
|
||||
// set position of dragger cursor
|
||||
this._var.refs.draggerCursor.style.cssText = `left: ${left - draggerCellLeft}px; display: block`;
|
||||
}
|
||||
}
|
||||
|
||||
@ -1057,14 +1082,21 @@ export class Grid {
|
||||
}
|
||||
}
|
||||
|
||||
_getItemValue(item, key, filter) {
|
||||
_getItemProp(item, editing, col) {
|
||||
let value;
|
||||
if (typeof filter === 'function') {
|
||||
value = filter(item, false, this._var.refs.body);
|
||||
if (typeof col?.filter === 'function') {
|
||||
value = col.filter(item, editing, this._var.refs.body);
|
||||
} else {
|
||||
value = item[key];
|
||||
value = item[col.key];
|
||||
}
|
||||
return value?.Value ?? value;
|
||||
if (value == null) {
|
||||
return value;
|
||||
}
|
||||
const prop = editing ? 'Value' : 'DisplayValue';
|
||||
if (Object.prototype.hasOwnProperty.call(value, prop)) {
|
||||
return value[prop];
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
_getRowTarget(target) {
|
||||
@ -1174,19 +1206,35 @@ export class Grid {
|
||||
} else {
|
||||
const dict = Object.create(null);
|
||||
for (let item of this._var.source) {
|
||||
const val = this._getItemValue(item.values, col.key, col.filter);
|
||||
if (!Object.hasOwnProperty.call(dict, val)) {
|
||||
const v = item.values[col.key];
|
||||
dict[val] = {
|
||||
let displayValue = this._getItemProp(item.values, false, col);
|
||||
if (displayValue == null) {
|
||||
displayValue = this.langs.null;
|
||||
}
|
||||
if (!Object.hasOwnProperty.call(dict, displayValue)) {
|
||||
const val = this._getItemProp(item.values, true, col);
|
||||
dict[displayValue] = {
|
||||
Value: val,
|
||||
DisplayValue: typeof col.filter === 'function' ? col.filter(item.values) : v?.DisplayValue ?? v
|
||||
DisplayValue: displayValue
|
||||
};
|
||||
}
|
||||
}
|
||||
array = Object.values(dict)
|
||||
.sort((a, b) => {
|
||||
a = a?.Value ?? a;
|
||||
b = b?.Value ?? b;
|
||||
if (a == null && b == null) {
|
||||
return 0;
|
||||
}
|
||||
if (a == null && b != null) {
|
||||
return -1;
|
||||
}
|
||||
if (a != null && b == null) {
|
||||
return 1;
|
||||
}
|
||||
if (Object.prototype.hasOwnProperty.call(a, 'Value')) {
|
||||
a = a.Value;
|
||||
}
|
||||
if (Object.prototype.hasOwnProperty.call(b, 'Value')) {
|
||||
b = b.Value;
|
||||
}
|
||||
return a > b ? 1 : a < b ? -1 : 0;
|
||||
});
|
||||
}
|
||||
@ -1197,7 +1245,7 @@ export class Grid {
|
||||
}
|
||||
return {
|
||||
Value: i,
|
||||
DisplayValue: i == null ? '' : i
|
||||
DisplayValue: i == null ? this.langs.null : i
|
||||
};
|
||||
});
|
||||
this._fillFilterList(col, itemlist, array, itemall);
|
||||
@ -1207,8 +1255,16 @@ export class Grid {
|
||||
searchbox.addEventListener('input', e => {
|
||||
const key = e.currentTarget.value.toLowerCase();
|
||||
const items = key.length === 0 ? array : array.filter(i => {
|
||||
const displayValue = i?.DisplayValue ?? i;
|
||||
return String(displayValue ?? '').toLowerCase().includes(key);
|
||||
let displayValue;
|
||||
if (i != null && Object.prototype.hasOwnProperty.call(i, 'DisplayValue')) {
|
||||
displayValue = i.DisplayValue;
|
||||
} else {
|
||||
displayValue = i;
|
||||
}
|
||||
if (displayValue == null) {
|
||||
displayValue = this.langs.null;
|
||||
}
|
||||
return String(displayValue).toLowerCase().includes(key);
|
||||
});
|
||||
this._fillFilterList(col, itemlist, items, itemall);
|
||||
});
|
||||
@ -1223,7 +1279,7 @@ export class Grid {
|
||||
if (typeof col.onFilterOk === 'function') {
|
||||
col.onFilterOk.call(this, col, array);
|
||||
} else {
|
||||
col.filterValues = array.map(a => a.Value);
|
||||
col.filterValues = array.map(a => a.DisplayValue);
|
||||
}
|
||||
this._var.colAttrs.__filtered = true;
|
||||
this._refreshSource();
|
||||
@ -1268,7 +1324,8 @@ export class Grid {
|
||||
content.style.top = `${rowHeight}px`;
|
||||
this._set(col.key, 'filterSource', array);
|
||||
for (let item of array) {
|
||||
item.__checked = !Array.isArray(col.filterValues) || col.filterValues.includes(item.Value ?? item);
|
||||
const v = Object.prototype.hasOwnProperty.call(item, 'DisplayValue') ? item.DisplayValue : item;
|
||||
item.__checked = !Array.isArray(col.filterValues) || col.filterValues.includes(v);
|
||||
}
|
||||
if (array.length > 12) {
|
||||
array = array.slice(0, 12);
|
||||
@ -1282,7 +1339,7 @@ export class Grid {
|
||||
const div = createElement('div', 'filter-item');
|
||||
div.appendChild(createCheckbox({
|
||||
checked: item.__checked,
|
||||
label: item?.DisplayValue ?? item,
|
||||
label: Object.prototype.hasOwnProperty.call(item, 'DisplayValue') ? item.DisplayValue : item,
|
||||
onchange: e => {
|
||||
item.__checked = e.target.checked;
|
||||
all.querySelector('input').checked = ![...content.querySelectorAll('input')].some(i => !i.checked);
|
||||
@ -1333,7 +1390,7 @@ export class Grid {
|
||||
const cx = getClientX(e);
|
||||
const clearEvents = attr => {
|
||||
for (let event of ['mousemove', 'mouseup']) {
|
||||
if (attr.hasOwnProperty(event)) {
|
||||
if (Object.prototype.hasOwnProperty.call(attr, event)) {
|
||||
window.removeEventListener(event, attr[event]);
|
||||
delete attr[event];
|
||||
}
|
||||
@ -1346,20 +1403,28 @@ export class Grid {
|
||||
clearEvents(attr);
|
||||
}
|
||||
attr.dragging = true;
|
||||
const offsetLeft = this._var.refs.header.querySelector('th:last-child').offsetLeft;
|
||||
const scrollLeft = this._var.el.scrollLeft;
|
||||
const draggerCellLeft = this._var.refs.header.querySelector('th:last-child').offsetLeft;
|
||||
// const gridScrollLeft = this._var.el.scrollLeft;
|
||||
let p = this._var.el;
|
||||
let gridLeftFromWindow = p.offsetLeft;
|
||||
while ((p = p.offsetParent) != null) {
|
||||
gridLeftFromWindow += p.offsetLeft + p.clientLeft;
|
||||
}
|
||||
const mouse = cx - e.currentTarget.offsetLeft + this._var.el.scrollLeft - gridLeftFromWindow;
|
||||
const dragmove = e => {
|
||||
const cx2 = getClientX(e);
|
||||
const offset = cx2 - cx;
|
||||
let pos = attr.offset;
|
||||
let dragging;
|
||||
if (pos == null && (offset > MiniDragOffset || offset < -MiniDragOffset)) {
|
||||
dragging = true;
|
||||
if (pos == null) {
|
||||
if (offset > MiniDragOffset || offset < -MiniDragOffset) {
|
||||
dragging = true;
|
||||
}
|
||||
} else if (pos !== offset) {
|
||||
dragging = true;
|
||||
}
|
||||
if (dragging) {
|
||||
this._changingColumnOrder(index, offset, cx2, offsetLeft, scrollLeft);
|
||||
this._changingColumnOrder(index, offset, mouse, draggerCellLeft);
|
||||
attr.offset = offset;
|
||||
}
|
||||
};
|
||||
@ -1386,7 +1451,7 @@ export class Grid {
|
||||
const window = this.window ?? global;
|
||||
const clearEvents = attr => {
|
||||
for (let event of ['mousemove', 'mouseup']) {
|
||||
if (attr.hasOwnProperty(event)) {
|
||||
if (Object.prototype.hasOwnProperty.call(attr, event)) {
|
||||
window.removeEventListener(event, attr[event]);
|
||||
delete attr[event];
|
||||
}
|
||||
@ -1648,7 +1713,7 @@ export class Grid {
|
||||
if (enabled !== false) {
|
||||
const val = item[col.key];
|
||||
let oldValue;
|
||||
if (val?.Value != null) {
|
||||
if (val != null && Object.prototype.hasOwnProperty.call(val, 'Value') != null) {
|
||||
oldValue = val.Value;
|
||||
val.Value = value;
|
||||
} else {
|
||||
|
Loading…
x
Reference in New Issue
Block a user