UNPKG

@visactor/vtable

Version:

canvas table width high performance

288 lines (277 loc) 22.2 kB
"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