feature: expandable rows
add: comments
This commit is contained in:
1 parent
24b5a22595
commit
5d199a2bfb
5 files changed
+574
-111
No files matched your search
@@ -283,6 +283,22 @@
|
||||
background-color: var(--row-bg-color);
|
||||
}
|
||||
|
||||
&.ui-expandable {
|
||||
&>svg {
|
||||
width: 24px;
|
||||
height: 34px;
|
||||
padding: 8px 3px;
|
||||
box-sizing: border-box;
|
||||
display: block;
|
||||
cursor: pointer;
|
||||
transition: opacity .12s ease;
|
||||
|
||||
&:hover {
|
||||
opacity: .4;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
>span {
|
||||
padding: var(--spacing-cell);
|
||||
display: block;
|
||||
@@ -402,6 +418,7 @@
|
||||
white-space: pre;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
overflow: hidden;
|
||||
visibility: hidden;
|
||||
opacity: 0;
|
||||
transition: visibility 0s linear .12s, opacity .12s ease;
|
||||
|
||||
+1
-1
@@ -261,7 +261,7 @@ export class DateSelector {
|
||||
* @static
|
||||
* @param {HTMLElement} [dom=document.body] 父元素
|
||||
* @param {Function} [trigger] 日期设置事件触发函数
|
||||
* @param {Date} trigger.[this]] - 上下文为触发设置日期的 `DateSelector` 实例
|
||||
* @param {Date} trigger.{this} - 上下文为触发设置日期的 `DateSelector` 实例
|
||||
* @param {Date} trigger.date - 修改后的日期值
|
||||
* @example <caption>HTML</caption>
|
||||
* <input id="dateFrom" data-type="date" data-min="1980-01-01"/>
|
||||
|
||||
+34
-20
@@ -12,6 +12,17 @@ import { createDateInput, formatDate, setDateValue, getDateValue } from "../date
|
||||
* @class
|
||||
*/
|
||||
export class GridColumn {
|
||||
/**
|
||||
* 设置该类型是否支持触发 {@linkcode GridColumnDefinition}`.onInputEnded` 方法<br/>
|
||||
* 该属性返回 `true` 后,在任意事件中修改行包装对象的 `__editing` 值,则会在行列元素变动时及时触发 [onInputEnded]{@linkcode GridColumnDefinition#onInputEnded} 方法,避免例如文本框还未触发 `onchange` 事件就被移除元素而导致的问题
|
||||
*
|
||||
* 更多例子参考代码中 {@linkcode GridInputColumn} 的实现
|
||||
* @member
|
||||
* @name GridColumn.editing
|
||||
* @readonly
|
||||
* @type {boolean}
|
||||
*/
|
||||
|
||||
/**
|
||||
* 创建显示单元格时调用的方法
|
||||
* @param {GridColumnDefinition} col - 列定义对象
|
||||
@@ -27,6 +38,8 @@ export class GridColumn {
|
||||
*
|
||||
* 元素修改后设置行包装对象的 `__editing` 后,支持在离开编辑状态时及时触发 [leaveEdit]{@linkcode GridColumn.leaveEdit} 方法<br/>
|
||||
* 更多例子参考代码中 {@linkcode GridDropdownColumn} 的实现。
|
||||
* @method
|
||||
* @name GridColumn.createEdit
|
||||
* @param {Function} trigger - 编辑事件回调函数,`e` 参数会传递给 [getValue]{@linkcode GridColumn.getValue} 方法
|
||||
* @param {GridColumnDefinition} col - 列定义对象
|
||||
* @param {HTMLElement} container - 父容器元素
|
||||
@@ -34,15 +47,25 @@ export class GridColumn {
|
||||
* @returns {HTMLElement} 返回创建的编辑状态的单元格元素
|
||||
* @virtual
|
||||
*/
|
||||
static createEdit() { }
|
||||
|
||||
/**
|
||||
* 创建列头时调用的方法
|
||||
* @method
|
||||
* @name GridColumn.createCaption
|
||||
* @param {GridColumnDefinition} col - 列定义对象
|
||||
* @returns {HTMLElement} 返回创建的列头元素
|
||||
* @virtual
|
||||
*/
|
||||
static createCaption() { }
|
||||
|
||||
/**
|
||||
* 获取编辑状态单元格值时调用的方法
|
||||
* @method
|
||||
* @name GridColumn.getValue
|
||||
* @param {any} `e` 由 [createEdit]{@linkcode GridColumn.createEdit} 方法中 `trigger` 函数传递来的对象
|
||||
* @param {GridColumnDefinition} col - 列定义对象
|
||||
* @returns {(string | boolean | number)} 返回单元格的值
|
||||
* @virtual
|
||||
*/
|
||||
|
||||
/**
|
||||
* 设置单元格值时调用的方法
|
||||
@@ -57,15 +80,6 @@ export class GridColumn {
|
||||
element.innerText = val;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取编辑状态单元格值时调用的方法
|
||||
* @param {any} `e` 由 [createEdit]{@linkcode GridColumn.createEdit} 方法中 `trigger` 函数传递来的对象
|
||||
* @param {GridColumnDefinition} col - 列定义对象
|
||||
* @returns {(string | boolean | number)} 返回单元格的值
|
||||
* @virtual
|
||||
*/
|
||||
static getValue() { }
|
||||
|
||||
/**
|
||||
* 设置单元格样式时调用的方法
|
||||
* @param {HTMLElement} element - 单元格元素
|
||||
@@ -94,27 +108,22 @@ export class GridColumn {
|
||||
|
||||
/**
|
||||
* 单元格离开编辑元素时触发,需要由行包装对象的 `__editing` 来确定是否触发。
|
||||
* @method
|
||||
* @name GridColumn.leaveEdit
|
||||
* @param {HTMLElement} element - 单元格元素
|
||||
* @param {HTMLElement} container - 父容器元素
|
||||
* @virtual
|
||||
*/
|
||||
static leaveEdit() { }
|
||||
|
||||
static toString() { return '[object Column]' }
|
||||
}
|
||||
|
||||
/**
|
||||
* 单行文本列
|
||||
* 单行文本输入列
|
||||
* @class
|
||||
* @extends GridColumn
|
||||
*/
|
||||
export class GridInputColumn extends GridColumn {
|
||||
/**
|
||||
* 设置该类型是否支持触发 [onInputEnded]{@linkcode GridColumnDefinition.onInputEnded} 方法<br/>
|
||||
* 该属性返回 `true` 后,在任意事件中修改行包装对象的 `__editing` 值,则会在行列元素变动时及时触发 [onInputEnded]{@linkcode GridColumnDefinition.onInputEnded} 方法,避免例如文本框还未触发 `onchange` 事件就被移除元素而导致的问题<br/>
|
||||
* 更多例子参考代码中 {@linkcode GridInputColumn} 的实现
|
||||
* @readonly
|
||||
* @type {boolean}
|
||||
*/
|
||||
static get editing() { return true };
|
||||
|
||||
static createEdit(trigger, col, _wrapper, vals) {
|
||||
@@ -185,6 +194,11 @@ export class GridTextColumn extends GridInputColumn {
|
||||
|
||||
const SymbolDropdown = Symbol.for('ui-dropdown');
|
||||
|
||||
/**
|
||||
* 下拉选择列
|
||||
* @class
|
||||
* @extends GridColumn
|
||||
*/
|
||||
export class GridDropdownColumn extends GridColumn {
|
||||
static createEdit(trigger, col, container, it) {
|
||||
const drop = new Dropdown({
|
||||
|
||||
+520
-89
@@ -15,12 +15,13 @@ const ColumnChangedType = {
|
||||
Resize: 'resize',
|
||||
Sort: 'sort'
|
||||
};
|
||||
const RefreshInterval = isMobile() ? 32 : 0;
|
||||
const RefreshInterval = isMobile() ? 32 : 10;
|
||||
const HoverInternal = 200;
|
||||
const RedumCount = 4;
|
||||
const MiniDragOffset = 10;
|
||||
const MiniColumnWidth = 50;
|
||||
const FilterPanelWidth = 200;
|
||||
const ExpandableWidth = 24;
|
||||
|
||||
function getClientX(e) {
|
||||
if (e == null) {
|
||||
@@ -58,9 +59,9 @@ let r = lang;
|
||||
* 行数据包装接口
|
||||
* @typedef GridItemWrapper
|
||||
* @property {object} values - 真实数据对象
|
||||
* @property {(GridItem | any)} values.[key]] 数据属性
|
||||
* @property {(GridItem | any)} values.{key} 数据属性
|
||||
* @property {object} source - 下拉数据源缓存对象
|
||||
* @property {GridSourceItem[]} source.[key]] 数据源
|
||||
* @property {GridSourceItem[]} source.{key} 数据源
|
||||
*/
|
||||
|
||||
/**
|
||||
@@ -84,6 +85,7 @@ let r = lang;
|
||||
* @param {GridItem} item - 行数据对象
|
||||
* @param {boolean} editing - 是否处于编辑状态
|
||||
* @param {HTMLElement} [body] - Grid 控件的 `<tbody>` 部分
|
||||
* @returns {any} - 返回过滤后的显示或编辑值
|
||||
* @this GridColumnDefinition
|
||||
*/
|
||||
|
||||
@@ -175,11 +177,46 @@ let r = lang;
|
||||
* @this GridColumnDefinition
|
||||
*/
|
||||
|
||||
/**
|
||||
* 下拉列表参数对象
|
||||
* @typedef DropdownOptions
|
||||
* @property {string} [textKey=text] - 文本关键字
|
||||
* @property {string} [valueKey=value] - 值关键字
|
||||
* @property {string} [htmlKey=html] - 源码显示的关键字
|
||||
* @property {number} [maxLength=500] - 最大输入长度
|
||||
* @property {boolean} [multiSelect] - 是否允许多选
|
||||
* @property {string} [selected] - 选中值
|
||||
* @property {string[]} [selectedList] - 选中的数组
|
||||
* @property {boolean} [disabled] - 是否禁用
|
||||
* @property {boolean} [input] - 是否支持输入
|
||||
* @property {boolean} [search] - 是否支持搜索
|
||||
* @property {string[]} [searchKeys] - 搜索的关键字数组
|
||||
* @property {string} [searchPlaceholder] - 搜索提示文本,默认值取语言资源 `searchHolder` "Search..."
|
||||
* @property {number} [tabIndex] - 焦点索引
|
||||
* @property {string} [placeholder] - 输入框的提示文本
|
||||
* @property {boolean} [slideFixed] - 是否固定为向下展开
|
||||
* @property {HTMLElement} [wrapper] - 父元素,默认添加到头元素之后
|
||||
*/
|
||||
|
||||
/**
|
||||
* 自定义日期格式化回调函数
|
||||
* @callback DateFormatterCallback
|
||||
* @param {Date} date - 日期值
|
||||
* @returns {any} 返回格式化后的结果
|
||||
*/
|
||||
|
||||
/**
|
||||
* 列定义接口
|
||||
* @typedef {object} GridColumnDefinition
|
||||
* @property {string} key - 列关键字,默认以该关键字从行数据中提取单元格值,行数据的关键字属性值里包含 DisplayValue 则优先显示此值
|
||||
* @property {(GridColumnTypeEnum | GridColumn)} [type=Grid.ColumnTypes.Common] - 列的类型,可以为 {@linkcode GridColumn} 的子类,或者内置类型 {@linkcode GridColumnTypeEnum}
|
||||
* @property {(GridColumnTypeEnum | GridColumn)} [type=Grid.ColumnTypes.Common] - 列的类型,可以为 {@linkcode GridColumn} 的子类,或者如下内置类型 {@linkcode Grid.ColumnTypes}
|
||||
* @property {number} type.Common=0 - 通用列(只读)
|
||||
* @property {number} type.Input=1 - 单行文本列
|
||||
* @property {number} type.Dropdown=2 - 下拉选择列
|
||||
* @property {number} type.Checkbox=3 - 复选框列
|
||||
* @property {number} type.Icon=4 - 图标列
|
||||
* @property {number} type.Text=5 - 多行文本列
|
||||
* @property {number} type.Date=6 - 日期选择列
|
||||
* @property {string} [caption] - 列标题文本
|
||||
* @property {object} [captionStyle] - 列标题的元素样式
|
||||
* @property {number} [width] - 大于 0 则设置为该宽度,否则根据列内容自动调整列宽
|
||||
@@ -188,8 +225,16 @@ let r = lang;
|
||||
*
|
||||
* * `boolean` 则直接使用该值
|
||||
* * `string` 则以该值为关键字从行数据中取值作为判断条件
|
||||
* * `(item: GridItem) => boolean` 则调用该函数(上下文为列定义对象),以返回值作为判断条件
|
||||
* * `GridItemBooleanCallback` 则调用如下回调,以返回值作为判断条件
|
||||
* @property {GridColumnDefinition} enabled.{this} - 上下文为列定义对象
|
||||
* @property {GridItem} enabled.item - 行数据对象
|
||||
* @property {boolean} enabled.{returns} - 返回是否启用
|
||||
* @property {GridItemFilterCallback} [filter] - 单元格取值采用该函数返回的值
|
||||
* @property {GridColumnDefinition} filter.{this} - 上下文为列定义对象
|
||||
* @property {GridItem} filter.item - 行数据对象
|
||||
* @property {boolean} filter.editing - 是否处于编辑状态
|
||||
* @property {HTMLElement} [filter.body] - Grid 控件的 `<tbody>` 部分
|
||||
* @property {any} filter.{returns} - 返回过滤后的显示或编辑值
|
||||
* @property {string} [text] - 单元格以该值填充内容,忽略filter与关键字属性
|
||||
* @property {boolean} [visible=true] - 列是否可见
|
||||
* @property {boolean} [resizable=true] - 列是否允许调整宽度
|
||||
@@ -198,30 +243,72 @@ let r = lang;
|
||||
* @property {boolean} [allcheck=false] - 列为复选框类型时是否在列头增加全选复选框
|
||||
* @property {object} [css] - 单元格css样式对象(仅在重建行元素时读取)
|
||||
* @property {GridItemObjectCallback} [styleFilter] - 根据返回值填充单元格样式(填充行列数据时读取)
|
||||
* @property {GridColumnDefinition} styleFilter.{this} - 上下文为列定义对象
|
||||
* @property {GridItem} styleFilter.item - 行数据对象
|
||||
* @property {object} styleFilter.{returns} - 返回样式对象
|
||||
* @property {GridItemStringCallback} [bgFilter] - 根据返回值设置单元格背景色
|
||||
* @property {GridColumnDefinition} bgFilter.{this} - 上下文为列定义对象
|
||||
* @property {GridItem} bgFilter.item - 行数据对象
|
||||
* @property {string} bgFilter.{returns} - 返回单元格背景色字符串
|
||||
* @property {object} [events] - 给单元格元素附加事件(事件函数上下文为数据行对象)
|
||||
* @property {Function} events.[event]] - 事件回调函数
|
||||
* @property {(object | GridItemObjectCallback)} [attrs] - 根据返回值设置单元格元素的附加属性,允许直接设置对象也支持函数返回对象
|
||||
* @property {Function} events.{event} - 事件回调函数
|
||||
* @property {(object | GridItemObjectCallback)} [attrs] - 根据返回值设置单元格元素的附加属性,允许直接设置对象也支持调用如下函数返回对象
|
||||
* @property {GridColumnDefinition} attrs.{this} - 上下文为列定义对象
|
||||
* @property {GridItem} attrs.item - 行数据对象
|
||||
* @property {object} attrs.{returns} - 返回附加属性对象
|
||||
* @property {boolean} [allowFilter=false] - 是否允许进行列头过滤
|
||||
* @property {(GridItem[] | GridColumnFilterSourceCallback)} [filterSource] - 自定义列过滤器的数据源(函数上下文为Grid)
|
||||
* @property {(GridItem[] | GridColumnFilterSourceCallback)} [filterSource] - 自定义列过滤器的数据源,允许调用如下函数
|
||||
* @property {Grid} filterSource.{this} - 上下文为 Grid
|
||||
* @property {GridColumnDefinition} filterSource.col - 列定义对象
|
||||
* @property {GridItem[]} filterSource.{returns} - 返回过滤器的数据数组
|
||||
* @property {GridItemSortCallback} [sortFilter] - 自定义列排序函数
|
||||
* @property {GridItem} sortFilter.a - 对比行数据1
|
||||
* @property {GridItem} sortFilter.b - 对比行数据2
|
||||
* @property {number} sortFilter.{returns} - 返回大小对比结果
|
||||
* @property {DropdownOptions} [dropOptions] - 列为下拉列表类型时以该值设置下拉框的参数
|
||||
* @property {(GridSourceItem[] | GridDropdownSourceCallback | Promise<GridSourceItem[]>)} [source] - 列为下拉列表类型时以该值设置下拉列表数据源,支持函数返回,也支持返回异步对象
|
||||
* @property {(GridSourceItem[] | Promise<GridSourceItem[]> | GridDropdownSourceCallback)} [source] - 列为下拉列表类型时以该值设置下拉列表数据源,支持返回异步对象,也支持如下函数返回
|
||||
* @property {GridItem} source.item - 行数据对象
|
||||
* @property {GridSourceItem[]} source.{returns} - 返回行下拉列表数据源
|
||||
* @property {boolean} [sourceCache=false] - 下拉列表数据源是否缓存结果(即行数据未发生变化时仅从source属性获取一次值)
|
||||
* @property {("fa-light" | "fa-regular" | "fa-solid")} [iconType=fa-light] - 列为图标类型时以该值设置图标样式(函数上下文为列定义对象)
|
||||
* @property {(string | GridItemStringCallback)} [iconClassName] - 列为图标类型时以该值作为单元格元素的额外样式类型(函数上下文为列定义对象)
|
||||
* @property {("fa-light" | "fa-regular" | "fa-solid")} [iconType=fa-light] - 列为图标类型时以该值设置图标样式
|
||||
* @property {(string | GridItemStringCallback)} [iconClassName] - 列为图标类型时以该值作为单元格元素的额外样式类型,支持直接使用字符串或者调用如下函数
|
||||
* @property {GridColumnDefinition} iconClassName.{this} - 上下文为列定义对象
|
||||
* @property {GridItem} iconClassName.item - 行数据对象
|
||||
* @property {string} iconClassName.{returns} - 返回额外样式类型字符串
|
||||
* @property {string} [dateMin] - 列为日期类型时以该值作为最小可选日期值
|
||||
* @property {string} [dateMax] - 列为日期类型时以该值作为最大可选日期值
|
||||
* @property {DateFormatterCallback} [dateValueFormatter] - 列为日期类型时自定义日期格式化函数
|
||||
* @property {(string | GridItemStringCallback)} [tooltip] - 以返回值额外设置单元格的tooltip(函数上下文为列定义对象)
|
||||
* @property {Date} dateValueFormatter.date - 日期值
|
||||
* @property {any} dateValueFormatter.{returns} - 返回格式化后的结果
|
||||
* @property {(string | GridItemStringCallback)} [tooltip] - 额外设置单元格的 tooltip,支持直接使用字符串或者调用如下函数
|
||||
* @property {GridColumnDefinition} tooltip.{this} - 上下文为列定义对象
|
||||
* @property {GridItem} tooltip.item - 行数据对象
|
||||
* @property {string} tooltip.{returns} - 返回额外 tooltip 字符串
|
||||
* @property {GridColumnCheckedCallback} [onAllChecked] - 列头复选框改变时触发
|
||||
* @property {Grid} onAllChecked.{this} - 上下文为 Grid
|
||||
* @property {GridColumnDefinition} onAllChecked.col - 列定义对象
|
||||
* @property {boolean} onAllChecked.flag - 是否选中
|
||||
* @property {GridCellChangedCallback} [onChanged] - 单元格发生变化时触发
|
||||
* @property {Grid} onChanged.{this} - 上下文为 Grid
|
||||
* @property {GridItem} onChanged.item - 行数据对象
|
||||
* @property {(boolean | string | number)} onChanged.value - 修改后的值
|
||||
* @property {(boolean | string | number)} onChanged.oldValue - 修改前的值
|
||||
* @property {any} [onChanged.e] - 列修改事件传递过来的任意对象
|
||||
* @property {GridCellInputEndedCallback} [onInputEnded] - 文本单元格在输入完成时触发的事件
|
||||
* @property {Grid} onInputEnded.{this} - 上下文为 Grid
|
||||
* @property {GridColumnDefinition} onInputEnded.col - 列定义对象
|
||||
* @property {string} onInputEnded.value - 修改后的文本框值
|
||||
* @property {GridColumnFilterOkCallback} [onFilterOk] - 列过滤点击 `OK` 时触发的事件
|
||||
* @property {Grid} onFilterOk.{this} - 上下文为 Grid
|
||||
* @property {GridColumnDefinition} onFilterOk.col - 列定义对象
|
||||
* @property {GridItem[]} onFilterOk.selected - 选中的过滤项
|
||||
* @property {GridColumnFilteredCallback} [onFiltered] - 列过滤后触发的事件
|
||||
* @property {Grid} onFiltered.{this} - 上下文为 Grid
|
||||
* @property {GridColumnDefinition} onFiltered.col - 列定义对象
|
||||
* @property {GridColumnDropExpandedCallback} [onDropExpanded] - 列为下拉框类型时在下拉列表展开时触发的事件
|
||||
* @property {GridColumnDefinition} onDropExpanded.{this} - 上下文为列定义对象
|
||||
* @property {GridItem} onDropExpanded.item - 行数据对象
|
||||
* @property {Dropdown} onDropExpanded.drop - 拉框对象
|
||||
*/
|
||||
|
||||
/**
|
||||
@@ -275,6 +362,20 @@ const GridColumnDirection = {
|
||||
* @property {("asc" | "desc")} order - 升序或降序
|
||||
*/
|
||||
|
||||
/**
|
||||
* 扩展行对象接口
|
||||
* @typedef GridExpandableObject
|
||||
* @property {HTMLElement} element - 扩展行元素
|
||||
*/
|
||||
|
||||
/**
|
||||
* 扩展行生成回调函数
|
||||
* @callback GridExpandableObjectCallback
|
||||
* @param {GridItem} item - 行数据对象
|
||||
* @returns {GridExpandableObject} 返回扩展行对象
|
||||
* @this Grid
|
||||
*/
|
||||
|
||||
/**
|
||||
* Grid 控件基础类
|
||||
*
|
||||
@@ -324,30 +425,168 @@ const GridColumnDirection = {
|
||||
*/
|
||||
export class Grid {
|
||||
_var = {
|
||||
/**
|
||||
* 父容器元素
|
||||
* @type {HTMLElement}
|
||||
*/
|
||||
parent: null,
|
||||
/**
|
||||
* Grid 元素 - `div.ui-grid`
|
||||
* @type {HTMLDivElement}
|
||||
*/
|
||||
el: null,
|
||||
/**
|
||||
* 全部数据数组
|
||||
* @type {GridItemWrapper[]}
|
||||
*/
|
||||
source: null,
|
||||
/**
|
||||
* 当前已过滤显示的数据数组
|
||||
* @type {GridItemWrapper[]}
|
||||
*/
|
||||
currentSource: null,
|
||||
/**
|
||||
* 当前选中的列索引
|
||||
* @type {number}
|
||||
*/
|
||||
selectedColumnIndex: -1,
|
||||
/**
|
||||
* 当前选中的行索引数组
|
||||
* @type {number[]}
|
||||
*/
|
||||
selectedIndexes: null,
|
||||
/**
|
||||
* 虚模式头部索引
|
||||
* @type {number}
|
||||
*/
|
||||
startIndex: 0,
|
||||
/**
|
||||
* 旧选择索引数组
|
||||
* @type {number[]}
|
||||
*/
|
||||
oldSelectedIndexes: null,
|
||||
/**
|
||||
* 旧虚模式头部索引
|
||||
*/
|
||||
oldIndex: null,
|
||||
/**
|
||||
* 当前滚动上边距
|
||||
* @type {number}
|
||||
*/
|
||||
scrollTop: 0,
|
||||
/**
|
||||
* 当前滚动左边距
|
||||
* @type {number}
|
||||
*/
|
||||
scrollLeft: 0,
|
||||
/**
|
||||
* 一页高度可显示的行数
|
||||
* @type {number}
|
||||
*/
|
||||
rowCount: -1,
|
||||
/**
|
||||
* 列类型缓存字典
|
||||
* @property {GridColumn} {key} - 关键字对应列的类型缓存对象
|
||||
*/
|
||||
colTypes: {},
|
||||
colAttrs: {}
|
||||
/**
|
||||
* 列属性字典
|
||||
* @property {object} {key} - 关键字对应列的拖拽、调整大小暂存对象
|
||||
* @property {boolean} {key}.dragging - 列正在拖拽
|
||||
* @property {number} {key}.offset - 列拖拽偏移
|
||||
* @property {Function} {key}.mousemove - 拖拽或调整大小移动回调函数
|
||||
* @property {Function} {key}.mouseup - 拖拽或调整大小鼠标释放回调函数
|
||||
* @property {number} {key}.resizing - 列临时大小
|
||||
* @property {boolean} {key}.sizing - 列已进入修改大小的状态
|
||||
* @property {boolean} {key}.autoResize - 列需要自动调整大小
|
||||
* @property {object} {key}.style - 列样式对象
|
||||
* @property {GridItem[]} {key}.filterSource - 列过滤面板数据源
|
||||
* @property {number} {key}.filterHeight - 列过滤面板高度
|
||||
* @property {number} {key}.filterTop - 列过滤面板滚动头部间距
|
||||
*/
|
||||
colAttrs: {
|
||||
/**
|
||||
* 有已过滤的列
|
||||
* @type {boolean}
|
||||
*/
|
||||
__filtered: false,
|
||||
/**
|
||||
* 过滤面板已打开
|
||||
* @type {boolean}
|
||||
*/
|
||||
__filtering: false,
|
||||
/**
|
||||
* 上一个目标排序列索引
|
||||
* @type {number}
|
||||
*/
|
||||
__orderIndex: -1,
|
||||
},
|
||||
/**
|
||||
* 是否处于渲染中
|
||||
* @type {boolean}
|
||||
*/
|
||||
rendering: false,
|
||||
/**
|
||||
* 正文高度
|
||||
* @type {number}
|
||||
*/
|
||||
containerHeight: null,
|
||||
/**
|
||||
* 正文宽度
|
||||
* @type {number}
|
||||
*/
|
||||
bodyClientWidth: null,
|
||||
/**
|
||||
* 是否需要 resize
|
||||
* @type {boolean}
|
||||
*/
|
||||
needResize: null,
|
||||
/**
|
||||
* 页面元素引用
|
||||
*/
|
||||
refs: {
|
||||
/**
|
||||
* 表格引用 - table.ui-grid-table
|
||||
* @type {HTMLTableElement}
|
||||
*/
|
||||
table: null,
|
||||
/**
|
||||
* 表格正文引用 - tbody
|
||||
* @type {HTMLTableSectionElement}
|
||||
*/
|
||||
body: null,
|
||||
/**
|
||||
* 表格头部引用 - thead>tr
|
||||
* @type {HTMLTableSectionElement}
|
||||
*/
|
||||
header: null,
|
||||
/**
|
||||
* 加载状态元素引用 - div.ui-grid-loading
|
||||
* @type {HTMLDivElement}
|
||||
*/
|
||||
loading: null,
|
||||
/**
|
||||
* 大小计算元素引用 - span.ui-grid-sizer
|
||||
* @type {HTMLSpanElement}
|
||||
*/
|
||||
sizer: null,
|
||||
/**
|
||||
* 包装元素引用 - div.ui-grid-wrapper
|
||||
* @type {HTMLDivElement}
|
||||
*/
|
||||
wrapper: null,
|
||||
/**
|
||||
* 拖拽块引用 - div.dragger
|
||||
* @type {HTMLDivElement}
|
||||
*/
|
||||
dragger: null,
|
||||
/**
|
||||
* 拖拽光标引用 - layer.dragger-cursor
|
||||
* @type {HTMLElement}
|
||||
*/
|
||||
draggerCursor: null,
|
||||
}
|
||||
};
|
||||
// _var.source;
|
||||
// _var.currentSource;
|
||||
// _var.parent;
|
||||
// _var.el;
|
||||
// _var.refs;
|
||||
// _var.rendering;
|
||||
// _var.selectedColumnIndex = -1;
|
||||
// _var.selectedIndexes;
|
||||
// _var.startIndex = 0;
|
||||
// _var.needResize;
|
||||
// _var.containerHeight;
|
||||
// _var.bodyClientWidth;
|
||||
// _var.rowCount = -1;
|
||||
// _var.scrollTop;
|
||||
// _var.scrollLeft;
|
||||
// _var.colTypes = {};
|
||||
// _var.colAttrs = {};
|
||||
// _var.vtable = [];
|
||||
|
||||
/**
|
||||
* 列定义的数组
|
||||
@@ -460,8 +699,26 @@ export class Grid {
|
||||
* 排序列数组
|
||||
* @type {GridColumnSortDefinition[]}
|
||||
* @default null
|
||||
* @property {string} column - 排序列的关键字
|
||||
* @property {("asc" | "desc")} order - 升序或降序
|
||||
*/
|
||||
sortArray = null;
|
||||
/**
|
||||
* 是否支持点击扩展
|
||||
* @type {boolean}
|
||||
* @default false
|
||||
*/
|
||||
expandable;
|
||||
/**
|
||||
* 扩展行生成器
|
||||
* @type {GridExpandableObjectCallback}
|
||||
* @property {Grid} {this} - 上下文为 Grid
|
||||
* @property {GridItem} item - 行数据对象
|
||||
* @property {GridExpandableObject} {returns} - 返回扩展行对象
|
||||
* @property {number} {returns}.index - 行索引
|
||||
* @property {HTMLElement} {returns}.element - 扩展行元素
|
||||
*/
|
||||
expandableGenerator;
|
||||
|
||||
/**
|
||||
* 即将选中行时触发
|
||||
@@ -469,6 +726,7 @@ export class Grid {
|
||||
* @param {number} index - 即将选中的行索引
|
||||
* @param {number} colIndex - 即将选中的列索引
|
||||
* @returns {boolean} 返回 `false`、`null`、`undefined`、`0` 等则取消选中动作
|
||||
* @this Grid
|
||||
*/
|
||||
willSelect;
|
||||
/**
|
||||
@@ -477,6 +735,7 @@ export class Grid {
|
||||
* @param {number} index - 点击的行索引
|
||||
* @param {number} colIndex - 点击的列索引
|
||||
* @returns {boolean} 返回 false 则取消事件冒泡
|
||||
* @this Grid
|
||||
*/
|
||||
cellClicked;
|
||||
|
||||
@@ -484,6 +743,7 @@ export class Grid {
|
||||
* 选中行发生变化时触发的事件
|
||||
* @event
|
||||
* @param {number} index - 选中的行索引
|
||||
* @this Grid
|
||||
*/
|
||||
onSelectedRowChanged;
|
||||
/**
|
||||
@@ -491,12 +751,14 @@ export class Grid {
|
||||
* @event
|
||||
* @param {number} index - 双击的行索引
|
||||
* @param {number} colIndex - 双击的列索引
|
||||
* @this Grid
|
||||
*/
|
||||
onCellDblClicked;
|
||||
/**
|
||||
* 行双击时触发的事件
|
||||
* @event
|
||||
* @param {number} index - 双击的行索引
|
||||
* @this Grid
|
||||
*/
|
||||
onRowDblClicked;
|
||||
/**
|
||||
@@ -509,31 +771,56 @@ export class Grid {
|
||||
* * "sort" 为发生列排序事件,此时 value 为 1(升序)或 -1(倒序)
|
||||
* @param {number} colIndex - 发生变化事件的列索引
|
||||
* @param {number | GridColumnDirection} value - 变化的值
|
||||
* @this Grid
|
||||
*/
|
||||
onColumnChanged;
|
||||
/**
|
||||
* 列滚动时触发的事件
|
||||
* @event
|
||||
* @param {Event} e - 滚动事件对象
|
||||
* @this Grid
|
||||
*/
|
||||
onBodyScrolled;
|
||||
/**
|
||||
* 扩展行展开时触发的事件
|
||||
* @event
|
||||
* @param {GridItem} item - 行数据对象
|
||||
* @param {GridExpandableObject} expandableObject - 由 [expandableGenerator]{@linkcode Grid#expandableGenerator} 产生的行扩展对象
|
||||
* @param {HTMLElement} expandableObject.element - 扩展行元素
|
||||
* @this Grid
|
||||
*/
|
||||
onRowExpanded;
|
||||
/**
|
||||
* 扩展行收缩时触发的事件
|
||||
* @event
|
||||
* @param {GridItem} item - 行数据对象
|
||||
* @param {GridExpandableObject} expandableObject - 由 [expandableGenerator]{@linkcode Grid#expandableGenerator} 产生的行扩展对象
|
||||
* @param {HTMLElement} expandableObject.element - 扩展行元素
|
||||
* @this Grid
|
||||
*/
|
||||
onRowCollapsed;
|
||||
|
||||
/**
|
||||
* 列类型枚举
|
||||
* @readonly
|
||||
* @type {GridColumnTypeEnum}
|
||||
* @property {number} Common=0 - 通用列(只读)
|
||||
* @property {number} Input=1 - 单行文本列
|
||||
* @property {number} Dropdown=2 - 下拉选择列
|
||||
* @property {number} Checkbox=3 - 复选框列
|
||||
* @property {number} Icon=4 - 图标列
|
||||
* @property {number} Text=5 - 多行文本列
|
||||
* @property {number} Date=6 - 日期选择列
|
||||
*/
|
||||
static get ColumnTypes() { return GridColumnTypeEnum }
|
||||
|
||||
/**
|
||||
*
|
||||
* @param {(string | HTMLElement)?} container Grid 控件所在的父容器,可以是 string 表示选择器,也可以是 HTMLElement 对象
|
||||
* Grid 控件构造函数<br/>
|
||||
* _**构造时可以不进行赋值,但是调用 init 函数时则必须进行赋值**_
|
||||
* Grid 控件构造函数
|
||||
* @param {(string | HTMLElement)?} container Grid 控件所在的父容器,可以是 string 表示选择器,也可以是 HTMLElement 对象<br/>_**构造时可以不进行赋值,但是调用 init 函数时则必须进行赋值**_
|
||||
* @param {Function} [getText] 获取多语言文本的函数代理
|
||||
* @param {string} getText.id - 资源 ID
|
||||
* @param {string} [getText.def] - 默认资源
|
||||
* @param {string} getText.[returns]] 返回的多语言
|
||||
* @param {string} getText.{returns} 返回的多语言
|
||||
*/
|
||||
constructor(container, getText) {
|
||||
this._var.parent = typeof container === 'string' ? document.querySelector(container) : container;
|
||||
@@ -589,6 +876,8 @@ export class Grid {
|
||||
/**
|
||||
* 获取已过滤的数据数组,或者设置数据并刷新列表
|
||||
* @type {GridItem[]}
|
||||
* @property {any} Value - 值
|
||||
* @property {string} DisplayValue - 显示值
|
||||
*/
|
||||
get source() { return this._var.currentSource?.map(s => s.values) }
|
||||
set source(list) {
|
||||
@@ -608,6 +897,13 @@ export class Grid {
|
||||
this._refreshSource(list);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取已过滤的数据中的扩展对象数组
|
||||
* @type {GridExpandableObject[]}
|
||||
* @property {HTMLElement} element - 扩展行元素
|
||||
*/
|
||||
get sourceExpandable() { return this._var.currentSource?.map(s => s.__expandable_object) }
|
||||
|
||||
/**
|
||||
* 设置单行数据
|
||||
* @param {number} index - 行索引
|
||||
@@ -840,9 +1136,13 @@ export class Grid {
|
||||
return this.columns[this.sortIndex]?.key;
|
||||
}
|
||||
|
||||
get tableRows() {
|
||||
get _tableRows() {
|
||||
// return [...this._var.refs.body.children];
|
||||
return Array.prototype.slice.call(this._var.refs.body.children);
|
||||
return Array.prototype.slice.call(this._var.refs.body.querySelectorAll('&>.ui-grid-row'));
|
||||
}
|
||||
|
||||
get _headerCells() {
|
||||
return Array.prototype.slice.call(this._var.refs.header.querySelectorAll('&>th.column'));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -856,7 +1156,7 @@ export class Grid {
|
||||
if (this.readonly !== true) {
|
||||
this.refresh();
|
||||
} else {
|
||||
this.tableRows.forEach((row, i) => {
|
||||
this._tableRows.forEach((row, i) => {
|
||||
if (indexes.includes(startIndex + i)) {
|
||||
row.classList.add('selected');
|
||||
} else if (row.classList.contains('selected')) {
|
||||
@@ -955,6 +1255,38 @@ export class Grid {
|
||||
e.stopPropagation();
|
||||
}
|
||||
});
|
||||
grid.addEventListener('mousedown', e => {
|
||||
if (e.target === this._var.el) {
|
||||
// cancel selections
|
||||
const selectedIndexes = this._var.selectedIndexes;
|
||||
if (selectedIndexes == null || selectedIndexes.length === 0) {
|
||||
return;
|
||||
}
|
||||
selectedIndexes.splice(0);
|
||||
if (this.readonly !== true) {
|
||||
this.refresh();
|
||||
} else {
|
||||
this._tableRows.forEach(row => {
|
||||
row.classList.remove('selected');
|
||||
});
|
||||
}
|
||||
if (typeof this.onSelectedRowChanged === 'function') {
|
||||
this.onSelectedRowChanged(selectedIndex);
|
||||
}
|
||||
this._var.selectedColumnIndex = -1;
|
||||
return;
|
||||
}
|
||||
let [parent, target] = this._getRowTarget(e.target);
|
||||
if (parent == null) {
|
||||
return;
|
||||
}
|
||||
const rowIndex = indexOfParent(parent);
|
||||
let colIndex = indexOfParent(target) - (this.expandable ? 1 : 0);
|
||||
if (colIndex >= this.columns.length) {
|
||||
colIndex = -1;
|
||||
}
|
||||
this._onRowClicked(e, rowIndex, colIndex);
|
||||
});
|
||||
container.replaceChildren(grid);
|
||||
const sizer = createElement('span', 'ui-grid-sizer');
|
||||
grid.appendChild(sizer);
|
||||
@@ -969,7 +1301,7 @@ export class Grid {
|
||||
const table = createElement('table', 'ui-grid-table');
|
||||
this._var.refs.table = table;
|
||||
this._createHeader(table);
|
||||
const body = this._createBody(table);
|
||||
this._createBody(table);
|
||||
wrapper.appendChild(table);
|
||||
// tooltip
|
||||
if (!this.tooltipDisabled) {
|
||||
@@ -985,7 +1317,7 @@ export class Grid {
|
||||
});
|
||||
holder.addEventListener('dblclick', e => this._onRowDblClicked(e));
|
||||
wrapper.appendChild(holder);
|
||||
body.addEventListener('mousemove', e => throttle(this._onBodyMouseMove, HoverInternal, this, e, holder), { passive: true });
|
||||
wrapper.addEventListener('mousemove', e => throttle(this._onGridMouseMove, HoverInternal, this, e, holder), { passive: true });
|
||||
}
|
||||
|
||||
// loading
|
||||
@@ -1057,7 +1389,7 @@ export class Grid {
|
||||
const filtered = this.columns.some(c => c.filterValues != null);
|
||||
if ((filtered ^ this._var.colAttrs.__filtered) === 1) {
|
||||
this._var.colAttrs.__filtered = filtered;
|
||||
const headers = this._var.refs.header.children;
|
||||
const headers = this._headerCells;
|
||||
for (let i = 0; i < this.columns.length; ++i) {
|
||||
const ele = headers[i].querySelector('.filter');
|
||||
if (ele == null) {
|
||||
@@ -1076,7 +1408,7 @@ export class Grid {
|
||||
if (this.extraRows > 0) {
|
||||
length += this.extraRows;
|
||||
}
|
||||
this._var.containerHeight = length * (this.rowHeight + 1);
|
||||
this._var.containerHeight = (length + 1) * (this.rowHeight + 1);
|
||||
if (!keep) {
|
||||
this._var.el.scrollTop = 0;
|
||||
// this._var.el.scrollLeft = 0;
|
||||
@@ -1095,7 +1427,7 @@ export class Grid {
|
||||
throw new Error('body has not been created.');
|
||||
}
|
||||
const widths = {};
|
||||
this._fillRows(this.tableRows, this.columns, widths);
|
||||
this._fillRows(this._tableRows, this.columns, widths);
|
||||
if (this._var.needResize && widths.flag) {
|
||||
this._var.needResize = false;
|
||||
this.columns.forEach((col, i) => {
|
||||
@@ -1161,7 +1493,7 @@ export class Grid {
|
||||
}
|
||||
this.sortArray = null;
|
||||
const direction = this.sortDirection;
|
||||
[...this._var.refs.header.children].forEach((th, i) => {
|
||||
[...this._headerCells].forEach((th, i) => {
|
||||
const arrow = th.querySelector('.arrow');
|
||||
if (arrow == null) {
|
||||
return;
|
||||
@@ -1223,7 +1555,7 @@ export class Grid {
|
||||
this.refresh();
|
||||
}
|
||||
// arrow icon
|
||||
[...this._var.refs.header.children].forEach((th, i) => {
|
||||
[...this._headerCells].forEach((th, i) => {
|
||||
const arrow = th.querySelector('.arrow');
|
||||
if (arrow == null) {
|
||||
return;
|
||||
@@ -1263,7 +1595,7 @@ export class Grid {
|
||||
grid.onSelectedRowChanged = rowChanged;
|
||||
const reload = index => {
|
||||
grid.selectedIndexes = [index];
|
||||
grid.scrollTop = index * grid.rowHeight;
|
||||
grid.scrollTop = index * (grid.rowHeight + 1);
|
||||
rowChanged(index);
|
||||
}
|
||||
buttonWrapper.append(
|
||||
@@ -1457,7 +1789,19 @@ export class Grid {
|
||||
const header = createElement('tr');
|
||||
thead.appendChild(header);
|
||||
const sizer = this._var.refs.sizer;
|
||||
let left = 0;
|
||||
let left = this.expandable ? ExpandableWidth : 0;
|
||||
if (this.expandable) {
|
||||
header.appendChild(createElement('th', th => {
|
||||
th.className = 'ui-expandable sticky';
|
||||
const w = `${ExpandableWidth}px`;
|
||||
th.style.cssText = convertCssStyle({
|
||||
'width': w,
|
||||
'max-width': w,
|
||||
'min-width': w,
|
||||
'left': '0px'
|
||||
});
|
||||
}, createElement('div')));
|
||||
}
|
||||
for (let col of this.columns) {
|
||||
if (col.visible === false) {
|
||||
const hidden = createElement('th', 'column');
|
||||
@@ -1600,42 +1944,47 @@ export class Grid {
|
||||
width += col.width + 1;
|
||||
}
|
||||
}
|
||||
if (width > 0) {
|
||||
table.style.width = `${width}px`;
|
||||
if (this.expandable) {
|
||||
width += ExpandableWidth;
|
||||
}
|
||||
table.style.width = `${width}px`;
|
||||
// body content
|
||||
body.addEventListener('mousedown', e => {
|
||||
let [parent, target] = this._getRowTarget(e.target);
|
||||
const rowIndex = indexOfParent(parent);
|
||||
let colIndex = indexOfParent(target);
|
||||
if (colIndex >= this.columns.length) {
|
||||
colIndex = -1;
|
||||
}
|
||||
this._onRowClicked(e, rowIndex, colIndex);
|
||||
});
|
||||
body.addEventListener('dblclick', e => this._onRowDblClicked(e));
|
||||
// this._adjustRows();
|
||||
// this._adjustRows(body);
|
||||
this._var.refs.body = body;
|
||||
|
||||
// this.refresh();
|
||||
return body;
|
||||
}
|
||||
|
||||
_adjustRows() {
|
||||
_adjustRows(content) {
|
||||
let count = this._var.rowCount;
|
||||
if (isNaN(count) || count < 0 || !this.virtual) {
|
||||
count = this._var.currentSource?.length ?? 0;
|
||||
}
|
||||
const cols = this.columns;
|
||||
const content = this._var.refs.body;
|
||||
const exists = content.children.length;
|
||||
const exists = content.querySelectorAll('&>.ui-grid-row').length;
|
||||
count -= exists;
|
||||
if (count > 0) {
|
||||
for (let i = 0; i < count; ++i) {
|
||||
const row = createElement('tr', 'ui-grid-row');
|
||||
let left = 0;
|
||||
let left = this.expandable ? ExpandableWidth : 0;
|
||||
if (this.expandable) {
|
||||
const icon = createIcon('fa-solid', 'caret-right');
|
||||
icon.dataset.expanded = '0';
|
||||
row.appendChild(createElement('td', td => {
|
||||
td.className = 'ui-expandable sticky';
|
||||
td.style.cssText = 'left: 0px';
|
||||
td.addEventListener('mousedown', e => {
|
||||
this._onExpandable(e, exists + i, row);
|
||||
e.stopPropagation();
|
||||
});
|
||||
},
|
||||
icon
|
||||
));
|
||||
}
|
||||
cols.forEach((col, j) => {
|
||||
const cell = createElement('td');
|
||||
const cell = createElement('td', 'ui-grid-cell');
|
||||
if (col.visible !== false) {
|
||||
let style = this._get(col.key, 'style') ?? {};
|
||||
if (col.isfixed) {
|
||||
@@ -1677,9 +2026,11 @@ export class Grid {
|
||||
content.appendChild(row);
|
||||
}
|
||||
} else if (count < 0) {
|
||||
for (let i = -1; i >= count; i -= 1) {
|
||||
// content.removeChild(content.children[exists + i]);
|
||||
content.children[exists + i].remove();
|
||||
let last = content.querySelectorAll('&>.ui-grid-row')[exists + count];
|
||||
while (last != null) {
|
||||
const next = last.nextElementSibling;
|
||||
last.remove();
|
||||
last = next;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1698,6 +2049,7 @@ export class Grid {
|
||||
this._var.oldSelectedIndexes = selectedIndexes.slice();
|
||||
}
|
||||
}
|
||||
const offset = this.expandable ? 1 : 0;
|
||||
[...rows].forEach((row, i) => {
|
||||
const vals = this._var.currentSource[startIndex + i];
|
||||
if (vals == null) {
|
||||
@@ -1714,11 +2066,59 @@ export class Grid {
|
||||
row.classList.remove('selected');
|
||||
}
|
||||
// data
|
||||
if (this.expandable) {
|
||||
const expanded = vals.__expanded;
|
||||
let rowExpanded = row.nextElementSibling;
|
||||
if (rowExpanded?.className !== 'ui-grid-row-expanded') {
|
||||
rowExpanded = null;
|
||||
}
|
||||
if (expanded) {
|
||||
let expandableObject = vals.__expandable_object;
|
||||
if (expandableObject == null && typeof this.expandableGenerator === 'function') {
|
||||
expandableObject = this.expandableGenerator(item);
|
||||
if (expandableObject?.element == null) {
|
||||
return;
|
||||
}
|
||||
expandableObject.element = createElement('td', td => {
|
||||
td.colSpan = cols.length + 2;
|
||||
},
|
||||
expandableObject.element
|
||||
);
|
||||
vals.__expandable_object = expandableObject;
|
||||
}
|
||||
if (rowExpanded == null) {
|
||||
rowExpanded = createElement('tr', 'ui-grid-row-expanded');
|
||||
this._var.refs.body.insertBefore(rowExpanded, row.nextElementSibling);
|
||||
} else {
|
||||
rowExpanded.style.display = '';
|
||||
}
|
||||
rowExpanded.replaceChildren(expandableObject.element);
|
||||
} else {
|
||||
if (rowExpanded != null) {
|
||||
rowExpanded.style.display = 'none';
|
||||
}
|
||||
}
|
||||
const iconCell = row.children[0];
|
||||
if (iconCell.children[0].dataset.expanded !== (expanded ? '1' : '0')) {
|
||||
const icon = createIcon('fa-solid', expanded ? 'caret-down' : 'caret-right');
|
||||
icon.dataset.expanded = expanded ? '1' : '0';
|
||||
iconCell.replaceChildren(icon);
|
||||
if (expanded) {
|
||||
if (typeof this.onRowExpanded === 'function') {
|
||||
this.onRowExpanded(vals.values, vals.__expandable_object);
|
||||
}
|
||||
} else {
|
||||
if (typeof this.onRowCollapsed === 'function') {
|
||||
this.onRowCollapsed(vals.values, vals.__expandable_object);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
cols.forEach((col, j) => {
|
||||
if (col.visible === false) {
|
||||
return;
|
||||
}
|
||||
const cell = row.children[j];
|
||||
const cell = row.children[j + offset];
|
||||
if (cell == null) {
|
||||
return;
|
||||
}
|
||||
@@ -1833,12 +2233,13 @@ export class Grid {
|
||||
style.width = w;
|
||||
style['max-width'] = w;
|
||||
style['min-width'] = w;
|
||||
const headerCells = this._var.refs.header.children;
|
||||
const headerCells = this._headerCells;
|
||||
let element = headerCells[index];
|
||||
element.style.width = w;
|
||||
element.style.maxWidth = w;
|
||||
element.style.minWidth = w;
|
||||
let left = 0;
|
||||
// element.style.cssText += `width: ${w}; max-width: ${w}; min-width: ${w}`;
|
||||
let left = this.expandable ? ExpandableWidth : 0;
|
||||
if (col.isfixed) {
|
||||
left = element.offsetLeft + width;
|
||||
let l = left;
|
||||
@@ -1851,15 +2252,17 @@ export class Grid {
|
||||
}
|
||||
}
|
||||
}
|
||||
for (let row of this.tableRows) {
|
||||
element = row.children[index];
|
||||
const offset = this.expandable ? 1 : 0;
|
||||
for (let row of this._tableRows) {
|
||||
element = row.children[index + offset];
|
||||
if (element != null) {
|
||||
element.style.width = w;
|
||||
element.style.maxWidth = w;
|
||||
element.style.minWidth = w;
|
||||
// element.style.cssText += `width: ${w}; max-width: ${w}; min-width: ${w}`;
|
||||
if (col.isfixed) {
|
||||
let l = left;
|
||||
for (let i = index + 1; i < this.columns.length; ++i) {
|
||||
for (let i = index + offset + 1; i < this.columns.length; ++i) {
|
||||
if (this.columns[i].isfixed) {
|
||||
row.children[i].style.left = `${l}px`;
|
||||
l += this.columns[i].width;
|
||||
@@ -1873,7 +2276,7 @@ export class Grid {
|
||||
}
|
||||
|
||||
_changingColumnOrder(index, offset, mouse, draggerCellLeft) {
|
||||
const children = this._var.refs.header.children;
|
||||
const children = this._headerCells;
|
||||
let element = children[index];
|
||||
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);
|
||||
@@ -1945,9 +2348,10 @@ export class Grid {
|
||||
return;
|
||||
}
|
||||
const header = this._var.refs.header;
|
||||
const children = header.children;
|
||||
const rows = this.tableRows;
|
||||
const children = this._headerCells;
|
||||
const rows = this._tableRows;
|
||||
const columns = this.columns;
|
||||
const offset = this.expandable ? 1 : 0;
|
||||
if (targetIndex > 1) {
|
||||
targetIndex = orderIndex - 1;
|
||||
// const current = columns[index];
|
||||
@@ -1959,7 +2363,7 @@ export class Grid {
|
||||
columns.splice(targetIndex, 0, current);
|
||||
header.insertBefore(children[index], children[targetIndex].nextElementSibling);
|
||||
for (let row of rows) {
|
||||
row.insertBefore(row.children[index], row.children[targetIndex].nextElementSibling);
|
||||
row.insertBefore(row.children[index + offset], row.children[targetIndex + offset].nextElementSibling);
|
||||
}
|
||||
} else {
|
||||
targetIndex = orderIndex;
|
||||
@@ -1972,7 +2376,7 @@ export class Grid {
|
||||
columns.splice(targetIndex, 0, current);
|
||||
header.insertBefore(children[index], children[targetIndex]);
|
||||
for (let row of rows) {
|
||||
row.insertBefore(row.children[index], row.children[targetIndex]);
|
||||
row.insertBefore(row.children[index + offset], row.children[targetIndex + offset]);
|
||||
}
|
||||
}
|
||||
if (this.sortArray == null || this.sortArray.length === 0) {
|
||||
@@ -2066,6 +2470,13 @@ export class Grid {
|
||||
return [parent, target];
|
||||
}
|
||||
|
||||
_getParentElement(element) {
|
||||
while (element != null && element.className !== 'ui-grid') {
|
||||
element = element.parentElement;
|
||||
}
|
||||
return element;
|
||||
}
|
||||
|
||||
_notHeader(tagName) {
|
||||
return /^(input|label|layer|svg|use)$/i.test(tagName);
|
||||
}
|
||||
@@ -2243,7 +2654,11 @@ export class Grid {
|
||||
if (typeof col.onFilterOk === 'function') {
|
||||
col.onFilterOk.call(this, col, array);
|
||||
} else {
|
||||
col.filterValues = array.map(a => a.DisplayValue);
|
||||
if (GridColumnTypeEnum.isCheckbox(col.type)) {
|
||||
col.filterValues = array.map(a => a.Value);
|
||||
} else {
|
||||
col.filterValues = array.map(a => a.DisplayValue);
|
||||
}
|
||||
}
|
||||
this._var.colAttrs.__filtered = true;
|
||||
this._refreshSource();
|
||||
@@ -2287,8 +2702,9 @@ export class Grid {
|
||||
const content = createElement('div', 'filter-content');
|
||||
content.style.top = `${rowHeight}px`;
|
||||
this._set(col.key, 'filterSource', array);
|
||||
const propKey = GridColumnTypeEnum.isCheckbox(col.type) ? 'Value' : 'DisplayValue';
|
||||
for (let item of array) {
|
||||
const v = Object.prototype.hasOwnProperty.call(item, 'DisplayValue') ? item.DisplayValue : item;
|
||||
const v = Object.prototype.hasOwnProperty.call(item, propKey) ? item[propKey] : item;
|
||||
item.__checked = !Array.isArray(col.filterValues) || col.filterValues.includes(v);
|
||||
}
|
||||
if (array.length > 12) {
|
||||
@@ -2350,7 +2766,7 @@ export class Grid {
|
||||
if (e.currentTarget.classList.contains('sticky')) {
|
||||
return;
|
||||
}
|
||||
const index = indexOfParent(e.currentTarget);
|
||||
const index = indexOfParent(e.currentTarget) - (this.expandable ? 1 : 0);
|
||||
const cx = getClientX(e);
|
||||
const clearEvents = attr => {
|
||||
for (let event of ['mousemove', 'mouseup']) {
|
||||
@@ -2411,7 +2827,7 @@ export class Grid {
|
||||
_onResizeStart(e, col) {
|
||||
const cx = getClientX(e);
|
||||
const width = col.width;
|
||||
const index = indexOfParent(e.currentTarget.parentElement);
|
||||
const index = indexOfParent(e.currentTarget.parentElement) - (this.expandable ? 1 : 0);
|
||||
const window = this.window ?? global;
|
||||
const clearEvents = attr => {
|
||||
for (let event of ['mousemove', 'mouseup']) {
|
||||
@@ -2462,9 +2878,10 @@ export class Grid {
|
||||
_onAutoResize(e, col) {
|
||||
const th = e.currentTarget.parentElement;
|
||||
const index = indexOfParent(th);
|
||||
const offset = this.expandable ? 1 : 0;
|
||||
let width = th.querySelector('div:first-child').scrollWidth;
|
||||
for (let row of this.tableRows) {
|
||||
const element = row.children[index].children[0];
|
||||
for (let row of this._tableRows) {
|
||||
const element = row.children[index + offset].children[0];
|
||||
const w = element.scrollWidth;
|
||||
if (w > width) {
|
||||
width = w;
|
||||
@@ -2475,9 +2892,9 @@ export class Grid {
|
||||
}
|
||||
if (width > 0 && width !== col.width) {
|
||||
width += 12;
|
||||
this._changeColumnWidth(index, width);
|
||||
this._changeColumnWidth(index - offset, width);
|
||||
if (typeof this.onColumnChanged === 'function') {
|
||||
this.onColumnChanged(ColumnChangedType.Resize, index, width);
|
||||
this.onColumnChanged(ColumnChangedType.Resize, index - offset, width);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -2524,7 +2941,8 @@ export class Grid {
|
||||
this._scrollToTop(top);
|
||||
}
|
||||
|
||||
_onBodyMouseMove(e, holder) {
|
||||
_onGridMouseMove(e, holder) {
|
||||
e.stopPropagation();
|
||||
if (e.target.classList.contains('ui-grid-hover-holder')) {
|
||||
return;
|
||||
}
|
||||
@@ -2537,6 +2955,10 @@ export class Grid {
|
||||
}
|
||||
return;
|
||||
}
|
||||
if (this._getParentElement(parent) !== this._var.el) {
|
||||
// sub ui-grid
|
||||
return;
|
||||
}
|
||||
const element = target.children[0];
|
||||
if (element?.tagName !== 'SPAN') {
|
||||
if (holder.classList.contains('active')) {
|
||||
@@ -2621,7 +3043,7 @@ export class Grid {
|
||||
if (this.readonly !== true) {
|
||||
this.refresh();
|
||||
} else {
|
||||
this.tableRows.forEach((row, i) => {
|
||||
this._tableRows.forEach((row, i) => {
|
||||
if (selectedIndexes.includes(startIndex + i)) {
|
||||
row.classList.add('selected');
|
||||
} else if (row.classList.contains('selected')) {
|
||||
@@ -2705,4 +3127,13 @@ export class Grid {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
_onExpandable(_e, index, _row) {
|
||||
if (this._var.currentSource == null) {
|
||||
return;
|
||||
}
|
||||
const vals = this._var.currentSource[this._var.startIndex + index];
|
||||
vals.__expanded = !vals.__expanded
|
||||
this.refresh();
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user