This commit is contained in:
2024-07-10 12:19:52 +08:00
parent 5baf00de64
commit adbf4750cc
16 changed files with 1176 additions and 722 deletions

View File

@ -87,6 +87,17 @@ function filterSource(searchkeys, textkey, key, source) {
return source;
}
function getValue(it, valuekey, textkey) {
if (it == null) {
return null;
}
const value = it[valuekey];
if (value == null || value === '') {
return it[textkey];
}
return value;
}
/**
* 下拉列表参数对象
* @typedef DropdownOptions
@ -171,6 +182,7 @@ export class Dropdown {
const source = this.source;
const count = source.length;
const valuekey = this._var.options.valueKey;
const textkey = this._var.options.textKey;
let index = source?.indexOf(this._var.selected);
if (isNaN(index) || index < -1) {
index = -1;
@ -192,7 +204,7 @@ export class Dropdown {
index = count - 1;
}
}
const target = source[index]?.[valuekey];
const target = getValue(source[index], valuekey, textkey);
if (target != null) {
this.select(target);
}
@ -315,7 +327,7 @@ export class Dropdown {
const textkey = this._var.options.textKey;
const template = this._var.options.htmlTemplate;
const htmlkey = this._var.options.htmlKey;
let item = this.source.find(it => (ignoreCase ? String(it[valuekey]).toLowerCase() : String(it[valuekey])) === selected);
let item = this.source.find(it => (ignoreCase ? String(getValue(it, valuekey, textkey)).toLowerCase() : String(getValue(it, valuekey, textkey))) === selected);
if (this._var.options.input) {
if (item == null) {
item = { [valuekey]: selected };
@ -377,7 +389,7 @@ export class Dropdown {
const htmlkey = this._var.options.htmlKey;
const itemlist = selectedlist.map(a => {
const v = typeof a === 'string' ? a : String(a);
let item = source.find(it => String(it[valuekey]) === v);
let item = source.find(it => String(getValue(it, valuekey, textkey)) === v);
if (item == null) {
item = {
[valuekey]: v,
@ -557,15 +569,16 @@ export class Dropdown {
}
const multiselect = this.multiSelect;
const valuekey = this._var.options.valueKey;
const textkey = this._var.options.textKey;
const allchecked = this._var.allChecked;
const selectedlist = this.selectedList;
source.forEach((item, i) => {
let val = item[valuekey];
let val = getValue(item, valuekey, textkey);
if (typeof val !== 'string') {
val = String(val);
}
if (multiselect) {
const selected = selectedlist.some(s => String(s[valuekey]) === val);
const selected = selectedlist.some(s => String(getValue(s, valuekey, textkey)) === val);
item.__checked = allchecked || selected;
}
});
@ -588,7 +601,7 @@ export class Dropdown {
const selected = this.selected;
let scrolled;
array.forEach((item, i) => {
let val = item[valuekey];
let val = getValue(item, valuekey, textkey);
if (typeof val !== 'string') {
val = String(val);
}
@ -671,9 +684,9 @@ export class Dropdown {
if (all != null) {
all.checked = false;
}
list = this.source.filter(it => String(it[valuekey]) !== val);
list = this.source.filter(it => String(getValue(it, valuekey, textkey)) !== val);
} else {
list = this.selectedList.filter(it => String(it[valuekey]) !== val);
list = this.selectedList.filter(it => String(getValue(it, valuekey, textkey)) !== val);
}
}
}

View File

@ -14,7 +14,7 @@ import { requestAnimationFrame } from '../../ui';
/**
* @author Tsanie Lily <tsorgy@gmail.com>
* @license MIT
* @version 1.0.6
* @version 1.0.7
*/
const ScriptPath = (self.document == null ? self.location.href : self.document.currentScript?.src ?? '').replace(/ui\.min\.js\?.+$/, '');
@ -259,7 +259,7 @@ let r = lang;
* @property {GridItemObjectCallback} [styleFilter] - **已过时**<br/>_根据返回值填充单元格样式填充行列数据时读取_
* @property {(string | GridItemStringCallback)} [background] - 设置单元格背景色(填充行列数据时读取),支持直接设置颜色字符串或调用函数返回(若赋值则忽略 [bgFilter]{@linkcode GridColumnDefinition#bgFilter}
* @property {GridItemStringCallback} [bgFilter] - **已过时**<br/>_根据返回值设置单元格背景色_
* @property {boolean} [switch=false] - 复选框为 `ui-switch` 样式 `@since 1.0.6`
* @property {boolean} [switch=false] - 复选框为 `ui-switch` 样式 *@since* 1.0.6
* @property {(any | GridItemObjectCallback)} [attrs] - 根据返回值设置单元格元素的附加属性,允许直接设置对象也支持调用函数返回对象
* @property {KeyMap<Function>} [events] - 给单元格元素附加事件(事件函数上下文为数据行对象)
* @property {boolean} [allowFilter=false] - 是否允许进行列头过滤
@ -1065,7 +1065,9 @@ export class Grid {
/**
* 列滚动时触发的事件
* @event
* @param {Event} e - 滚动事件对象
* @param {Event} [e] - 滚动事件对象
* @param {number} index - 起始行
* @param {number} count - 显示行数
* @this Grid
*/
onBodyScrolled;
@ -1136,7 +1138,7 @@ export class Grid {
* @property {boolean} [tooltipDisabled=false] - 单元格 tooltip 是否禁用
* @property {boolean} [headerVisible=true] - 列头是否显示
* @property {boolean} [headerWrap=true] - 列头是否允许换行
* @property {boolean} [rowDraggable=false] - 是否允许行间拖拽 @since 1.0.3
* @property {boolean} [rowDraggable=false] - 是否允许行间拖拽 *since* 1.0.3
* @property {(Window | HTMLElement)} [window=global] - 监听事件的窗口载体
* @property {number} [sortIndex=-1] - 排序列的索引
* @property {GridColumnDirection} [sortDirection=GridColumnDirection.Ascending] - 排序方式,正数升序,负数倒序
@ -1205,6 +1207,16 @@ export class Grid {
return this.columns[this.sortIndex]?.key;
}
/**
* 获取当前选中的行对象
* @readonly
* @type {GridRowItem | null}
* @since 1.0.7
*/
get currentItem() {
return this.source[this.selectedIndex];
}
/**
* @private
* @type {HTMLTableRowElement[]}
@ -1526,10 +1538,10 @@ export class Grid {
this._var.rendering = false;
if (this._var.source != null) {
if (this.sortIndex >= 0) {
this.sortColumn(true);
} else if (this.sortArray?.length > 0) {
if (this.sortArray?.length > 0) {
this.sort(true);
} else if (this.sortIndex >= 0) {
this.sortColumn(true);
} else {
this.resize(true);
}
@ -1575,6 +1587,14 @@ export class Grid {
const count = truncate((height - 1) / (this.rowHeight + 1)) + (RedumCount * 2) + 1;
if (force || count !== this._var.rowCount) {
this._var.rowCount = count;
if (typeof this.onBodyScrolled === 'function') {
if (!this.virtual) {
const tti = this._topToIndex(this._var.el.scrollTop);
this.onBodyScrolled(null, tti.index, count);
} else {
this.onBodyScrolled(null, this._var.startIndex, count);
}
}
if (typeof callback === 'function') {
callback.call(this);
} else {
@ -1792,8 +1812,8 @@ export class Grid {
/**
* 显示多列排序设置面板
* @param {Function} [callback] - 更新回调函数 @since 1.0.3
* @param {boolean} [layout] - 是否显示更新 layout 复选框 @since 1.0.3
* @param {Function} [callback] - 更新回调函数 *@since* 1.0.3
* @param {boolean} [layout] - 是否显示更新 layout 复选框 *@since* 1.0.3
* @since 1.0.1
*/
showSortPanel(callback, layout) {
@ -1989,6 +2009,8 @@ export class Grid {
const source = grid.source;
if (source == null || source.length === 0) {
this.sortArray = null;
this.sortIndex = -1;
this.sortDirection = GridColumnDirection.Ascending;
// arrow icon
[...this._headerCells].forEach((th, i) => {
const arrow = th.querySelector('.arrow');
@ -2081,10 +2103,10 @@ export class Grid {
// FIXME: 清除缓存会导致选中状态下动态数据源下拉列表显示为空
// delete it.source;
it.values = item;
if (this.sortIndex >= 0) {
this.sortColumn();
} else if (this.sortArray?.length > 0) {
if (this.sortArray?.length > 0) {
this.sort();
} else if (this.sortIndex >= 0) {
this.sortColumn();
} else {
this.refresh();
}
@ -2122,10 +2144,10 @@ export class Grid {
this._var.source.push(newIt);
}
}
if (this.sortIndex >= 0) {
this.sortColumn(true);
} else if (this.sortArray?.length > 0) {
if (this.sortArray?.length > 0) {
this.sort(true);
} else if (this.sortIndex >= 0) {
this.sortColumn(true);
} else {
this.reload();
}
@ -2169,10 +2191,10 @@ export class Grid {
this._var.source.push(...items);
}
}
if (this.sortIndex >= 0) {
this.sortColumn(true);
} else if (this.sortArray?.length > 0) {
if (this.sortArray?.length > 0) {
this.sort(true);
} else if (this.sortIndex >= 0) {
this.sortColumn(true);
} else {
this.reload();
}
@ -2564,10 +2586,10 @@ export class Grid {
this._var.rowCount = -1;
this.resize(true, false, () => {
if (this.sortIndex >= 0) {
this.sortColumn(true);
} else if (this.sortArray?.length > 0) {
if (this.sortArray?.length > 0) {
this.sort(true);
} else if (this.sortIndex >= 0) {
this.sortColumn(true);
} else {
this.reload();
}
@ -3515,13 +3537,7 @@ export class Grid {
}
}
/**
* @private
* @param {number} top
* @param {boolean} [reload]
* @returns {number}
*/
_scrollToTop(top, reload) {
_topToIndex(top) {
const rowHeight = (this.rowHeight + 1);
top -= (top % (rowHeight * 2)) + (RedumCount * rowHeight);
if (top < 0) {
@ -3535,10 +3551,22 @@ export class Grid {
top = bottomTop;
}
}
return { top, index: top / rowHeight };
}
/**
* @private
* @param {number} top
* @param {boolean} [reload]
* @returns {number}
*/
_scrollToTop(top, reload) {
const tti = this._topToIndex(top);
top = tti.top;
if (this._var.scrollTop !== top) {
this._var.scrollTop = top;
if (this.virtual) {
this._var.startIndex = top / rowHeight;
this._var.startIndex = tti.index;
}
this._fillRows(this._tableRows, this.columns);
if (this.virtual) {
@ -4241,21 +4269,25 @@ export class Grid {
if (this._var.colAttrs.__filtering != null) {
this._onCloseFilter();
}
if (this.onBodyScrolled === 'function') {
this.onBodyScrolled(e);
}
this._var.scrollLeft = e.target.scrollLeft;
const top = e.target.scrollTop;
if (!this.virtual) {
if (this.total != null) {
this._var.refs.footer.parentElement.style.bottom = `${this._var.footerOffset - e.target.scrollTop}px`;
}
const tti = this._topToIndex(top);
if (this.onBodyScrolled === 'function') {
this.onBodyScrolled(e, tti.index, this._var.rowCount);
}
return;
}
const top = e.target.scrollTop;
this._scrollToTop(top);
if (this.total != null) {
this._var.refs.footer.parentElement.style.bottom = `${this._var.refs.table.offsetTop + this._var.footerOffset - e.target.scrollTop}px`;
}
if (this.onBodyScrolled === 'function') {
this.onBodyScrolled(e, this._var.startIndex, this._var.rowCount);
}
if (this._var.isFirefox) {
// 修复 firefox 下列头显示位置不正确的问题
debounce(this._fillRows, RefreshInterval, this, this._tableRows, this.columns);

2
lib/ui/popup.d.ts vendored
View File

@ -63,7 +63,7 @@ interface PopupOptions {
/**
* 弹出框关闭时的回调函数
*/
resolve?: () => void;
resolve?: (this: Popup, result: { result: any, popup: Popup }) => void;
}
export class Popup {