This commit is contained in:
2024-08-30 17:36:21 +08:00
parent a3f0288c92
commit eec9d6045c
19 changed files with 332 additions and 219 deletions

View File

@ -3,6 +3,10 @@ import { createElement } from "../functions";
import { createIcon } from "./icon";
function fillCheckbox(container, type = 'fa-regular', label, tabindex = -1, charactor = 'check', title) {
const checkIcon = createIcon(type, charactor);
checkIcon.classList.add('ui-check-icon');
const indeterminateIcon = createIcon(type, 'grip-lines');
indeterminateIcon.classList.add('ui-indeterminate-icon')
container.appendChild(
createElement('layer', layer => {
layer.className = 'ui-check-inner';
@ -18,7 +22,7 @@ function fillCheckbox(container, type = 'fa-regular', label, tabindex = -1, char
if (tabindex >= 0) {
layer.tabIndex = tabindex;
}
}, createIcon(type, charactor))
}, checkIcon, indeterminateIcon)
);
if (label instanceof Element) {
container.appendChild(label);
@ -68,6 +72,9 @@ export function createCheckbox(opts = {}) {
if (opts.checked === true) {
input.checked = true;
}
if (opts.indeterminate === true) {
input.indeterminate = true;
}
if (opts.enabled === false) {
input.disabled = true;
}

View File

@ -185,9 +185,20 @@ $listMaxHeight: 210px;
background-color: var(--hover-bg-color);
}
>.ui-check-wrapper {
height: $dropItemHeight;
>.li-wrapper {
display: flex;
align-items: center;
>.ui-expandor {
width: 12px;
height: 12px;
display: flex;
}
>.ui-check-wrapper {
height: $dropItemHeight;
display: flex;
}
}
}
}

View File

