diff --git a/lib/ui/css/grid.scss b/lib/ui/css/grid.scss index ac5f2c0..c2e8d9d 100644 --- a/lib/ui/css/grid.scss +++ b/lib/ui/css/grid.scss @@ -94,6 +94,7 @@ // position: relative; top: 0; position: sticky; + z-index: 1; &.sticky { position: sticky; diff --git a/lib/ui/grid/column.js b/lib/ui/grid/column.js index 11dcaa0..51ac9d9 100644 --- a/lib/ui/grid/column.js +++ b/lib/ui/grid/column.js @@ -55,7 +55,8 @@ export class GridColumn { * 更多例子参考代码中 {@linkcode GridDropdownColumn} 的实现。 * @method * @name GridColumn.createEdit - * @param {Function} trigger - 编辑事件回调函数,`e` 参数会传递给 [getValue]{@linkcode GridColumn.getValue} 方法 + * @param {Function} trigger - 编辑事件回调函数 + * @param {any} trigger.e - 该参数会传递给 [getValue]{@linkcode GridColumn.getValue} 方法 * @param {GridColumnDefinition} col - 列定义对象 * @param {HTMLElement} container - 父容器元素 * @param {GridItemWrapper} wrapper - 行包装对象,其 `values` 属性为行数据对象 @@ -144,6 +145,29 @@ export class GridColumn { * @ignore */ static toString() { return '[object Column]' } + + /** + * @ignore + * @param {string} key + * @param {GridItemWrapper} wrapper + * @param {any} value + */ + static _changeValue(key, wrapper, value) { + const val = wrapper.values[key] ?? null; + const hasValue = val != null && Object.prototype.hasOwnProperty.call(val, 'Value'); + if (wrapper.__editing == null) { + wrapper.__editing = { + [key]: hasValue ? val.Value : val + } + } else if (!Object.prototype.hasOwnProperty.call(wrapper.__editing, key)) { + wrapper.__editing[key] = hasValue ? val.Value : val; + } + if (hasValue) { + val.Value = value; + } else { + wrapper.values[key] = value; + } + } } /** @@ -158,24 +182,17 @@ export class GridInputColumn extends GridColumn { /** * @ignore - * @param {Function} _trigger + * @param {Function} trigger * @param {GridColumnDefinition} col * @param {HTMLElement} _container * @param {GridItemWrapper} wrapper * @returns {HTMLElement} */ - static createEdit(_trigger, col, _container, wrapper) { + static createEdit(trigger, col, _container, wrapper) { const input = createElement('input'); input.setAttribute('type', 'text'); - input.addEventListener('input', () => { - if (wrapper.__editing == null) { - wrapper.__editing = { - [col.key]: true - } - } else { - wrapper.__editing[col.key] = true; - } - }); + input.addEventListener('input', () => super._changeValue(col.key, wrapper, input.value)); + input.addEventListener('change', trigger); return input; } @@ -221,23 +238,16 @@ export class GridInputColumn extends GridColumn { export class GridTextColumn extends GridInputColumn { /** * @ignore - * @param {Function} _trigger + * @param {Function} trigger * @param {GridColumnDefinition} col * @param {HTMLElement} _container * @param {GridItemWrapper} wrapper * @returns {HTMLElement} */ - static createEdit(_trigger, col, _container, wrapper) { + static createEdit(trigger, col, _container, wrapper) { const input = createElement('textarea'); - input.addEventListener('input', () => { - if (wrapper.__editing == null) { - wrapper.__editing = { - [col.key]: true - } - } else { - wrapper.__editing[col.key] = true; - } - }); + input.addEventListener('input', () => super._changeValue(col.key, wrapper, input.value)); + input.addEventListener('change', trigger); return input; } @@ -476,7 +486,7 @@ export class GridCheckboxColumn extends GridColumn { */ static createEdit(trigger) { const check = createCheckbox({ - onchange: typeof trigger === 'function' ? trigger : null + onchange: trigger }); return check; } @@ -604,13 +614,13 @@ export class GridDateColumn extends GridColumn { /** * @ignore - * @param {Function} _trigger + * @param {Function} trigger * @param {GridColumnDefinition} col * @param {HTMLElement} _container * @param {GridItemWrapper} wrapper * @returns {HTMLElement} */ - static createEdit(_trigger, col, _container, wrapper) { + static createEdit(trigger, col, _container, wrapper) { let enabled = col.enabled; if (typeof enabled === 'string') { enabled = wrapper.values[enabled]; @@ -621,15 +631,8 @@ export class GridDateColumn extends GridColumn { return super.create(); } const date = createDateInput(col.dateMin, col.dateMax); - date.addEventListener('change', () => { - if (wrapper.__editing == null) { - wrapper.__editing = { - [col.key]: true - } - } else { - wrapper.__editing[col.key] = true; - } - }); + date.addEventListener('change', () => super._changeValue(col.key, wrapper, date.value)); + date.addEventListener('blur', trigger); return date; } diff --git a/lib/ui/grid/grid.js b/lib/ui/grid/grid.js index b7a9118..261d50d 100644 --- a/lib/ui/grid/grid.js +++ b/lib/ui/grid/grid.js @@ -95,7 +95,7 @@ let r = lang; * @property {KeyMap} source - 下拉数据源缓存对象 * @property {number} __index - 行索引 * @property {number} __offset - 批量删除时暂存的索引偏移量 - * @property {KeyMap} __editing - 列正在编辑 + * @property {KeyMap} __editing - 正在编辑的列的原始值字典 * @property {boolean} __changed - 行数据是否发生改变 * @property {boolean} __expanded - 行是否已展开 * @property {GridExpandableObject} __expandable_object - 行扩展对象 @@ -2593,19 +2593,30 @@ export class Grid { const type = isCheckbox ? GridCheckboxColumn : this._var.colTypes[col.key] ?? GridColumn; let element; if (!readonly && !isCheckbox && typeof type.createEdit === 'function') { - if (vals.__editing?.[col.key]) { + const oldValue = vals.__editing?.[col.key]; + if (oldValue !== undefined) { delete vals.__editing[col.key]; if (typeof type.leaveEdit === 'function') { type.leaveEdit(cell.children[0], this._var.el); } if (type.editing) { val = type.getValue({ target: cell.children[0] }, col); - this._onRowChanged(null, i, col, val, cell); + this._onRowChanged(null, i, col, val, cell, oldValue); } } if (stateChanged) { element = selected ? - type.createEdit(e => this._onRowChanged(e, i, col, type.getValue(e, col), cell), col, this._var.el, vals) : + type.createEdit(e => { + let old; + if (type.editing) { + old = vals.__editing?.[col.key]; + if (old === undefined) { + return; + } + delete vals.__editing[col.key]; + } + this._onRowChanged(e, i, col, type.getValue(e, col), cell, old); + }, col, this._var.el, vals) : type.create(col, i, this); if (typeof col.class === 'string') { type.setClass(element, col.class); @@ -3783,8 +3794,9 @@ export class Grid { * @param {GridColumnDefinition} col * @param {any} value * @param {HTMLTableCellElement} cell + * @param {any} [oldValue] */ - _onRowChanged(e, index, col, value, cell) { + _onRowChanged(e, index, col, value, cell, oldValue) { if (this._var.currentSource == null) { return; } @@ -3802,12 +3814,11 @@ export class Grid { } if (enabled !== false) { const val = item[col.key]; - let oldValue; if (val != null && Object.prototype.hasOwnProperty.call(val, 'Value')) { - oldValue = val.Value; + oldValue ??= val.Value; val.Value = value; } else { - oldValue = val; + oldValue ??= val; item[col.key] = value; } let tip = col.tooltip; diff --git a/lib/ui/icon.js b/lib/ui/icon.js index d7d9046..ad28973 100644 --- a/lib/ui/icon.js +++ b/lib/ui/icon.js @@ -1650,8 +1650,9 @@ const dict = { function createUse(type, id) { const c = typeof consts !== 'undefined' ? consts : {}; - const netroot = typeof _network !== 'undefined' ? _network.root : ''; - const path = c.path || netroot; + const path = c.path || + (typeof _network !== 'undefined' ? _network.root : + (typeof _net !== 'undefined' ? _net.root : '')); const ver = c.resver == null ? '' : `?${c.resver}`; const use = document.createElementNS(svgns, 'use'); if (id?.length === 1 && id.charCodeAt(0) > 0xf000) { diff --git a/lib/utility/strings.js b/lib/utility/strings.js index 3371e86..5cafa51 100644 --- a/lib/utility/strings.js +++ b/lib/utility/strings.js @@ -50,6 +50,8 @@ export function formatUrl(msg) { path = consts.path; } else if (typeof _network !== 'undefined') { path = _network.root; + } else if (typeof _net !== 'undefined') { + path = _net.root; } for (let r of rs) { msg = msg.replaceAll(r, ``);