@visactor/vtable
Version:
canvas table width high performance
288 lines (277 loc) • 22.2 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", {
value: !0
}), exports.MenuElement = exports.isMenuHighlight = void 0;
const EventHandler_1 = require("../../../../event/EventHandler"), dom_1 = require("../../../../tools/dom"), MenuElementStyle_1 = require("./MenuElementStyle"), TABLE_EVENT_TYPE_1 = require("../../../../core/TABLE_EVENT_TYPE"), helper_1 = require("../../../../tools/helper"), vutils_1 = require("@visactor/vutils"), global_1 = require("../../../../tools/global");
(0, MenuElementStyle_1.importStyle)();
const CLASSNAME = "vtable__menu-element", ITEM_CLASSNAME = `${CLASSNAME}__item`, CONTENT_CLASSNAME = `${CLASSNAME}__content`, HIDDEN_CLASSNAME = `${CLASSNAME}--hidden`, SHOWN_CLASSNAME = `${CLASSNAME}--shown`, NORAML_CLASSNAME = `${CLASSNAME}--normal`, SELECT_CLASSNAME = `${CLASSNAME}--select`, ICOM_CLASSNAME = `${CLASSNAME}__icon`, SPLIT_CLASSNAME = `${CLASSNAME}__split`, TITLE_CLASSNAME = `${CLASSNAME}__title`, ARROW_CLASSNAME = `${CLASSNAME}__arrow`, NOEVENT_CLASSNAME = `${CLASSNAME}__no-event`, ITEMTEXT_CLASSNAME = `${CLASSNAME}__item-text`;
function createMenuDomElement() {
return (0, dom_1.createElement)("div", [ CLASSNAME, HIDDEN_CLASSNAME ]);
}
function isMenuHighlight(_table, cells, menuKeyCurrent, colCurrent, rowCurrent, index) {
const cellRange = _table.getCellRange(colCurrent, rowCurrent);
for (let i = 0; i < cells.length; i++) {
const highlight = cells[i];
let {col: col, row: row} = highlight;
const {field: field, menuKey: menuKey} = highlight;
if ("number" != typeof col || "number" != typeof row) if (_table.isPivotTable() && (Array.isArray(field),
1)) {
const cellAddress = _table.internalProps.layoutMap.getPivotCellAdress(field);
if (!cellAddress) continue;
col = cellAddress.col, row = cellAddress.row;
} else {
const cellAddress = _table.internalProps.layoutMap.getHeaderCellAddressByField(field);
if (!cellAddress) continue;
col = cellAddress.col, row = cellAddress.row;
}
if ((0, vutils_1.isValid)(col) && (0, vutils_1.isValid)(row) && (0, helper_1.cellInRange)(cellRange, col, row) && menuKeyCurrent === menuKey) return !0;
}
return !1;
}
exports.isMenuHighlight = isMenuHighlight;
class MenuElement {
constructor(table) {
var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l;
this._handler = new EventHandler_1.EventHandler, this._rootElement = createMenuDomElement(),
this._secondElement = createMenuDomElement(), this._secondElement.sub = !0, this._showChildrenIndex = -1,
this._rootElement.addEventListener("wheel", (e => {
e.stopPropagation();
})), null === (_a = this._rootElement) || void 0 === _a || _a.addEventListener("mousedown", (e => {
e.stopPropagation(), e.preventDefault();
})), null === (_b = this._rootElement) || void 0 === _b || _b.addEventListener("contextmenu", (e => {
e.stopPropagation(), e.preventDefault();
})), null === (_c = this._rootElement) || void 0 === _c || _c.addEventListener("touchend", (e => {
if (e.stopPropagation(), e.preventDefault(), this._rootElement.classList.contains(HIDDEN_CLASSNAME)) return;
const {col: col, row: row, dropDownIndex: dropDownIndex, menuKey: menuKey, text: text, hasChildren: hasChildren} = e.target;
if ("number" != typeof dropDownIndex || hasChildren) return void e.stopPropagation();
const field = table.isPivotTable() ? table.internalProps.layoutMap.getPivotDimensionInfo(col, row) : table.getHeaderField(col, row), highlight = table._dropDownMenuIsHighlight(col, row, dropDownIndex);
table.fireListeners(TABLE_EVENT_TYPE_1.TABLE_EVENT_TYPE.DROPDOWN_MENU_CLICK, {
col: col,
row: row,
field: field,
menuKey: menuKey,
text: text,
highlight: highlight,
cellLocation: table.getCellLocation(col, row),
event: e
}), table.fireListeners(TABLE_EVENT_TYPE_1.TABLE_EVENT_TYPE.DROPDOWN_MENU_CLEAR, null),
table.fireListeners(TABLE_EVENT_TYPE_1.TABLE_EVENT_TYPE.HIDE_MENU, null), e.stopPropagation();
})), null === (_d = this._rootElement) || void 0 === _d || _d.addEventListener("click", (e => {
if (e.stopPropagation(), e.preventDefault(), this._rootElement.classList.contains(HIDDEN_CLASSNAME)) return;
const {col: col, row: row, dropDownIndex: dropDownIndex, menuKey: menuKey, text: text, hasChildren: hasChildren} = e.target;
if ("number" != typeof dropDownIndex || hasChildren) return void e.stopPropagation();
const field = table.isPivotTable() ? table.internalProps.layoutMap.getPivotDimensionInfo(col, row) : table.getHeaderField(col, row), highlight = table._dropDownMenuIsHighlight(col, row, dropDownIndex);
table.fireListeners(TABLE_EVENT_TYPE_1.TABLE_EVENT_TYPE.DROPDOWN_MENU_CLICK, {
col: col,
row: row,
field: field,
menuKey: menuKey,
text: text,
highlight: highlight,
cellLocation: table.getCellLocation(col, row),
event: e
}), table.fireListeners(TABLE_EVENT_TYPE_1.TABLE_EVENT_TYPE.DROPDOWN_MENU_CLEAR, null),
table.fireListeners(TABLE_EVENT_TYPE_1.TABLE_EVENT_TYPE.HIDE_MENU, null), e.stopPropagation();
})), null === (_e = this._rootElement) || void 0 === _e || _e.addEventListener("mousemove", (e => {
var _a, _b;
if (this._rootElement.classList.contains(HIDDEN_CLASSNAME)) return;
e.stopPropagation();
const {hasChildren: hasChildren, dropDownIndex: dropDownIndex, col: col, row: row, sub: sub} = e.target;
if (hasChildren) {
this._showChildrenIndex = dropDownIndex;
const secondElement = this._secondElement;
null == secondElement || secondElement.classList.remove(HIDDEN_CLASSNAME), null == secondElement || secondElement.classList.add(SHOWN_CLASSNAME),
secondElement.innerHTML = "";
const children = null === (_a = this._menuInstanceInfo.content[dropDownIndex]) || void 0 === _a ? void 0 : _a.children;
for (let i = 0; i < children.length; i++) {
const menuItem = children[i], item = createItem(menuItem, !!table.stateManager.menu.dropDownMenuHighlight && isMenuHighlight(table, table.stateManager.menu.dropDownMenuHighlight, "object" == typeof menuItem ? (null == menuItem ? void 0 : menuItem.menuKey) || (null == menuItem ? void 0 : menuItem.text) : menuItem, col, row, i));
item.col = col, item.row = row, item.dropDownIndex = i, "string" == typeof menuItem ? (item.text = menuItem,
item.menuKey = menuItem) : "object" == typeof menuItem && (item.text = menuItem.text,
item.menuKey = menuItem.menuKey || menuItem.text), item.sub = !0, item.sub = !0,
secondElement.appendChild(item);
}
const rect = e.target.getBoundingClientRect();
this._bindSecondElement(table, col, row, rect.right, rect.top);
} else if (hasChildren && this._showChildrenIndex === dropDownIndex) {
const secondElement = this._secondElement;
null == secondElement || secondElement.classList.remove(HIDDEN_CLASSNAME), null == secondElement || secondElement.classList.add(SHOWN_CLASSNAME);
} else !sub && (null === (_b = this._secondElement) || void 0 === _b ? void 0 : _b.classList.contains(SHOWN_CLASSNAME)) && setTimeout((() => {
if (!0 !== this._mouseEnterSecondElement) {
this._showChildrenIndex = -1;
const secondElement = this._secondElement;
null == secondElement || secondElement.classList.remove(SHOWN_CLASSNAME), null == secondElement || secondElement.classList.add(HIDDEN_CLASSNAME);
}
}), 300);
})), null === (_f = this._secondElement) || void 0 === _f || _f.addEventListener("wheel", (e => {
e.stopPropagation();
})), null === (_g = this._secondElement) || void 0 === _g || _g.addEventListener("mousemove", (e => {
this._rootElement.classList.contains(HIDDEN_CLASSNAME) || e.stopPropagation();
})), null === (_h = this._secondElement) || void 0 === _h || _h.addEventListener("mouseenter", (e => {
this._mouseEnterSecondElement = !0;
})), null === (_j = this._secondElement) || void 0 === _j || _j.addEventListener("mouseleave", (e => {
this._mouseEnterSecondElement = !1;
})), null === (_k = this._secondElement) || void 0 === _k || _k.addEventListener("mousedown", (e => {
e.stopPropagation(), e.preventDefault();
})), null === (_l = this._secondElement) || void 0 === _l || _l.addEventListener("click", (e => {
if (e.stopPropagation(), e.preventDefault(), this._secondElement.classList.contains(HIDDEN_CLASSNAME)) return;
const {col: col, row: row, dropDownIndex: dropDownIndex, menuKey: menuKey, text: text, hasChildren: hasChildren} = e.target;
if ("number" != typeof dropDownIndex || hasChildren) return void e.stopPropagation();
const field = table.isPivotTable() ? table.internalProps.layoutMap.getPivotDimensionInfo(col, row) : table.getHeaderField(col, row);
let highlight = !1;
this._menuInstanceInfo.content.forEach(((menu, i) => {
if ("object" == typeof menu && menu.children && menu.children.length) for (let j = 0; j < menu.children.length; j++) {
const childItem = menu.children[j];
if (isMenuHighlight(table, table.stateManager.menu.dropDownMenuHighlight, "object" == typeof childItem ? null == childItem ? void 0 : childItem.menuKey : childItem, col, row, -1) && menuKey === ("object" == typeof childItem ? null == childItem ? void 0 : childItem.menuKey : childItem)) return void (highlight = !0);
}
})), table.fireListeners(TABLE_EVENT_TYPE_1.TABLE_EVENT_TYPE.DROPDOWN_MENU_CLICK, {
col: col,
row: row,
field: field,
cellHeaderPaths: table.isPivotTable() ? table.getCellHeaderPaths(col, row) : void 0,
menuKey: menuKey,
text: text,
highlight: highlight,
cellLocation: table.getCellLocation(col, row),
event: e
}), table.fireListeners(TABLE_EVENT_TYPE_1.TABLE_EVENT_TYPE.DROPDOWN_MENU_CLEAR, null),
table.fireListeners(TABLE_EVENT_TYPE_1.TABLE_EVENT_TYPE.HIDE_MENU, null), e.stopPropagation();
}));
}
get rootElement() {
return this._rootElement;
}
release() {
this.unbindFromCell();
const rootElement = this._rootElement;
(null == rootElement ? void 0 : rootElement.parentElement) && rootElement.parentElement.removeChild(rootElement),
this._handler.release(), delete this._rootElement;
}
bindToCell(table, col, row, menuInstanceInfo) {
var _a, _b;
const rootElement = this._rootElement, secondElement = this._secondElement;
if (this._menuInstanceInfo = menuInstanceInfo, null == rootElement || rootElement.classList.remove(SHOWN_CLASSNAME),
null == rootElement || rootElement.classList.add(HIDDEN_CLASSNAME), null == secondElement || secondElement.classList.remove(SHOWN_CLASSNAME),
null == secondElement || secondElement.classList.add(HIDDEN_CLASSNAME), this._canBindToCell(table, col, row)) {
if (rootElement.innerHTML = "", Array.isArray(menuInstanceInfo.content)) {
const menuListItem = menuInstanceInfo.content;
for (let i = 0; null !== (_a = i < (null == menuListItem ? void 0 : menuListItem.length)) && void 0 !== _a && _a; i++) {
const menuItem = menuListItem[i];
let isHighlight = !!table.stateManager.menu.dropDownMenuHighlight && isMenuHighlight(table, table.stateManager.menu.dropDownMenuHighlight, "object" == typeof menuItem ? (null == menuItem ? void 0 : menuItem.menuKey) || (null == menuItem ? void 0 : menuItem.text) : menuItem, col, row, i);
if (table.stateManager.menu.dropDownMenuHighlight && "object" == typeof menuItem && Array.isArray(menuItem.children) && menuItem.children.length) for (let i = 0; i < menuItem.children.length; i++) {
const childItem = menuItem.children[i];
if (isMenuHighlight(table, table.stateManager.menu.dropDownMenuHighlight, "object" == typeof childItem ? (null == childItem ? void 0 : childItem.menuKey) || (null == childItem ? void 0 : childItem.text) : childItem, col, row, i)) {
isHighlight = !0;
break;
}
}
const item = createItem(menuItem, isHighlight);
item.col = col, item.row = row, item.dropDownIndex = i, "string" == typeof menuItem ? (item.text = menuItem,
item.menuKey = menuItem) : "object" == typeof menuItem && (item.text = menuItem.text,
item.menuKey = menuItem.menuKey || menuItem.text, (null === (_b = menuItem.children) || void 0 === _b ? void 0 : _b.length) && (item.hasChildren = !0)),
rootElement.appendChild(item);
}
}
if (this._bindToCell(table, col, row, menuInstanceInfo.position, menuInstanceInfo.referencePosition)) return null == rootElement || rootElement.classList.add(SHOWN_CLASSNAME),
null == rootElement || rootElement.classList.remove(HIDDEN_CLASSNAME), !0;
} else this.unbindFromCell();
return !1;
}
unbindFromCell() {
const rootElement = this._rootElement, secondElement = this._secondElement;
this._menuInstanceInfo = void 0, (null == rootElement ? void 0 : rootElement.parentElement) && (rootElement.classList.remove(SHOWN_CLASSNAME),
rootElement.classList.add(HIDDEN_CLASSNAME)), (null == secondElement ? void 0 : secondElement.parentElement) && (secondElement.classList.remove(SHOWN_CLASSNAME),
secondElement.classList.add(HIDDEN_CLASSNAME));
}
_canBindToCell(table, col, row) {
var _a;
const rect = table.getCellRangeRelativeRect({
col: col,
row: row
}), element = null !== (_a = table.internalProps.menu.parentElement) && void 0 !== _a ? _a : table.getElement(), {top: top, bottom: bottom, left: left, right: right} = rect;
if (table.isFrozenCell(col, row)) return !0;
if (bottom < table.getFrozenRowsHeight() || right < table.getFrozenColsWidth() || left > table.tableNoFrameWidth - table.getRightFrozenColsWidth() || top > table.tableNoFrameHeight - table.getBottomFrozenRowsHeight()) return !1;
const {offsetHeight: offsetHeight, offsetWidth: offsetWidth} = element;
return !(offsetHeight < top) && !(offsetWidth < left);
}
_bindToCell(table, col, row, position, referencePosition) {
var _a;
const rootElement = this._rootElement, element = null !== (_a = table.internalProps.menu.parentElement) && void 0 !== _a ? _a : table.getElement(), {width: containerWidth, height: containerHeight, left: containerLeft, top: containerTop} = element.getBoundingClientRect();
if (rootElement) {
rootElement.parentElement !== element && element.appendChild(rootElement), rootElement.style.left = "0px";
const maxWidth = .8 * containerWidth;
rootElement.style.maxWidth = `${maxWidth}px`;
const rootElementWidth = rootElement.offsetWidth, rootElementHeight = rootElement.offsetHeight;
let rootElementLeft, rootElementTop;
position ? (rootElementLeft = position.x, rootElementTop = position.y) : referencePosition && (rootElementLeft = referencePosition.rect.right - rootElementWidth,
rootElementTop = referencePosition.rect.bottom);
const rect = element.getBoundingClientRect(), scaleX = rect.width / element.offsetWidth, scaleY = rect.height / element.offsetHeight;
rootElementTop * scaleY + rootElementHeight > containerHeight && (rootElementTop = (containerHeight - rootElementHeight) / scaleY),
rootElementTop < 0 && (rootElementTop /= 2);
let deltaTop = 0, deltaLeft = 0;
if (table.getElement() !== element) {
const {left: left, top: top} = table.getElement().getBoundingClientRect();
deltaTop = top - containerTop, deltaLeft = left - containerLeft;
}
return rootElement.style.top = `${rootElementTop + deltaTop}px`, rootElementLeft < 0 ? rootElementLeft = 0 : rootElementLeft * scaleX + rootElementWidth > containerWidth && (rootElementLeft = (containerWidth - rootElementWidth) / scaleX),
rootElement.style.left = `${rootElementLeft + deltaLeft}px`, !0;
}
return !1;
}
_bindSecondElement(table, col, row, x, y) {
var _a;
const secondElement = this._secondElement, rootElement = this._rootElement, element = null !== (_a = table.internalProps.menu.parentElement) && void 0 !== _a ? _a : table.getElement(), {width: containerWidth, left: containerLeft, top: containerTop} = element.getBoundingClientRect(), {x: rootLeft, y: rootTop, width: rootWidth} = rootElement.getBoundingClientRect();
if (secondElement) {
secondElement.parentElement !== element && element.appendChild(secondElement), secondElement.style.left = "0px";
const maxWidth = .8 * containerWidth;
secondElement.style.maxWidth = `${maxWidth}px`;
const secondElementWidth = secondElement.clientWidth, secondElementTop = y - 4 - containerTop, secondElementLeft = x - containerLeft;
secondElement.style.top = `${secondElementTop}px`;
let leftStyle = secondElementLeft;
return leftStyle + secondElementWidth > containerWidth ? leftStyle = leftStyle - secondElementWidth - rootWidth : leftStyle += 4,
secondElement.style.left = `${leftStyle}px`, !0;
}
return !1;
}
pointInMenuElement(x, y) {
const rootElement = this._rootElement, {x: rootLeft, y: rootTop, width: rootWidth, height: rootHeight} = rootElement.getBoundingClientRect();
if (x > rootLeft - 5 && x < rootLeft + rootWidth + 5 && y > rootTop - 5 && y < rootTop + rootHeight + 5) return !0;
if (this._secondElement) {
const {x: secondLeft, y: secondTop, width: secondWidth, height: secondHeight} = rootElement.getBoundingClientRect();
if (x > secondLeft - 5 && x < secondLeft + secondWidth + 5 && y > secondTop - 5 && y < secondTop + secondHeight + 5) return !0;
}
return !1;
}
}
function createItem(info, isHighlight) {
var _a, _b, _c;
const itemContainer = (0, dom_1.createElement)("div", [ ITEM_CLASSNAME, isHighlight ? SELECT_CLASSNAME : NORAML_CLASSNAME ]);
if ("string" == typeof info) {
const item = (0, dom_1.createElement)("span", [ CONTENT_CLASSNAME, NOEVENT_CLASSNAME, ITEMTEXT_CLASSNAME ]);
item.innerHTML = info, itemContainer.appendChild(item);
} else if ("object" == typeof info) {
const type = null !== (_a = info.type) && void 0 !== _a ? _a : "item";
if ("split" === type) return null == itemContainer || itemContainer.classList.add(SPLIT_CLASSNAME),
itemContainer;
if (null === (_b = null == info ? void 0 : info.icon) || void 0 === _b ? void 0 : _b.svg) if (global_1.regUrl.test(info.icon.svg)) {
const image = new Image;
info.icon.width ? image.style.width = info.icon.width.toString() + "px" : image.style.width = "16px",
info.icon.height ? image.style.height = info.icon.height.toString() + "px" : image.style.height = "16px",
image.src = info.icon.svg, itemContainer.appendChild(image);
} else {
const svg = (0, dom_1.createElement)("span", [ ICOM_CLASSNAME, NOEVENT_CLASSNAME ]);
svg.innerHTML = isHighlight && info.selectedIcon && info.selectedIcon.svg ? info.selectedIcon.svg : info.icon.svg,
info.icon.width && svg.children[0].setAttribute("width", info.icon.width.toString()),
info.icon.height && svg.children[0].setAttribute("height", info.icon.height.toString()),
itemContainer.appendChild(svg);
}
const item = (0, dom_1.createElement)("span", [ CONTENT_CLASSNAME, NOEVENT_CLASSNAME, ITEMTEXT_CLASSNAME ]);
if (item.innerHTML = info.text, itemContainer.appendChild(item), "title" === type) null == itemContainer || itemContainer.classList.add(NOEVENT_CLASSNAME, TITLE_CLASSNAME); else if (null === (_c = null == info ? void 0 : info.children) || void 0 === _c ? void 0 : _c.length) {
const arrow = (0, dom_1.createElement)("span", [ CONTENT_CLASSNAME, NOEVENT_CLASSNAME, ARROW_CLASSNAME ]);
arrow.innerHTML = isHighlight ? '<svg width="8" height="12" viewBox="0 0 10 17" fill="none" xmlns="http://www.w3.org/2000/svg" style="vertical-align: baseline"><path d="M1.78186 16.7729L0.300378 15.2915L6.8189 8.77295L0.300377 2.25443L1.78186 0.77295L9.78186 8.77295L1.78186 16.7729Z" fill="#2E68CF" fill-opacity="0.65"></path></svg>' : '<svg width="8" height="12" viewBox="0 0 10 17" fill="none" xmlns="http://www.w3.org/2000/svg" style="vertical-align: baseline"><path d="M1.78186 16.7729L0.300378 15.2915L6.8189 8.77295L0.300377 2.25443L1.78186 0.77295L9.78186 8.77295L1.78186 16.7729Z" fill="#141414" fill-opacity="0.65"></path></svg>',
itemContainer.appendChild(arrow);
}
}
return itemContainer;
}
exports.MenuElement = MenuElement;
//# sourceMappingURL=MenuElement.js.map