fixed: column drag issue.

optimized: documentation.
This commit is contained in:
2024-01-26 14:09:52 +08:00
parent 0b9b322b80
commit 984496e08e
5 changed files with 313 additions and 78 deletions

View File

@ -17,7 +17,7 @@ const ColumnChangedType = {
const RefreshInterval = isMobile() ? 32 : 0;
const HoverInternal = 200;
const RedumCount = 4;
const MiniDragOffset = 4;
const MiniDragOffset = 10;
const MiniColumnWidth = 50;
const FilterPanelWidth = 200;
@ -29,15 +29,6 @@ function getClientX(e) {
return cx ?? e.clientX;
}
function getOffsetLeftFromWindow(element) {
let left = 0;
while (element != null) {
left += element.offsetLeft;
element = element.offsetParent;
}
return left;
}
function indexOfParent(target) {
// return [...target.parentElement.children].indexOf(target);
return Array.prototype.indexOf.call(target.parentElement.children, target);
@ -127,7 +118,8 @@ export class Grid {
this.langs = {
all: r('allItem', '( All )'),
ok: r('ok', 'OK'),
reset: r('reset', 'Reset')
reset: r('reset', 'Reset'),
null: r('null', '( Null )')
};
}
@ -190,7 +182,7 @@ export class Grid {
this._var.currentSource = list.filter(it => {
for (let col of this.columns) {
if (Array.isArray(col.filterValues)) {
const v = this._getItemValue(it.values, col.key, col.filter);
const v = this._getItemProp(it.values, false, col);
if (col.filterValues.indexOf(v) < 0) {
return false;
}
@ -485,8 +477,8 @@ export class Grid {
direction = 1;
}
comparer = (a, b) => {
a = this._getItemValue(a.values, col.key, col.filter);
b = this._getItemValue(b.values, col.key, col.filter);
a = this._getItemProp(a.values, true, col);
b = this._getItemProp(b.values, true, col);
if (a == null && typeof b === 'number') {
a = 0;
} else if (typeof a === 'number' && b == null) {
@ -533,7 +525,7 @@ export class Grid {
let left = 0;
for (let col of this.columns) {
if (col.visible === false) {
const hidden = createElement('th');
const hidden = createElement('th', 'column');
hidden.style.display = 'none';
if (col.sortable !== false) {
hidden.dataset.key = col.key;
@ -544,7 +536,17 @@ export class Grid {
}
// style
const isCheckbox = Grid.ColumnTypes.isCheckbox(col.type);
if (col.width > 0) {
let type = this._var.colTypes[col.key];
if (type == null) {
if (isNaN(col.type)) {
type = col.type;
} else {
type = ColumnTypes[col.type];
}
type ??= GridColumn;
this._var.colTypes[col.key] = type;
}
if (col.width > 0 || typeof type.createCaption === 'function') {
// col.autoResize = false;
} else {
this._set(col.key, 'autoResize', true);
@ -600,12 +602,19 @@ export class Grid {
});
wrapper.appendChild(check);
}
const caption = createElement('span');
if (col.captionStyle != null) {
caption.style.cssText = convertCssStyle(col.captionStyle);
let caption;
if (typeof type.createCaption === 'function') {
caption = type.createCaption(col);
} else {
caption = createElement('span');
caption.innerText = col.caption ?? '';
}
if (caption instanceof HTMLElement) {
if (col.captionStyle != null) {
caption.style.cssText = convertCssStyle(col.captionStyle);
}
wrapper.appendChild(caption);
}
caption.innerText = col.caption ?? '';
wrapper.appendChild(caption);
// order arrow
if (col.sortable) {
th.appendChild(createElement('layer', 'arrow'));
@ -906,13 +915,15 @@ export class Grid {
}
}
_changingColumnOrder(index, offset, x, offsetLeft, scrollLeft) {
_changingColumnOrder(index, offset, mouse, draggerCellLeft) {
const children = this._var.refs.header.children;
let element = children[index];
this._var.refs.dragger.style.cssText = `left: ${element.offsetLeft - offsetLeft + offset}px; width: ${element.style.width}; display: block`;
offset = x + scrollLeft - element.offsetLeft; // getOffsetLeftFromWindow(element);
this._var.refs.dragger.style.cssText = `left: ${element.offsetLeft - draggerCellLeft + offset}px; width: ${element.style.width}; display: block`;
// offset = x + gridScrollLeft - element.offsetLeft; // getOffsetLeftFromWindow(element);
offset += mouse;
let idx;
if (offset < 0) {
const toLeft = offset < 0;
if (toLeft) {
offset = -offset;
for (let i = index - 1; i >= 0 && offset >= 0; i -= 1) {
element = children[i];
@ -943,13 +954,27 @@ export class Grid {
}
idx ??= count - 1;
}
if (idx !== this._var.colAttrs.__orderIndex) {
this._var.colAttrs.__orderIndex = idx;
if (idx !== this._var.colAttrs.__orderIndex || this._var.refs.draggerCursor.style.display !== 'block') {
element = children[idx];
if (element == null) {
return;
}
this._var.refs.draggerCursor.style.cssText = `left: ${element.offsetLeft - offsetLeft}px; display: block`;
this._var.colAttrs.__orderIndex = idx;
// avoid `offsetLeft` of hidden header to be 0
let left;
if (element.style.display === 'none') {
left = 0;
while (left === 0 && (element = children[++idx]) != null) {
left = element.offsetLeft;
}
if (!toLeft && left === 0) {
left = draggerCellLeft;
}
} else {
left = element.offsetLeft;
}
// set position of dragger cursor
this._var.refs.draggerCursor.style.cssText = `left: ${left - draggerCellLeft}px; display: block`;
}
}
@ -1057,14 +1082,21 @@ export class Grid {
}
}
_getItemValue(item, key, filter) {
_getItemProp(item, editing, col) {
let value;
if (typeof filter === 'function') {
value = filter(item, false, this._var.refs.body);
if (typeof col?.filter === 'function') {
value = col.filter(item, editing, this._var.refs.body);
} else {
value = item[key];
value = item[col.key];
}
return value?.Value ?? value;
if (value == null) {
return value;
}
const prop = editing ? 'Value' : 'DisplayValue';
if (Object.prototype.hasOwnProperty.call(value, prop)) {
return value[prop];
}
return value;
}
_getRowTarget(target) {
@ -1174,19 +1206,35 @@ export class Grid {
} else {
const dict = Object.create(null);
for (let item of this._var.source) {
const val = this._getItemValue(item.values, col.key, col.filter);
if (!Object.hasOwnProperty.call(dict, val)) {
const v = item.values[col.key];
dict[val] = {
let displayValue = this._getItemProp(item.values, false, col);
if (displayValue == null) {
displayValue = this.langs.null;
}
if (!Object.hasOwnProperty.call(dict, displayValue)) {
const val = this._getItemProp(item.values, true, col);
dict[displayValue] = {
Value: val,
DisplayValue: typeof col.filter === 'function' ? col.filter(item.values) : v?.DisplayValue ?? v
DisplayValue: displayValue
};
}
}
array = Object.values(dict)
.sort((a, b) => {
a = a?.Value ?? a;
b = b?.Value ?? b;
if (a == null && b == null) {
return 0;
}
if (a == null && b != null) {
return -1;
}
if (a != null && b == null) {
return 1;
}
if (Object.prototype.hasOwnProperty.call(a, 'Value')) {
a = a.Value;
}
if (Object.prototype.hasOwnProperty.call(b, 'Value')) {
b = b.Value;
}
return a > b ? 1 : a < b ? -1 : 0;
});
}
@ -1197,7 +1245,7 @@ export class Grid {
}
return {
Value: i,
DisplayValue: i == null ? '' : i
DisplayValue: i == null ? this.langs.null : i
};
});
this._fillFilterList(col, itemlist, array, itemall);
@ -1207,8 +1255,16 @@ export class Grid {
searchbox.addEventListener('input', e => {
const key = e.currentTarget.value.toLowerCase();
const items = key.length === 0 ? array : array.filter(i => {
const displayValue = i?.DisplayValue ?? i;
return String(displayValue ?? '').toLowerCase().includes(key);
let displayValue;
if (i != null && Object.prototype.hasOwnProperty.call(i, 'DisplayValue')) {
displayValue = i.DisplayValue;
} else {
displayValue = i;
}
if (displayValue == null) {
displayValue = this.langs.null;
}
return String(displayValue).toLowerCase().includes(key);
});
this._fillFilterList(col, itemlist, items, itemall);
});
@ -1223,7 +1279,7 @@ export class Grid {
if (typeof col.onFilterOk === 'function') {
col.onFilterOk.call(this, col, array);
} else {
col.filterValues = array.map(a => a.Value);
col.filterValues = array.map(a => a.DisplayValue);
}
this._var.colAttrs.__filtered = true;
this._refreshSource();
@ -1268,7 +1324,8 @@ export class Grid {
content.style.top = `${rowHeight}px`;
this._set(col.key, 'filterSource', array);
for (let item of array) {
item.__checked = !Array.isArray(col.filterValues) || col.filterValues.includes(item.Value ?? item);
const v = Object.prototype.hasOwnProperty.call(item, 'DisplayValue') ? item.DisplayValue : item;
item.__checked = !Array.isArray(col.filterValues) || col.filterValues.includes(v);
}
if (array.length > 12) {
array = array.slice(0, 12);
@ -1282,7 +1339,7 @@ export class Grid {
const div = createElement('div', 'filter-item');
div.appendChild(createCheckbox({
checked: item.__checked,
label: item?.DisplayValue ?? item,
label: Object.prototype.hasOwnProperty.call(item, 'DisplayValue') ? item.DisplayValue : item,
onchange: e => {
item.__checked = e.target.checked;
all.querySelector('input').checked = ![...content.querySelectorAll('input')].some(i => !i.checked);
@ -1333,7 +1390,7 @@ export class Grid {
const cx = getClientX(e);
const clearEvents = attr => {
for (let event of ['mousemove', 'mouseup']) {
if (attr.hasOwnProperty(event)) {
if (Object.prototype.hasOwnProperty.call(attr, event)) {
window.removeEventListener(event, attr[event]);
delete attr[event];
}
@ -1346,20 +1403,28 @@ export class Grid {
clearEvents(attr);
}
attr.dragging = true;
const offsetLeft = this._var.refs.header.querySelector('th:last-child').offsetLeft;
const scrollLeft = this._var.el.scrollLeft;
const draggerCellLeft = this._var.refs.header.querySelector('th:last-child').offsetLeft;
// const gridScrollLeft = this._var.el.scrollLeft;
let p = this._var.el;
let gridLeftFromWindow = p.offsetLeft;
while ((p = p.offsetParent) != null) {
gridLeftFromWindow += p.offsetLeft + p.clientLeft;
}
const mouse = cx - e.currentTarget.offsetLeft + this._var.el.scrollLeft - gridLeftFromWindow;
const dragmove = e => {
const cx2 = getClientX(e);
const offset = cx2 - cx;
let pos = attr.offset;
let dragging;
if (pos == null && (offset > MiniDragOffset || offset < -MiniDragOffset)) {
dragging = true;
if (pos == null) {
if (offset > MiniDragOffset || offset < -MiniDragOffset) {
dragging = true;
}
} else if (pos !== offset) {
dragging = true;
}
if (dragging) {
this._changingColumnOrder(index, offset, cx2, offsetLeft, scrollLeft);
this._changingColumnOrder(index, offset, mouse, draggerCellLeft);
attr.offset = offset;
}
};
@ -1386,7 +1451,7 @@ export class Grid {
const window = this.window ?? global;
const clearEvents = attr => {
for (let event of ['mousemove', 'mouseup']) {
if (attr.hasOwnProperty(event)) {
if (Object.prototype.hasOwnProperty.call(attr, event)) {
window.removeEventListener(event, attr[event]);
delete attr[event];
}
@ -1648,7 +1713,7 @@ export class Grid {
if (enabled !== false) {
const val = item[col.key];
let oldValue;
if (val?.Value != null) {
if (val != null && Object.prototype.hasOwnProperty.call(val, 'Value') != null) {
oldValue = val.Value;
val.Value = value;
} else {