@ -92,7 +92,22 @@
border-color: var(--link-color);
background-color: var(--link-color);
>svg {
>.ui-check-icon {
transform: scale(1);
opacity: 1;
}
}
&:indeterminate+.ui-check-inner {
border-color: var(--secondary-color);
background-color: var(--secondary-color);
>.ui-check-icon {
transform: scale(0);
opacity: 0;
}
>.ui-indeterminate-icon {
transform: scale(1);
opacity: 1;
}

View File

@ -178,6 +178,7 @@ export function getFormatter(date, utc) {
* @param {Date | number | string} date - 需要格式化的日期值,支持的格式如下:
*
* * `"2024-01-26"`
* * `"2024/1/26"`
* * `"2024-01-26T00:00:00"`
* * `"1/26/2024"`
* * `"638418240000000000"`
@ -214,7 +215,7 @@ export function formatDate(date, formatter) {
if (isNaN(date)) {
let e = /^(\d{4})-(\d{2})-(\d{2})/.exec(date);
if (e == null) {
e = /^(\d{4})\/(\d{2})\/(\d{2})/.exec(date);
e = /^(\d{4})\/(\d{1,2})\/(\d{1,2})/.exec(date);
}
if (e != null) {
date = new Date(e[1], parseInt(e[2]) - 1, e[3]);

View File

@ -302,7 +302,14 @@ export class Dropdown {
if (!Array.isArray(list)) {
return;
}
this._var.source = list;
const valuekey = this._var.options.valueKey;
function reduceItems(list, id, level = 0) {
if (!Array.isArray(list)) {
return [];
}
return list.reduce((array, item) => [...array, { __p: id, __level: level, ...item }, ...reduceItems(item.children, item[valuekey], level + 1)], []);
}
this._var.source = reduceItems(list);
if (this._expanded) {
setTimeout(() => this._dropdown(), 120);
}
@ -422,6 +429,7 @@ export class Dropdown {
const search = createElement('div', 'ui-drop-search');
const input = createElement('input');
input.type = 'text';
input.className = 'ui-input';
isPositive(options.tabIndex) && input.setAttribute('tabindex', options.tabIndex);
!nullOrEmpty(options.searchPlaceholder) && input.setAttribute('placeholder', options.searchPlaceholder);
input.addEventListener('input', e => {
@ -579,7 +587,14 @@ export class Dropdown {
}
if (multiselect) {
const selected = selectedlist.some(s => String(getValue(s, valuekey, textkey)) === val);
item.__checked = allchecked || selected;
if (allchecked || selected) {
item.__checked = 1;
} else {
const indeterminate = selectedlist.some(s => this._contains(String(getValue(s, valuekey, textkey)), item, valuekey, textkey));
if (indeterminate) {
item.__checked = 2;
}
}
}
});
if (source.length > 20) {
@ -592,6 +607,20 @@ export class Dropdown {
}
}
_contains(it, item, valuekey, textkey) {
if (item.children?.length > 0) {
for (let t of item.children) {
if (it === getValue(t, valuekey, textkey)) {
return true;
}
if (this._contains(it, t, valuekey, textkey)) {
return true;
}
}
}
return false;
}
_dofilllist(content, array) {
const multiselect = this.multiSelect;
const valuekey = this._var.options.valueKey;
@ -608,6 +637,18 @@ export class Dropdown {
const li = createElement('li');
li.dataset.value = val;
li.title = item[textkey];
if (item.__level > 0) {
li.style.marginLeft = `${item.__level * 24}px`;
}
const wrapper = createElement('span', 'li-wrapper',
createElement('span', span => {
// events
span.className = 'ui-expandor';
},
createIcon('fa-light', 'caret-down')
)
);
li.appendChild(wrapper);
let label;
let html;
if (typeof template === 'function') {
@ -628,20 +669,21 @@ export class Dropdown {
}
const box = createCheckbox({
label,
checked: item.__checked,
checked: item.__checked === 1,
indeterminate: item.__checked === 2,
customAttributes: {
'class': 'dataitem',
'data-value': val
},
onchange: e => this._triggerselect(e.target, item)
});
li.appendChild(box);
wrapper.appendChild(box);
} else {
if (label == null) {
li.innerText = item[textkey];
} else {
li.appendChild(label);
label = createElement('span');
label.innerHTML = item[textkey];
}
wrapper.appendChild(label);
if (selected != null && String(selected[valuekey]) === val) {
scrolled = DropdownItemHeight * i;
li.classList.add('selected');
@ -664,7 +706,7 @@ export class Dropdown {
boxes.forEach(box => box.checked = allchecked);
list = [];
} else {
item.__checked = checkbox.checked;
item.__checked = checkbox.indeterminate ? 2 : checkbox.checked ? 1 : 0;
const all = this._var.container.querySelector('input[isall="1"]');
if (checkbox.checked) {
const source = this.source;

View File

@ -1431,12 +1431,21 @@ export class Grid {
e.stopPropagation();
}
});
grid.addEventListener('mousedown', e => {
grid.addEventListener('mousedown', async e => {
if (e.target === this._var.el) {
if (e.offsetX < 0 || e.offsetX > e.target.clientWidth || e.offsetY < 0 || e.offsetY > e.target.clientHeight) {
// except scroll bars
return;
}
if (typeof this.willSelect === 'function') {
let result = this.willSelect(-1, -1);
if (result instanceof Promise) {
result = await result;
}
if (!result) {
return;
}
}
// cancel selections
const selectedIndexes = this._var.selectedIndexes;
if (selectedIndexes?.length > 0) {
@ -1525,7 +1534,7 @@ export class Grid {
holder.classList.remove('active');
this._clearHolder(holder);
}
return this._onRowClicked(e, row, col);
this._onRowClicked(e, row, col);
});
holder.addEventListener('dblclick', e => this._onRowDblClicked(e));
wrapper.appendChild(holder);
@ -2107,6 +2116,7 @@ export class Grid {
// FIXME: 清除缓存会导致选中状态下动态数据源下拉列表显示为空
// delete it.source;
it.values = item;
this._var.colAttrs.__filtered = false;
if (this.sortArray?.length > 0) {
this.sort();
} else if (this.sortIndex >= 0) {
@ -2148,6 +2158,7 @@ export class Grid {
this._var.source.push(newIt);
}
}
this._var.colAttrs.__filtered = false;
if (this.sortArray?.length > 0) {
this.sort(true);
} else if (this.sortIndex >= 0) {
@ -2195,6 +2206,7 @@ export class Grid {
this._var.source.push(...items);
}
}
this._var.colAttrs.__filtered = false;
if (this.sortArray?.length > 0) {
this.sort(true);
} else if (this.sortIndex >= 0) {
@ -3926,6 +3938,8 @@ export class Grid {
return String(displayValue).toLowerCase().includes(key);
});
this._fillFilterList(col, itemlist, items, itemall);
this._set(col.key, 'filterTop', -1);
itemlist.dispatchEvent(new Event('scroll'));
});
}
// function
@ -4405,12 +4419,9 @@ export class Grid {
* @param {number} index
* @param {number} colIndex
*/
_onRowClicked(e, index, colIndex) {
_afterRowChanged(e, index, colIndex) {
const startIndex = this._var.startIndex;
const selectedIndex = startIndex + index;
if (typeof this.willSelect === 'function' && !this.willSelect(selectedIndex, colIndex)) {
return;
}
// multi-select
let flag = false;
const selectedIndexes = this._var.selectedIndexes;
@ -4471,6 +4482,26 @@ export class Grid {
}
}
/**
* @private
* @param {MouseEvent} e
* @param {number} index
* @param {number} colIndex
*/
async _onRowClicked(e, index, colIndex) {
if (typeof this.willSelect === 'function') {
const selectedIndex = this._var.startIndex + index;
let result = this.willSelect(selectedIndex, colIndex);
if (result instanceof Promise) {
result = await result;
}
if (!result) {
return;
}
}
this._afterRowChanged(e, index, colIndex);
}
/**
* @private
* @param {MouseEvent} e