diff --git a/lib/ui/css/grid.scss b/lib/ui/css/grid.scss index 341cc7c..093bd84 100644 --- a/lib/ui/css/grid.scss +++ b/lib/ui/css/grid.scss @@ -125,6 +125,14 @@ >.ui-check-wrapper { height: 20px; } + + >svg { + width: 14px; + min-width: 14px; + height: 14px; + margin-left: 4px; + fill: var(--split-border-color); + } } >.arrow { @@ -367,6 +375,7 @@ box-sizing: border-box; width: 100%; padding: 0; + max-height: none !important; @include outline(); diff --git a/lib/ui/grid/column.js b/lib/ui/grid/column.js index 7313e1b..a16c361 100644 --- a/lib/ui/grid/column.js +++ b/lib/ui/grid/column.js @@ -1,7 +1,7 @@ import { global } from "../../utility"; import { createElement } from "../../functions"; import { createIcon } from "../icon"; -import { createCheckbox } from "../checkbox"; +import { createCheckbox, createRadiobox } from "../checkbox"; // import { setTooltip } from "../tooltip"; import { Dropdown } from "../dropdown"; import { convertCssStyle } from "../extension"; @@ -66,8 +66,8 @@ export class GridColumn { * @param {Function} trigger - 编辑事件回调函数 * @param {any} trigger.e - 该参数会传递给 [getValue]{@linkcode GridColumn.getValue} 方法 * @param {GridColumnDefinition} col - 列定义对象 - * @param {HTMLElement} container - 父容器元素 - * @param {GridItemWrapper} wrapper - 行包装对象,其 `values` 属性为行数据对象 + * @param {HTMLElement} [container] - 父容器元素 + * @param {GridItemWrapper} [wrapper] - 行包装对象,其 `values` 属性为行数据对象 * @returns {HTMLElement} 返回创建的编辑状态的单元格元素 * @virtual */ @@ -351,6 +351,18 @@ export class GridDropdownColumn extends GridColumn { return drop.create(); } + /** + * @ignore + * @param {HTMLElement} element + * @returns {HTMLElement} + */ + static getElement(element) { + if (element.tagName === 'DIV') { + return element.children[0].children[0]; + } + return element; + } + /** * @private * @param {HTMLElement} element @@ -543,7 +555,8 @@ export class GridCheckboxColumn extends GridColumn { * @param {boolean} val */ static setValue(element, val) { - element.querySelector('input').checked = val; + // element.querySelector('input').checked = val; + element.children[0].checked = val; } /** @@ -573,7 +586,8 @@ export class GridCheckboxColumn extends GridColumn { */ static setEnabled(element, enabled) { super.setEnabled(element, enabled); - element.querySelector('input').disabled = enabled === false; + // element.querySelector('input').disabled = enabled === false; + element.children[0].disabled = enabled === false; } /** @@ -582,6 +596,36 @@ export class GridCheckboxColumn extends GridColumn { static toString() { return 'GridCheckbox' } } +/** + * 单选框列 + * @class + * @static + * @extends GridCheckboxColumn + * @hideconstructor + * @ignore + */ +export class GridRadioboxColumn extends GridCheckboxColumn { + /** + * @ignore + * @param {Function} trigger + * @param {GridColumnDefinition} _col + * @param {number} index + * @returns {HTMLElement} + */ + static createEdit(trigger, _col, index) { + const check = createRadiobox({ + name: `r_${index}`, + onchange: trigger + }); + return check; + } + + /** + * @ignore + */ + static toString() { return 'GridRadiobox' } +} + /** * 图标列 * @class diff --git a/lib/ui/grid/grid.js b/lib/ui/grid/grid.js index 49ff044..3eea830 100644 --- a/lib/ui/grid/grid.js +++ b/lib/ui/grid/grid.js @@ -8,7 +8,7 @@ import { createCheckbox } from "../checkbox"; import { setTooltip } from "../tooltip"; import { Popup, showAlert } from "../popup"; import { convertCssStyle } from "../extension"; -import { GridColumn, GridInputColumn, GridTextColumn, GridDropdownColumn, GridCheckboxColumn, GridIconColumn, GridDateColumn } from "./column"; +import { GridColumn, GridInputColumn, GridTextColumn, GridDropdownColumn, GridCheckboxColumn, GridRadioboxColumn, GridIconColumn, GridDateColumn } from "./column"; /** * @author Tsanie Lily @@ -59,7 +59,8 @@ const ColumnTypeDefs = { 3: GridCheckboxColumn, 4: GridIconColumn, 5: GridTextColumn, - 6: GridDateColumn + 6: GridDateColumn, + 7: GridRadioboxColumn }; let r = lang; @@ -217,8 +218,10 @@ let r = lang; * * Grid.ColumnTypes.Icon - 4: 图标列 * * Grid.ColumnTypes.Text - 5: 多行文本列 * * Grid.ColumnTypes.Date - 6: 日期选择列 + * * Grid.ColumnTypes.Radio - 7: 单选框列 * @property {string} [caption] - 列标题文本 * @property {any} [captionStyle] - 列标题的元素样式 + * @property {string} [captionTooltip] - 列标题的帮助文本 * @property {number} [width] - 大于 0 则设置为该宽度,否则根据列内容自动调整列宽 * @property {("left" |"center" | "right")} [align=left] 列对齐方式 * @property {(boolean | string | GridItemBooleanCallback)} [enabled] - 列是否可用(可编辑),允许以下类型 @@ -389,10 +392,10 @@ let r = lang; */ /** - * 判断复选框列的回调函数 - * @callback ColumnTypesEnumIsCheckbox + * 判断列是否始终编辑的回调函数 + * @callback ColumnTypesEnumIsAlwaysEditing * @param {number} type - 列类型 - * @returns {boolean} 返回是否为复选框列 + * @returns {boolean} 返回是否始终编辑 */ /** @@ -414,11 +417,13 @@ const GridColumnTypeEnum = { Text: 5, /** 6 - 日期选择列 */ Date: 6, + /** 7 - 单选框列 */ + Radio: 7, /** * 判断列是否为复选框列 - * @type {ColumnTypesEnumIsCheckbox} + * @type {ColumnTypesEnumIsAlwaysEditing} */ - isCheckbox(type) { return type === 3 } + isAlwaysEditing(type) { return type === 3 || type === 7 } }; /** @@ -1039,6 +1044,7 @@ export class Grid { * @property {number} Icon=4 - 图标列 * @property {number} Text=5 - 多行文本列 * @property {number} Date=6 - 日期选择列 + * @property {number} Radio=7 - 单选框列 */ static get ColumnTypes() { return GridColumnTypeEnum } @@ -2264,7 +2270,7 @@ export class Grid { continue; } // style - const isCheckbox = GridColumnTypeEnum.isCheckbox(col.type); + const alwaysEditing = GridColumnTypeEnum.isAlwaysEditing(col.type); let type = this._var.colTypes[col.key]; if (type == null) { if (isNaN(col.type)) { @@ -2285,7 +2291,7 @@ export class Grid { this._var.needResize = true; sizer.innerText = col.caption ?? ''; let width = sizer.offsetWidth + 22; - if (!readonly && col.enabled !== false && col.allcheck && isCheckbox) { + if (!readonly && col.enabled !== false && col.allcheck && alwaysEditing) { width += 32; } if (col.allowFilter === true) { @@ -2296,7 +2302,7 @@ export class Grid { } col.width = width; } - col.align ??= isCheckbox ? 'center' : 'left'; + col.align ??= alwaysEditing ? 'center' : 'left'; if (col.sortable !== false) { col.sortable = true; } @@ -2338,7 +2344,7 @@ export class Grid { wrapper.style.justifyContent = 'center'; } th.appendChild(wrapper); - if (!readonly && col.enabled !== false && col.allcheck && isCheckbox) { + if (!readonly && col.enabled !== false && col.allcheck && alwaysEditing) { const check = createCheckbox({ onchange: e => this._onColumnAllChecked(col, e.target.checked) }); @@ -2360,6 +2366,11 @@ export class Grid { } wrapper.appendChild(caption); } + if (col.captionTooltip != null) { + const help = createIcon('fa-solid', 'question-circle'); + wrapper.appendChild(help); + setTooltip(help, col.captionTooltip, false, this._var.parent); + } // order arrow if (col.sortable) { th.appendChild(createElement('layer', 'arrow')); @@ -2539,21 +2550,20 @@ export class Grid { if (style !== '') { cell.style.cssText = style; } - let element; - if (!readonly && GridColumnTypeEnum.isCheckbox(col.type)) { - element = GridCheckboxColumn.createEdit(e => this._onRowChanged(e, exists + i, col, e.target.checked, cell)); - // this._var.colTypes[col.key] = GridCheckboxColumn; - } else { - let type = this._var.colTypes[col.key]; - if (type == null) { - if (isNaN(col.type)) { - type = col.type; - } else { - type = ColumnTypeDefs[col.type]; - } - type ??= GridColumn; - this._var.colTypes[col.key] = type; + let type = this._var.colTypes[col.key]; + if (type == null) { + if (isNaN(col.type)) { + type = col.type; + } else { + type = ColumnTypeDefs[col.type]; } + type ??= GridColumn; + this._var.colTypes[col.key] = type; + } + let element; + if (!readonly && GridColumnTypeEnum.isAlwaysEditing(col.type)) { + element = type.createEdit(e => this._onRowChanged(e, exists + i, col, e.target.checked, cell), col, exists + i); + } else { element = type.create(col, i, this); if (typeof col.class === 'string') { type.setClass(element, col.class); @@ -2704,10 +2714,10 @@ export class Grid { virtualCell.background = bg; cell.style.backgroundColor = bg; } - const isCheckbox = GridColumnTypeEnum.isCheckbox(col.type); - const type = isCheckbox ? GridCheckboxColumn : this._var.colTypes[col.key] ?? GridColumn; + const alwaysEditing = GridColumnTypeEnum.isAlwaysEditing(col.type); + const type = this._var.colTypes[col.key] ?? GridColumn; let element; - if (!readonly && !isCheckbox && typeof type.createEdit === 'function') { + if (!readonly && !alwaysEditing && typeof type.createEdit === 'function') { const oldValue = vals.__editing?.[col.key]; if (oldValue !== undefined) { delete vals.__editing[col.key]; @@ -2759,7 +2769,7 @@ export class Grid { delete virtualCell.enabled; } if (typeof type.setEditing === 'function') { - type.setEditing(element, virtualRow.editing); + type.setEditing(element, selected); } } if (val !== virtualCell.value) { @@ -2813,12 +2823,16 @@ export class Grid { } else if (typeof col.styleFilter === 'function') { style = col.styleFilter(item); } + const separateElement = typeof type.getElement === 'function'; + let maxHeight; if (col.maxLines > 0) { - const maxHeight = `${col.maxLines * this.lineHeight}px`; - if (style == null) { - style = { 'max-height': maxHeight }; - } else { - style['max-height'] = maxHeight; + maxHeight = `${col.maxLines * this.lineHeight}px`; + if (!separateElement) { + if (style == null) { + style = { 'max-height': maxHeight }; + } else { + style['max-height'] = maxHeight; + } } } const styleText = style != null ? convertCssStyle(style) : ''; @@ -2830,6 +2844,12 @@ export class Grid { element.style.cssText = ''; } } + if (separateElement && maxHeight != null) { + const e = type.getElement(element); + if (e != null) { + e.style['max-height'] = maxHeight; + } + } if (col.attrs != null) { let attrs = col.attrs; if (typeof attrs === 'function') { @@ -3442,7 +3462,7 @@ export class Grid { if (typeof col.onFilterOk === 'function') { col.onFilterOk.call(this, col, array); } else { - if (GridColumnTypeEnum.isCheckbox(col.type)) { + if (GridColumnTypeEnum.isAlwaysEditing(col.type)) { col.filterValues = array.map(a => a.Value); } else { const nullValue = col.filterAllowNull ? null : ''; @@ -3501,7 +3521,7 @@ 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'; + const propKey = GridColumnTypeEnum.isAlwaysEditing(col.type) ? 'Value' : 'DisplayValue'; const nullValue = col.filterAllowNull ? null : ''; const allSelected = !Array.isArray(col.filterValues); for (let item of array) { @@ -4021,8 +4041,7 @@ export class Grid { if (cell == null) { return; } - const type = GridColumnTypeEnum.isCheckbox(c.type) ? - GridCheckboxColumn : this._var.colTypes[c.key] ?? GridColumn; + const type = this._var.colTypes[c.key] ?? GridColumn; if (typeof type.setEnabled === 'function') { if (typeof c.enabled === 'function') { enabled = c.enabled(item);