feature: caption help text

fix: editing style when turning column content wrap to `true`
This commit is contained in:
Chen Lily 2024-03-08 10:51:06 +08:00
parent 3ea7ce62bb
commit 39378e9963
3 changed files with 115 additions and 43 deletions

View File

@ -125,6 +125,14 @@
>.ui-check-wrapper { >.ui-check-wrapper {
height: 20px; height: 20px;
} }
>svg {
width: 14px;
min-width: 14px;
height: 14px;
margin-left: 4px;
fill: var(--split-border-color);
}
} }
>.arrow { >.arrow {
@ -367,6 +375,7 @@
box-sizing: border-box; box-sizing: border-box;
width: 100%; width: 100%;
padding: 0; padding: 0;
max-height: none !important;
@include outline(); @include outline();

View File

@ -1,7 +1,7 @@
import { global } from "../../utility"; import { global } from "../../utility";
import { createElement } from "../../functions"; import { createElement } from "../../functions";
import { createIcon } from "../icon"; import { createIcon } from "../icon";
import { createCheckbox } from "../checkbox"; import { createCheckbox, createRadiobox } from "../checkbox";
// import { setTooltip } from "../tooltip"; // import { setTooltip } from "../tooltip";
import { Dropdown } from "../dropdown"; import { Dropdown } from "../dropdown";
import { convertCssStyle } from "../extension"; import { convertCssStyle } from "../extension";
@ -66,8 +66,8 @@ export class GridColumn {
* @param {Function} trigger - 编辑事件回调函数 * @param {Function} trigger - 编辑事件回调函数
* @param {any} trigger.e - 该参数会传递给 [getValue]{@linkcode GridColumn.getValue} 方法 * @param {any} trigger.e - 该参数会传递给 [getValue]{@linkcode GridColumn.getValue} 方法
* @param {GridColumnDefinition} col - 列定义对象 * @param {GridColumnDefinition} col - 列定义对象
* @param {HTMLElement} container - 父容器元素 * @param {HTMLElement} [container] - 父容器元素
* @param {GridItemWrapper} wrapper - 行包装对象 `values` 属性为行数据对象 * @param {GridItemWrapper} [wrapper] - 行包装对象 `values` 属性为行数据对象
* @returns {HTMLElement} 返回创建的编辑状态的单元格元素 * @returns {HTMLElement} 返回创建的编辑状态的单元格元素
* @virtual * @virtual
*/ */
@ -351,6 +351,18 @@ export class GridDropdownColumn extends GridColumn {
return drop.create(); 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 * @private
* @param {HTMLElement} element * @param {HTMLElement} element
@ -543,7 +555,8 @@ export class GridCheckboxColumn extends GridColumn {
* @param {boolean} val * @param {boolean} val
*/ */
static setValue(element, 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) { static setEnabled(element, enabled) {
super.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' } 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 * @class

View File

@ -8,7 +8,7 @@ import { createCheckbox } from "../checkbox";
import { setTooltip } from "../tooltip"; import { setTooltip } from "../tooltip";
import { Popup, showAlert } from "../popup"; import { Popup, showAlert } from "../popup";
import { convertCssStyle } from "../extension"; 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 <tsorgy@gmail.com> * @author Tsanie Lily <tsorgy@gmail.com>
@ -59,7 +59,8 @@ const ColumnTypeDefs = {
3: GridCheckboxColumn, 3: GridCheckboxColumn,
4: GridIconColumn, 4: GridIconColumn,
5: GridTextColumn, 5: GridTextColumn,
6: GridDateColumn 6: GridDateColumn,
7: GridRadioboxColumn
}; };
let r = lang; let r = lang;
@ -217,8 +218,10 @@ let r = lang;
* * Grid.ColumnTypes.Icon - 4: 图标列 * * Grid.ColumnTypes.Icon - 4: 图标列
* * Grid.ColumnTypes.Text - 5: 多行文本列 * * Grid.ColumnTypes.Text - 5: 多行文本列
* * Grid.ColumnTypes.Date - 6: 日期选择列 * * Grid.ColumnTypes.Date - 6: 日期选择列
* * Grid.ColumnTypes.Radio - 7: 单选框列
* @property {string} [caption] - 列标题文本 * @property {string} [caption] - 列标题文本
* @property {any} [captionStyle] - 列标题的元素样式 * @property {any} [captionStyle] - 列标题的元素样式
* @property {string} [captionTooltip] - 列标题的帮助文本
* @property {number} [width] - 大于 0 则设置为该宽度否则根据列内容自动调整列宽 * @property {number} [width] - 大于 0 则设置为该宽度否则根据列内容自动调整列宽
* @property {("left" |"center" | "right")} [align=left] 列对齐方式 * @property {("left" |"center" | "right")} [align=left] 列对齐方式
* @property {(boolean | string | GridItemBooleanCallback)} [enabled] - 列是否可用可编辑允许以下类型 * @property {(boolean | string | GridItemBooleanCallback)} [enabled] - 列是否可用可编辑允许以下类型
@ -389,10 +392,10 @@ let r = lang;
*/ */
/** /**
* 判断复选框列的回调函数 * 判断是否始终编辑的回调函数
* @callback ColumnTypesEnumIsCheckbox * @callback ColumnTypesEnumIsAlwaysEditing
* @param {number} type - 列类型 * @param {number} type - 列类型
* @returns {boolean} 返回是否为复选框列 * @returns {boolean} 返回是否始终编辑
*/ */
/** /**
@ -414,11 +417,13 @@ const GridColumnTypeEnum = {
Text: 5, Text: 5,
/** 6 - 日期选择列 */ /** 6 - 日期选择列 */
Date: 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} Icon=4 - 图标列
* @property {number} Text=5 - 多行文本列 * @property {number} Text=5 - 多行文本列
* @property {number} Date=6 - 日期选择列 * @property {number} Date=6 - 日期选择列
* @property {number} Radio=7 - 单选框列
*/ */
static get ColumnTypes() { return GridColumnTypeEnum } static get ColumnTypes() { return GridColumnTypeEnum }
@ -2264,7 +2270,7 @@ export class Grid {
continue; continue;
} }
// style // style
const isCheckbox = GridColumnTypeEnum.isCheckbox(col.type); const alwaysEditing = GridColumnTypeEnum.isAlwaysEditing(col.type);
let type = this._var.colTypes[col.key]; let type = this._var.colTypes[col.key];
if (type == null) { if (type == null) {
if (isNaN(col.type)) { if (isNaN(col.type)) {
@ -2285,7 +2291,7 @@ export class Grid {
this._var.needResize = true; this._var.needResize = true;
sizer.innerText = col.caption ?? ''; sizer.innerText = col.caption ?? '';
let width = sizer.offsetWidth + 22; let width = sizer.offsetWidth + 22;
if (!readonly && col.enabled !== false && col.allcheck && isCheckbox) { if (!readonly && col.enabled !== false && col.allcheck && alwaysEditing) {
width += 32; width += 32;
} }
if (col.allowFilter === true) { if (col.allowFilter === true) {
@ -2296,7 +2302,7 @@ export class Grid {
} }
col.width = width; col.width = width;
} }
col.align ??= isCheckbox ? 'center' : 'left'; col.align ??= alwaysEditing ? 'center' : 'left';
if (col.sortable !== false) { if (col.sortable !== false) {
col.sortable = true; col.sortable = true;
} }
@ -2338,7 +2344,7 @@ export class Grid {
wrapper.style.justifyContent = 'center'; wrapper.style.justifyContent = 'center';
} }
th.appendChild(wrapper); th.appendChild(wrapper);
if (!readonly && col.enabled !== false && col.allcheck && isCheckbox) { if (!readonly && col.enabled !== false && col.allcheck && alwaysEditing) {
const check = createCheckbox({ const check = createCheckbox({
onchange: e => this._onColumnAllChecked(col, e.target.checked) onchange: e => this._onColumnAllChecked(col, e.target.checked)
}); });
@ -2360,6 +2366,11 @@ export class Grid {
} }
wrapper.appendChild(caption); 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 // order arrow
if (col.sortable) { if (col.sortable) {
th.appendChild(createElement('layer', 'arrow')); th.appendChild(createElement('layer', 'arrow'));
@ -2539,21 +2550,20 @@ export class Grid {
if (style !== '') { if (style !== '') {
cell.style.cssText = style; cell.style.cssText = style;
} }
let element; let type = this._var.colTypes[col.key];
if (!readonly && GridColumnTypeEnum.isCheckbox(col.type)) { if (type == null) {
element = GridCheckboxColumn.createEdit(e => this._onRowChanged(e, exists + i, col, e.target.checked, cell)); if (isNaN(col.type)) {
// this._var.colTypes[col.key] = GridCheckboxColumn; type = col.type;
} else { } else {
let type = this._var.colTypes[col.key]; type = ColumnTypeDefs[col.type];
if (type == null) {
if (isNaN(col.type)) {
type = col.type;
} else {
type = ColumnTypeDefs[col.type];
}
type ??= GridColumn;
this._var.colTypes[col.key] = 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); element = type.create(col, i, this);
if (typeof col.class === 'string') { if (typeof col.class === 'string') {
type.setClass(element, col.class); type.setClass(element, col.class);
@ -2704,10 +2714,10 @@ export class Grid {
virtualCell.background = bg; virtualCell.background = bg;
cell.style.backgroundColor = bg; cell.style.backgroundColor = bg;
} }
const isCheckbox = GridColumnTypeEnum.isCheckbox(col.type); const alwaysEditing = GridColumnTypeEnum.isAlwaysEditing(col.type);
const type = isCheckbox ? GridCheckboxColumn : this._var.colTypes[col.key] ?? GridColumn; const type = this._var.colTypes[col.key] ?? GridColumn;
let element; let element;
if (!readonly && !isCheckbox && typeof type.createEdit === 'function') { if (!readonly && !alwaysEditing && typeof type.createEdit === 'function') {
const oldValue = vals.__editing?.[col.key]; const oldValue = vals.__editing?.[col.key];
if (oldValue !== undefined) { if (oldValue !== undefined) {
delete vals.__editing[col.key]; delete vals.__editing[col.key];
@ -2759,7 +2769,7 @@ export class Grid {
delete virtualCell.enabled; delete virtualCell.enabled;
} }
if (typeof type.setEditing === 'function') { if (typeof type.setEditing === 'function') {
type.setEditing(element, virtualRow.editing); type.setEditing(element, selected);
} }
} }
if (val !== virtualCell.value) { if (val !== virtualCell.value) {
@ -2813,12 +2823,16 @@ export class Grid {
} else if (typeof col.styleFilter === 'function') { } else if (typeof col.styleFilter === 'function') {
style = col.styleFilter(item); style = col.styleFilter(item);
} }
const separateElement = typeof type.getElement === 'function';
let maxHeight;
if (col.maxLines > 0) { if (col.maxLines > 0) {
const maxHeight = `${col.maxLines * this.lineHeight}px`; maxHeight = `${col.maxLines * this.lineHeight}px`;
if (style == null) { if (!separateElement) {
style = { 'max-height': maxHeight }; if (style == null) {
} else { style = { 'max-height': maxHeight };
style['max-height'] = maxHeight; } else {
style['max-height'] = maxHeight;
}
} }
} }
const styleText = style != null ? convertCssStyle(style) : ''; const styleText = style != null ? convertCssStyle(style) : '';
@ -2830,6 +2844,12 @@ export class Grid {
element.style.cssText = ''; element.style.cssText = '';
} }
} }
if (separateElement && maxHeight != null) {
const e = type.getElement(element);
if (e != null) {
e.style['max-height'] = maxHeight;
}
}
if (col.attrs != null) { if (col.attrs != null) {
let attrs = col.attrs; let attrs = col.attrs;
if (typeof attrs === 'function') { if (typeof attrs === 'function') {
@ -3442,7 +3462,7 @@ export class Grid {
if (typeof col.onFilterOk === 'function') { if (typeof col.onFilterOk === 'function') {
col.onFilterOk.call(this, col, array); col.onFilterOk.call(this, col, array);
} else { } else {
if (GridColumnTypeEnum.isCheckbox(col.type)) { if (GridColumnTypeEnum.isAlwaysEditing(col.type)) {
col.filterValues = array.map(a => a.Value); col.filterValues = array.map(a => a.Value);
} else { } else {
const nullValue = col.filterAllowNull ? null : ''; const nullValue = col.filterAllowNull ? null : '';
@ -3501,7 +3521,7 @@ export class Grid {
const content = createElement('div', 'filter-content'); const content = createElement('div', 'filter-content');
content.style.top = `${rowHeight}px`; content.style.top = `${rowHeight}px`;
this._set(col.key, 'filterSource', array); 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 nullValue = col.filterAllowNull ? null : '';
const allSelected = !Array.isArray(col.filterValues); const allSelected = !Array.isArray(col.filterValues);
for (let item of array) { for (let item of array) {
@ -4021,8 +4041,7 @@ export class Grid {
if (cell == null) { if (cell == null) {
return; return;
} }
const type = GridColumnTypeEnum.isCheckbox(c.type) ? const type = this._var.colTypes[c.key] ?? GridColumn;
GridCheckboxColumn : this._var.colTypes[c.key] ?? GridColumn;
if (typeof type.setEnabled === 'function') { if (typeof type.setEnabled === 'function') {
if (typeof c.enabled === 'function') { if (typeof c.enabled === 'function') {
enabled = c.enabled(item); enabled = c.enabled(item);