/* * Copyright (C) 2022 Huawei Device Co., Ltd. * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ import { LitTableColumn } from './lit-table-column'; import { LitProgressBar } from './../progress-bar/LitProgressBar'; import { BaseElement, element } from '../BaseElement'; import '../utils/Template'; import { TableRowObject } from './TableRowObject'; import { addCopyEventListener, addSelectAllBox, createDownUpSvg, exportData, fixed, formatExportData, formatName, iconPadding, iconWidth, litPageTableHtml, } from './LitTableHtml'; import { LitIcon } from '../icon/LitIcon'; @element('lit-page-table') export class LitPageTable extends BaseElement { meauseRowElement: HTMLDivElement | undefined; currentRecycleList: HTMLDivElement[] = []; currentTreeDivList: HTMLDivElement[] = []; public rememberScrollTop = false; public getItemTextColor?: (data: unknown) => string; public itemTextHandleMap: Map string> = new Map string>(); public exportLoading: boolean = false; public exportTextHandleMap: Map string> = new Map string>(); public ds: Array = []; public recycleDs: Array = []; public tableColumns: NodeListOf | undefined; public tableElement: HTMLDivElement | null | undefined; public columns: Array | null | undefined; public exportProgress: LitProgressBar | null | undefined; private gridTemplateColumns: Array = []; private st: HTMLSlotElement | null | undefined; private theadElement: HTMLDivElement | null | undefined; private tbodyElement: HTMLDivElement | undefined | null; private treeElement: HTMLDivElement | undefined | null; private previousDiv: HTMLDivElement | undefined | null; private nextDiv: HTMLDivElement | undefined | null; private currentPageDiv: HTMLDivElement | undefined | null; private targetPageInput: HTMLInputElement | undefined | null; private jumpDiv: HTMLDivElement | undefined | null; private colCount: number = 0; private isScrollXOutSide: boolean = false; private currentPage: number = 0; startSkip: number = 0; static get observedAttributes(): string[] { return [ 'scroll-y', 'selectable', 'no-head', 'grid-line', 'defaultOrderColumn', 'hideDownload', 'loading', 'pagination', ]; } set loading(value: boolean) { this.exportProgress!.loading = value; } get hideDownload(): boolean { return this.hasAttribute('hideDownload'); } set hideDownload(value) { if (value) { this.setAttribute('hideDownload', ''); } else { this.removeAttribute('hideDownload'); } } get selectable(): boolean { return this.hasAttribute('selectable'); } set selectable(value) { if (value) { this.setAttribute('selectable', ''); } else { this.removeAttribute('selectable'); } } get scrollY(): string { return this.getAttribute('scroll-y') || 'auto'; } set scrollY(value) { this.setAttribute('scroll-y', value); } get recycleDataSource(): unknown[] { return this.ds || []; } set recycleDataSource(value) { this.isScrollXOutSide = this.tableElement!.scrollWidth > this.tableElement!.clientWidth; this.ds = value; this.toTop(); this.currentPage = 0; this.pagination = value.length > 0 && Array.isArray(value[0]); if (this.pagination) { this.currentPageDiv!.textContent = `第 ${this.currentPage + 1} 页,共 ${this.ds.length} 页`; this.targetPageInput!.value = ''; } if (this.hasAttribute('tree')) { this.recycleDs = this.meauseTreeRowElement(value); } else { // @ts-ignore this.recycleDs = this.meauseAllRowHeight(this.pagination ? value[0] : value); } } set pagination(value: boolean) { if (value) { this.setAttribute('pagination', ''); } else { this.removeAttribute('pagination'); } } get pagination(): boolean { return this.hasAttribute('pagination'); } initElements(): void { this.tableElement = this.shadowRoot?.querySelector('.table'); this.st = this.shadowRoot?.querySelector('#slot'); this.theadElement = this.shadowRoot?.querySelector('.thead'); this.exportProgress = this.shadowRoot?.querySelector('#export_progress_bar'); this.treeElement = this.shadowRoot?.querySelector('.tree'); this.tbodyElement = this.shadowRoot?.querySelector('.body'); this.tableColumns = this.querySelectorAll('lit-table-column'); this.previousDiv = this.shadowRoot?.querySelector('#previousPage'); this.nextDiv = this.shadowRoot?.querySelector('#nextPage'); this.currentPageDiv = this.shadowRoot?.querySelector('#currentPage'); this.targetPageInput = this.shadowRoot?.querySelector('#targetPage'); this.jumpDiv = this.shadowRoot?.querySelector('#jumpPage'); this.initPageEventListener(); } initPageEventListener(): void { this.previousDiv!.onclick = (): void => { if (this.currentPage > 0) { this.currentPage = Math.max(this.currentPage - 1, 0); this.showCurrentPageData(); } }; this.nextDiv!.onclick = (): void => { if (this.currentPage < this.ds.length - 1) { this.currentPage = Math.min(this.currentPage + 1, this.ds.length - 1); this.showCurrentPageData(); } }; this.jumpDiv!.onclick = (): void => { let value = this.targetPageInput!.value; let reg = /^[0-9]*$/; if (value.length > 0 && reg.test(value)) { let target = parseInt(value); if (target < 1) { target = 1; } if (target > this.ds.length) { target = this.ds.length; } this.targetPageInput!.value = `${target}`; if (this.currentPage !== target - 1) { this.currentPage = target - 1; this.showCurrentPageData(); } } else { this.targetPageInput!.value = ''; } }; } toTop(): void { if (this.rememberScrollTop) { this.tableElement!.scrollTop = 0; this.tableElement!.scrollLeft = 0; } else { this.tableElement!.scrollTop = 0; } } showCurrentPageData(): void { this.toTop(); this.currentPageDiv!.textContent = `第 ${(this.currentPage || 0) + 1} 页,共 ${this.ds.length} 页`; if (this.hasAttribute('tree')) { // @ts-ignore this.recycleDs = this.meauseTreeRowElement(this.ds[this.currentPage]); } else { // @ts-ignore this.recycleDs = this.meauseAllRowHeight(this.ds[this.currentPage]); } } initHtml(): string { return litPageTableHtml; } dataExportInit(): void { let exportDiv = this.shadowRoot!.querySelector('.export'); exportDiv && (exportDiv.onclick = (): void => { this.exportData(); }); } exportData(): void { exportData(this); } formatExportData(dataSource: unknown[]): unknown[] { return formatExportData(dataSource, this); } //当 custom element首次被插入文档DOM时,被调用。 connectedCallback(): void { this.dataExportInit(); addCopyEventListener(this); this.colCount = this.tableColumns!.length; this.st?.addEventListener('slotchange', () => { this.theadElement!.innerHTML = ''; setTimeout(() => { this.columns = this.st!.assignedElements(); let rowElement = document.createElement('div'); rowElement.classList.add('th'); this.gridTemplateColumns = []; let pageArea: Array = []; addSelectAllBox(rowElement, this); this.resolvingArea(this.columns, 0, 0, pageArea, rowElement); pageArea.forEach((rows, j, array) => { for (let i = 0; i < this.colCount; i++) { // @ts-ignore if (!rows[i]) { // @ts-ignore rows[i] = array[j - 1][i]; } } }); if (this.selectable) { // @ts-ignore let s = pageArea.map((a) => '"_checkbox_ ' + a.map((aa: unknown) => aa.t).join(' ') + '"').join(' '); rowElement.style.gridTemplateColumns = '60px ' + this.gridTemplateColumns.join(' '); rowElement.style.gridTemplateRows = `repeat(${pageArea.length},1fr)`; rowElement.style.gridTemplateAreas = s; } else { // @ts-ignore let s = pageArea.map((a) => '"' + a.map((aa: unknown) => aa.t).join(' ') + '"').join(' '); rowElement.style.gridTemplateColumns = this.gridTemplateColumns.join(' '); rowElement.style.gridTemplateRows = `repeat(${pageArea.length},1fr)`; rowElement.style.gridTemplateAreas = s; } this.theadElement!.innerHTML = ''; this.theadElement!.append(rowElement); this.treeElement!.style.top = this.theadElement?.clientHeight + 'px'; }); }); this.shadowRoot!.addEventListener('load', function (event) {}); this.tableElement!.addEventListener('mouseout', (ev) => this.mouseOut()); } resolvingArea(columns: unknown, x: unknown, y: unknown, area: Array, rowElement: HTMLDivElement): void { // @ts-ignore columns.forEach((a: unknown, i: unknown) => { // @ts-ignore if (!area[y]) { // @ts-ignore area[y] = []; } // @ts-ignore let key = a.getAttribute('key') || a.getAttribute('title'); // @ts-ignore if (a.tagName === 'LIT-TABLE-GROUP') { // @ts-ignore let childList = [...a.children].filter((a) => a.tagName !== 'TEMPLATE'); // @ts-ignore let len = a.querySelectorAll('lit-table-column').length; if (childList.length > 0) { // @ts-ignore this.resolvingArea(childList, x, y + 1, area, rowElement); } for (let j = 0; j < len; j++) { // @ts-ignore area[y][x] = { x, y, t: key }; // @ts-ignore x++; } let head = document.createElement('div'); head.classList.add('td'); // @ts-ignore head.style.justifyContent = a.getAttribute('align'); head.style.borderBottom = '1px solid #f0f0f0'; head.style.gridArea = key; // @ts-ignore head.innerText = a.title; // @ts-ignore if (a.hasAttribute('fixed')) { // @ts-ignore fixed(head, a.getAttribute('fixed'), '#42b983'); } rowElement.append(head); // @ts-ignore } else if (a.tagName === 'LIT-TABLE-COLUMN') { // @ts-ignore area[y][x] = { x, y, t: key }; // @ts-ignore x++; let h: unknown = document.createElement('div'); // @ts-ignore h.classList.add('td'); // @ts-ignore if (i > 0) { let resizeDiv: HTMLDivElement = document.createElement('div'); resizeDiv.classList.add('resize'); // @ts-ignore h.appendChild(resizeDiv); // @ts-ignore this.resizeEventHandler(rowElement, resizeDiv, i); } // @ts-ignore this.resolvingAreaColumnOrder(a, i, key, h); // @ts-ignore h.style.justifyContent = a.getAttribute('align'); // @ts-ignore this.gridTemplateColumns.push(a.getAttribute('width') || '1fr'); // @ts-ignore h.style.gridArea = key; let titleLabel = document.createElement('label'); // @ts-ignore titleLabel.textContent = a.title; // @ts-ignore h.appendChild(titleLabel); // @ts-ignore if (a.hasAttribute('fixed')) { // @ts-ignore fixed(h, a.getAttribute('fixed'), '#42b983'); } // @ts-ignore rowElement.append(h); } }); } resolvingAreaColumnOrder(column: unknown, index: number, key: string, head: unknown): void { // @ts-ignore if (column.hasAttribute('order')) { // @ts-ignore (head as unknown).sortType = 0; // @ts-ignore head.classList.add('td-order'); // @ts-ignore head.style.position = 'relative'; let { upSvg, downSvg } = createDownUpSvg(index, head); // @ts-ignore head.onclick = (): void => { if (this.isResize || this.resizeColumnIndex !== -1) { return; } this?.shadowRoot?.querySelectorAll('.td-order svg').forEach((it: unknown) => { // @ts-ignore it.setAttribute('fill', 'let(--dark-color1,#212121)'); // @ts-ignore it.sortType = 0; // @ts-ignore it.style.display = 'none'; }); // @ts-ignore if (head.sortType === undefined || head.sortType === null) { // @ts-ignore head.sortType = 0; // @ts-ignore } else if (head.sortType === 2) { // @ts-ignore head.sortType = 0; } else { // @ts-ignore head.sortType += 1; } upSvg.setAttribute('fill', 'let(--dark-color1,#212121)'); downSvg.setAttribute('fill', 'let(--dark-color1,#212121)'); // @ts-ignore upSvg.style.display = head.sortType === 1 ? 'block' : 'none'; // @ts-ignore downSvg.style.display = head.sortType === 2 ? 'block' : 'none'; // @ts-ignore switch (head.sortType) { case 1: this.theadElement!.setAttribute('sort', ''); break; case 2: break; default: this.theadElement!.removeAttribute('sort'); break; } this.dispatchEvent( new CustomEvent('column-click', { detail: { // @ts-ignore sort: head.sortType, key: key, }, composed: true, }) ); }; } } private isResize: boolean = false; private resizeColumnIndex: number = -1; private resizeDownX: number = 0; private columnMinWidth: number = 50; private beforeResizeWidth: number = 0; resizeMouseMoveEventHandler(header: HTMLDivElement): void { header.addEventListener('mousemove', (event) => { if (this.isResize) { header.style.cursor = 'col-resize'; let width = event.clientX - this.resizeDownX; let prePageWidth = Math.max(this.beforeResizeWidth + width, this.columnMinWidth); for (let i = 0; i < header.childNodes.length; i++) { let node = header.childNodes.item(i) as HTMLDivElement; this.gridTemplateColumns[i] = `${node.clientWidth}px`; } this.gridTemplateColumns[this.resizeColumnIndex - 1] = `${prePageWidth}px`; let lastNode = header.childNodes.item(header.childNodes.length - 1) as HTMLDivElement; let totalWidth = 0; this.gridTemplateColumns.forEach((it) => { totalWidth += parseInt(it); }); totalWidth = Math.max(totalWidth, this.shadowRoot!.querySelector('.table')!.scrollWidth); this.gridTemplateColumns[this.gridTemplateColumns.length - 1] = `${totalWidth - lastNode.offsetLeft - 1}px`; header.style.gridTemplateColumns = this.gridTemplateColumns.join(' '); let preNode = header.childNodes.item(this.resizeColumnIndex - 1) as HTMLDivElement; preNode.style.width = `${prePageWidth}px`; this.shadowRoot!.querySelectorAll('.tr').forEach((tr) => { tr.style.gridTemplateColumns = this.gridTemplateColumns.join(' '); }); event.preventDefault(); event.stopPropagation(); } else { header.style.cursor = 'pointer'; } }); } resizeEventHandler(header: HTMLDivElement, element: HTMLDivElement, index: number): void { this.resizeMouseMoveEventHandler(header); header.addEventListener('mouseup', (event) => { this.resizeDownX = 0; this.isResize = false; header.style.cursor = 'pointer'; setTimeout(() => { this.resizeColumnIndex = -1; }, 100); event.stopPropagation(); event.preventDefault(); }); header.addEventListener('mouseleave', (event) => { event.stopPropagation(); event.preventDefault(); this.isResize = false; this.resizeDownX = 0; this.resizeColumnIndex = -1; header.style.cursor = 'pointer'; }); element.addEventListener('mousedown', (event) => { if (event.button === 0) { this.resizeColumnIndex = index; this.isResize = true; this.resizeDownX = event.clientX; let pre = header.childNodes.item(this.resizeColumnIndex - 1) as HTMLDivElement; this.beforeResizeWidth = pre.clientWidth; event.stopPropagation(); } }); element.addEventListener('click', (event) => { event.stopPropagation(); }); } // Is called when the custom element is removed from the document DOM. disconnectedCallback(): void {} // It is called when the custom element is moved to a new document. adoptedCallback(): void {} // It is called when a custom element adds, deletes, or modifies its own properties. attributeChangedCallback(name: string, oldValue: string, newValue: string): void {} meauseElementHeight(rowData: unknown): number { return 27; } meauseTreeElementHeight(rowData: unknown, depth: number): number { return 27; } meauseAllRowHeight(list: unknown[]): TableRowObject[] { this.tbodyElement!.innerHTML = ''; this.meauseRowElement = undefined; this.startSkip = 0; let head = this.shadowRoot!.querySelector('.th'); this.tbodyElement && (this.tbodyElement.style.width = head?.clientWidth + 'px'); this.currentRecycleList = []; let headHeight = 0; let totalHeight = headHeight; let visibleObjects: TableRowObject[] = []; let itemHandler = (rowData: unknown, index: number): void => { let height = this.meauseElementHeight(rowData); let tableRowObject = new TableRowObject(); tableRowObject.height = height; tableRowObject.top = totalHeight; tableRowObject.data = rowData; tableRowObject.rowIndex = index; if ( Math.max(totalHeight, this.tableElement!.scrollTop + headHeight) <= Math.min(totalHeight + height, this.tableElement!.scrollTop + this.tableElement!.clientHeight + headHeight) ) { let newTableElement = this.createNewTableElement(tableRowObject); newTableElement.style.transform = `translateY(${totalHeight}px)`; this.tbodyElement?.append(newTableElement); this.currentRecycleList.push(newTableElement); } totalHeight += height; visibleObjects.push(tableRowObject); }; let realIndex = 0; list.forEach((item, index) => { if (Array.isArray(item)) { item.forEach((rowData, childIndex) => { itemHandler(rowData, realIndex); realIndex++; }); } else { itemHandler(item, index); } }); this.tbodyElement && (this.tbodyElement.style.height = totalHeight + (this.isScrollXOutSide ? 0 : 0) + 'px'); this.addOnScrollListener(visibleObjects); return visibleObjects; } addOnScrollListener(visibleObjList: TableRowObject[]): void { this.tableElement && (this.tableElement.onscroll = (event): void => { let tblScrollTop = this.tableElement!.scrollTop; let skip = 0; for (let i = 0; i < visibleObjList.length; i++) { if ( visibleObjList[i].top <= tblScrollTop && visibleObjList[i].top + visibleObjList[i].height >= tblScrollTop ) { skip = i; break; } } let reduce = this.currentRecycleList.map((item) => item.clientHeight).reduce((a, b) => a + b, 0); if (reduce === 0) { return; } while ( reduce <= this.tableElement!.clientHeight && this.currentRecycleList.length + skip < visibleObjList.length ) { let newTableElement = this.createNewTableElement(visibleObjList[skip]); this.tbodyElement?.append(newTableElement); this.currentRecycleList.push(newTableElement); reduce += newTableElement.clientHeight; } this.startSkip = skip; for (let i = 0; i < this.currentRecycleList.length; i++) { this.freshCurrentLine(this.currentRecycleList[i], visibleObjList[i + skip]); } }); } measureReset(): void { this.meauseRowElement = undefined; this.tbodyElement!.innerHTML = ''; this.treeElement!.innerHTML = ''; this.currentRecycleList = []; this.currentTreeDivList = []; } meauseTreeRowElement(list: unknown[]): TableRowObject[] { this.measureReset(); let headHeight = this.theadElement?.clientHeight || 0; let totalHeight = 0; let visibleObjects: TableRowObject[] = []; let resetAllHeight = (list: unknown[], depth: number, parentNode?: TableRowObject): void => { list.forEach((item) => { let tableRowObject = new TableRowObject(); tableRowObject.depth = depth; tableRowObject.data = item; tableRowObject.top = totalHeight; tableRowObject.height = this.meauseTreeElementHeight(tableRowObject, depth); if (parentNode !== undefined) { parentNode.children.push(tableRowObject); } let maxHeight = Math.max(totalHeight, this.tableElement!.scrollTop); let minHeight = Math.min( totalHeight + tableRowObject.height, this.tableElement!.scrollTop + this.tableElement!.clientHeight - headHeight ); if (maxHeight <= minHeight) { let newTableElement = this.createNewTreeTableElement(tableRowObject); // @ts-ignore newTableElement.style.transform = `translateY(${totalHeight}px)`; // @ts-ignore this.tbodyElement?.append(newTableElement); if (this.treeElement?.lastChild) { (this.treeElement?.lastChild as HTMLElement).style.height = tableRowObject.height + 'px'; } // @ts-ignore this.currentRecycleList.push(newTableElement); } totalHeight += tableRowObject.height; visibleObjects.push(tableRowObject); // @ts-ignore if (item.hasNext) { // @ts-ignore if (item.parents !== undefined && item.parents.length > 0 && item.status) { // @ts-ignore resetAllHeight(item.parents, depth + 1, tableRowObject); // @ts-ignore } else if (item.children !== undefined && item.children.length > 0 && item.status) { // @ts-ignore resetAllHeight(item.children, depth + 1, tableRowObject); } } else { // @ts-ignore if (item.children !== undefined && item.children.length > 0) { // @ts-ignore resetAllHeight(item.children, depth + 1, tableRowObject); } } }); }; resetAllHeight(list, 0); this.tbodyElement && (this.tbodyElement.style.height = totalHeight + 'px'); this.treeElement!.style.height = this.tableElement!.clientHeight - this.theadElement!.clientHeight + 'px'; this.addTreeRowScrollListener(); return visibleObjects; } addTreeRowScrollListener(): void { this.tableElement && (this.tableElement.onscroll = (event): void => { let visibleObjs = this.recycleDs.filter((item) => { // @ts-ignore return !item.rowHidden; }); let top = this.tableElement!.scrollTop; this.treeElement!.style.transform = `translateY(${top}px)`; let skip = 0; for (let index = 0; index < visibleObjs.length; index++) { // @ts-ignore if (visibleObjs[index].top <= top && visibleObjs[index].top + visibleObjs[index].height >= top) { skip = index; break; } } let reduce = this.currentRecycleList.map((item) => item.clientHeight).reduce((a, b) => a + b, 0); if (reduce === 0) { return; } while (reduce <= this.tableElement!.clientHeight) { // @ts-ignore let newTableElement = this.createNewTreeTableElement(visibleObjs[skip]); // @ts-ignore this.tbodyElement?.append(newTableElement); if (this.treeElement?.lastChild) { // @ts-ignore (this.treeElement?.lastChild as HTMLElement).style.height = visibleObjs[skip].height + 'px'; } // @ts-ignore this.currentRecycleList.push(newTableElement); // @ts-ignore reduce += newTableElement.clientHeight; } for (let i = 0; i < this.currentRecycleList.length; i++) { this.freshCurrentLine( this.currentRecycleList[i], // @ts-ignore visibleObjs[i + skip], this.treeElement?.children[i] as HTMLElement ); } }); } createNewTreeTableElement(rowData: TableRowObject): unknown { let newTableElement = document.createElement('div'); newTableElement.classList.add('tr'); let treeTop = 0; if (this.treeElement!.children?.length > 0) { let transX = Number((this.treeElement?.lastChild as HTMLElement).style.transform.replace(/[^0-9]/gi, '')); treeTop += transX + rowData.height; } this?.columns?.forEach((column: unknown, index) => { // @ts-ignore let dataIndex = column.getAttribute('data-index') || '1'; let td: unknown; if (index === 0) { td = this.firstElementTdHandler(newTableElement, dataIndex, rowData, column); } else { td = this.otherElementHandler(dataIndex, rowData, column); // @ts-ignore newTableElement.append(td); } }); let lastChild = this.treeElement?.lastChild as HTMLElement; if (lastChild) { lastChild.style.transform = `translateY(${treeTop}px)`; } // @ts-ignore (newTableElement as unknown).data = rowData.data; newTableElement.style.gridTemplateColumns = this.gridTemplateColumns.join(' '); newTableElement.style.position = 'absolute'; newTableElement.style.top = '0px'; newTableElement.style.left = '0px'; newTableElement.style.cursor = 'pointer'; //@ts-ignore this.setHighLight(rowData.data.isSearch, newTableElement); this.addRowElementEvent(newTableElement, rowData); return newTableElement; } addRowElementEvent(newTableElement: HTMLDivElement, rowData: unknown): void { newTableElement.onmouseenter = (): void => { // @ts-ignore if ((newTableElement as unknown).data.isSelected) { return; } let indexOf = this.currentRecycleList.indexOf(newTableElement); this.currentTreeDivList.forEach((row) => { row.classList.remove('mouse-in'); }); if (indexOf >= 0 && indexOf < this.treeElement!.children.length) { this.setMouseIn(true, [this.treeElement?.children[indexOf] as HTMLElement]); } }; newTableElement.onmouseleave = (): void => { // @ts-ignore if ((newTableElement as unknown).data.isSelected) { return; } let indexOf = this.currentRecycleList.indexOf(newTableElement); if (indexOf >= 0 && indexOf < this.treeElement!.children.length) { this.setMouseIn(false, [this.treeElement?.children[indexOf] as HTMLElement]); } }; newTableElement.onclick = (e): void => { let indexOf = this.currentRecycleList.indexOf(newTableElement); this.dispatchRowClickEvent(rowData, [this.treeElement?.children[indexOf] as HTMLElement, newTableElement]); }; } firstElementTdHandler( newTableElement: HTMLDivElement, dataIndex: string, rowData: unknown, column: unknown ): HTMLDivElement { let td: unknown; // @ts-ignore let text = formatName(dataIndex, rowData.data[dataIndex], this); // @ts-ignore if (column.template) { // @ts-ignore td = column.template.render(rowData.data).content.cloneNode(true); // @ts-ignore td.template = column.template; // @ts-ignore td.title = text; } else { td = document.createElement('div'); // @ts-ignore td.innerHTML = text; // @ts-ignore td.dataIndex = dataIndex; // @ts-ignore td.title = text; } // @ts-ignore if (rowData.data.children && rowData.data.children.length > 0 && !rowData.data.hasNext) { let btn = this.createExpandBtn(rowData); // @ts-ignore td.insertBefore(btn, td.firstChild); } // @ts-ignore if (rowData.data.hasNext) { // @ts-ignore td.title = rowData.data.objectName; let btn = this.createBtn(rowData); // @ts-ignore td.insertBefore(btn, td.firstChild); } // @ts-ignore td.style.paddingLeft = rowData.depth * iconWidth + 'px'; // @ts-ignore if (!rowData.data.children || rowData.data.children.length === 0) { // @ts-ignore td.style.paddingLeft = iconWidth * rowData.depth + iconWidth + iconPadding * 2 + 'px'; } // @ts-ignore (td as unknown).data = rowData.data; // @ts-ignore td.classList.add('tree-first-body'); // @ts-ignore td.style.position = 'absolute'; // @ts-ignore td.style.top = '0px'; // @ts-ignore td.style.left = '0px'; // @ts-ignore this.addFirstElementEvent(td, newTableElement, rowData); // @ts-ignore this.setHighLight(rowData.data.isSearch, td); // @ts-ignore this.treeElement!.style.width = column.getAttribute('width'); // @ts-ignore this.treeElement?.append(td); // @ts-ignore this.currentTreeDivList.push(td); // @ts-ignore return td; } addFirstElementEvent(td: HTMLDivElement, tr: HTMLDivElement, rowData: unknown): void { td.onmouseenter = (): void => { let indexOf = this.currentTreeDivList.indexOf(td); this.currentRecycleList.forEach((row) => { row.classList.remove('mouse-in'); }); if (indexOf >= 0 && indexOf < this.currentRecycleList.length && td.innerHTML !== '') { this.setMouseIn(true, [td]); } }; td.onmouseleave = (): void => { let indexOf = this.currentTreeDivList.indexOf(td); if (indexOf >= 0 && indexOf < this.currentRecycleList.length) { this.setMouseIn(false, [td]); } }; td.onclick = (): void => { let indexOf = this.currentTreeDivList.indexOf(td); this.dispatchRowClickEvent(rowData, [td, tr]); }; } otherElementHandler(dataIndex: string, rowData: unknown, column: unknown): HTMLDivElement { // @ts-ignore let text = formatName(dataIndex, rowData.data[dataIndex], this); let td: unknown = document.createElement('div'); td = document.createElement('div'); // @ts-ignore td.classList.add('td'); // @ts-ignore td.style.overflow = 'hidden'; // @ts-ignore td.style.textOverflow = 'ellipsis'; // @ts-ignore td.style.whiteSpace = 'nowrap'; // @ts-ignore td.title = text; // @ts-ignore td.dataIndex = dataIndex; // @ts-ignore td.style.justifyContent = column.getAttribute('align') || 'flex-start'; // @ts-ignore if (column.template) { // @ts-ignore td.appendChild(column.template.render(rowData.data).content.cloneNode(true)); // @ts-ignore td.template = column.template; } else { // @ts-ignore td.innerHTML = text; } // @ts-ignore return td; } createBtn(row: unknown): unknown { let btn: unknown = document.createElement('lit-icon'); // @ts-ignore btn.classList.add('tree-icon'); // @ts-ignore if (row.data.expanded) { // @ts-ignore btn.name = 'plus-square'; } else { // @ts-ignore btn.name = 'minus-square'; } // @ts-ignore btn.addEventListener('click', (e: unknown) => { // @ts-ignore row.data.status = false; const resetNodeHidden = (hidden: boolean, rowData: unknown): void => { if (hidden) { // @ts-ignore rowData.children.forEach((child: unknown) => { // @ts-ignore child.rowHidden = false; }); } else { // @ts-ignore rowData.children.forEach((child: unknown) => { // @ts-ignore child.rowHidden = true; resetNodeHidden(hidden, child); }); } }; // @ts-ignore if (row.data.expanded) { // @ts-ignore row.data.status = true; this.dispatchRowClickEventIcon(row, [btn]); // @ts-ignore row.data.expanded = false; resetNodeHidden(true, row); } else { // @ts-ignore row.data.expanded = true; // @ts-ignore row.data.status = false; resetNodeHidden(false, row); } this.reMeauseHeight(); // @ts-ignore e.stopPropagation(); }); return btn; } createExpandBtn(row: unknown): LitIcon { let btn: unknown = document.createElement('lit-icon'); // @ts-ignore btn.classList.add('tree-icon'); // @ts-ignore if (row.expanded) { // @ts-ignore btn.name = 'minus-square'; } else { // @ts-ignore btn.name = 'plus-square'; } // @ts-ignore btn.onclick = (e: Event): void => { const resetNodeHidden = (hidden: boolean, rowData: unknown): void => { // @ts-ignore if (rowData.children.length > 0) { if (hidden) { // @ts-ignore rowData.children.forEach((child: unknown) => { // @ts-ignore child.rowHidden = true; resetNodeHidden(hidden, child); }); } else { // @ts-ignore rowData.children.forEach((child: unknown) => { // @ts-ignore child.rowHidden = !rowData.expanded; // @ts-ignore if (rowData.expanded) { resetNodeHidden(hidden, child); } }); } } }; // @ts-ignore if (row.expanded) { // @ts-ignore row.expanded = false; resetNodeHidden(true, row); } else { // @ts-ignore row.expanded = true; resetNodeHidden(false, row); } this.reMeauseHeight(); e.stopPropagation(); }; // @ts-ignore return btn; } getVisibleObjs(): { visibleObjs: unknown[]; skip: number; reduce: number } { let totalH = 0; this.recycleDs.forEach((it) => { // @ts-ignore if (!it.rowHidden) { // @ts-ignore it.top = totalH; // @ts-ignore totalH += it.height; } }); this.tbodyElement && (this.tbodyElement.style.height = totalH + (this.isScrollXOutSide ? 0 : 0) + 'px'); this.treeElement!.style.height = this.tableElement!.clientHeight - this.theadElement!.clientHeight + 'px'; let visibleObjs = this.recycleDs.filter((item) => { // @ts-ignore return !item.rowHidden; }); let top = this.tableElement!.scrollTop; let skip = 0; for (let i = 0; i < visibleObjs.length; i++) { // @ts-ignore if (visibleObjs[i].top <= top && visibleObjs[i].top + visibleObjs[i].height >= top) { skip = i; break; } } let reduce = this.currentRecycleList.map((item) => item.clientHeight).reduce((a, b) => a + b, 0); return { visibleObjs, skip, reduce }; } reMeauseHeight(): void { if (this.currentRecycleList.length === 0) { return; } let { visibleObjs, skip, reduce } = this.getVisibleObjs(); if (reduce === 0) { return; } while (reduce <= this.tableElement!.clientHeight + 1) { let rowElement; if (this.hasAttribute('tree')) { // @ts-ignore rowElement = this.createNewTreeTableElement(visibleObjs[skip]); } else { rowElement = this.createNewTableElement(visibleObjs[skip]); } // @ts-ignore this.tbodyElement?.append(rowElement); if (this.hasAttribute('tree')) { if (this.treeElement?.lastChild) { // @ts-ignore (this.treeElement?.lastChild as HTMLElement).style.height = visibleObjs[skip].height + 'px'; } } // @ts-ignore this.currentRecycleList.push(rowElement); // @ts-ignore reduce += rowElement.clientHeight; } for (let i = 0; i < this.currentRecycleList.length; i++) { if (this.hasAttribute('tree')) { this.freshCurrentLine( this.currentRecycleList[i], // @ts-ignore visibleObjs[i + skip], this.treeElement?.children[i] as HTMLElement ); } else { // @ts-ignore this.freshCurrentLine(this.currentRecycleList[i], visibleObjs[i + skip]); } } } createNewTableElement(rowData: unknown): HTMLDivElement { let rowElement = document.createElement('div'); rowElement.classList.add('tr'); this?.columns?.forEach((column: unknown) => { // @ts-ignore let dataIndex = column.getAttribute('data-index') || '1'; let td: unknown; td = document.createElement('div'); // @ts-ignore td.classList.add('td'); // @ts-ignore td.style.overflow = 'hidden'; // @ts-ignore td.style.textOverflow = 'ellipsis'; // @ts-ignore td.style.whiteSpace = 'nowrap'; // @ts-ignore td.dataIndex = dataIndex; // @ts-ignore td.style.justifyContent = column.getAttribute('align') || 'flex-start'; // @ts-ignore let text = formatName(dataIndex, rowData.data[dataIndex], this); // @ts-ignore td.title = text; // @ts-ignore if (column.template) { // @ts-ignore td.appendChild(column.template.render(rowData.data).content.cloneNode(true)); // @ts-ignore td.template = column.template; } else { // @ts-ignore td.innerHTML = text; } // @ts-ignore rowElement.append(td); }); rowElement.onclick = (): void => { this.dispatchRowClickEvent(rowData, [rowElement]); }; rowElement.onmouseover = (): void => { this.dispatchRowHoverEvent(rowData, [rowElement]); }; // @ts-ignore if (rowData.data.isSelected !== undefined) { // @ts-ignore this.setSelectedRow(rowData.data.isSelected, [rowElement]); } // @ts-ignore (rowElement as unknown).data = rowData.data; rowElement.style.cursor = 'pointer'; rowElement.style.gridTemplateColumns = this.gridTemplateColumns.join(' '); rowElement.style.position = 'absolute'; rowElement.style.top = '0px'; rowElement.style.left = '0px'; // @ts-ignore rowElement.style.height = `${rowData.height}px`; if (this.getItemTextColor) { // @ts-ignore rowElement.style.color = this.getItemTextColor(rowData.data); } return rowElement; } freshCurrentLine(element: HTMLElement, rowObject: TableRowObject, firstElement?: HTMLElement): void { if (!rowObject) { if (firstElement) { firstElement.style.display = 'none'; } element.style.display = 'none'; return; } let childIndex = -1; //@ts-ignore this.setHighLight(rowObject.data.isSearch, element); element.childNodes.forEach((child) => { if (child.nodeType !== 1) { return; } childIndex++; let idx = firstElement !== undefined ? childIndex + 1 : childIndex; this.freshLineFirstElementHandler(firstElement, rowObject, childIndex); //@ts-ignore let dataIndex = this.columns![idx].getAttribute('data-index') || '1'; //@ts-ignore let text = formatName(dataIndex, rowObject.data[dataIndex], this); // @ts-ignore if ((this.columns![idx] as unknown).template) { (child as HTMLElement).innerHTML = ''; (child as HTMLElement).appendChild( // @ts-ignore (this.columns![idx] as unknown).template.render(rowObject.data).content.cloneNode(true) ); // @ts-ignore (child as HTMLElement).title = text; } else { //@ts-ignore (child as HTMLElement).innerHTML = text; //@ts-ignore (child as HTMLElement).title = text; } }); this.freshLineStyleAndEvents(element, rowObject, firstElement); } freshLineFirstElementHandler(rowFirstElement: unknown, rowObject: TableRowObject, childIndex: number): void { if (rowFirstElement !== undefined && childIndex === 0) { //@ts-ignore this.setHighLight(rowObject.data.isSearch, rowFirstElement); // @ts-ignore (rowFirstElement as unknown).data = rowObject.data; // @ts-ignore if ((this.columns![0] as unknown).template) { // @ts-ignore rowFirstElement.innerHTML = (this.columns![0] as unknown).template .render(rowObject.data) .content.cloneNode(true).innerHTML; } else { let dataIndex = this.columns![0].getAttribute('data-index') || '1'; //@ts-ignore let text = formatName(dataIndex, rowObject.data[dataIndex], this); // @ts-ignore rowFirstElement.innerHTML = text; // @ts-ignore rowFirstElement.title = text; } //@ts-ignore if (rowObject.children && rowObject.children.length > 0 && !rowObject.data.hasNext) { let btn = this.createExpandBtn(rowObject); // @ts-ignore rowFirstElement.insertBefore(btn, rowFirstElement.firstChild); } // @ts-ignore rowFirstElement.style.paddingLeft = iconWidth * rowObject.depth + 'px'; if (!rowObject.children || rowObject.children.length === 0) { // @ts-ignore rowFirstElement.style.paddingLeft = iconWidth * rowObject.depth + iconWidth + iconPadding * 2 + 'px'; } //@ts-ignore if (rowObject.data.hasNext) { let btn = this.createBtn(rowObject); // @ts-ignore rowFirstElement.title = rowObject.data.objectName; // @ts-ignore rowFirstElement.insertBefore(btn, rowFirstElement.firstChild); // @ts-ignore rowFirstElement.style.paddingLeft = iconWidth * rowObject.depth + 'px'; } // @ts-ignore rowFirstElement.onclick = (): void => { this.dispatchRowClickEvent(rowObject, [rowFirstElement, element]); }; // @ts-ignore rowFirstElement.style.transform = `translateY(${rowObject.top - this.tableElement!.scrollTop}px)`; //@ts-ignore if (rowObject.data.isSelected !== undefined) { //@ts-ignore this.setSelectedRow(rowObject.data.isSelected, [rowFirstElement]); } else { this.setSelectedRow(false, [rowFirstElement]); } } } freshLineStyleAndEvents(element: HTMLElement, rowData: TableRowObject, firstElement?: HTMLElement): void { if (element.style.display === 'none') { element.style.display = 'grid'; } element.style.transform = `translateY(${rowData.top}px)`; if (firstElement && firstElement.style.display === 'none') { firstElement.style.display = 'flex'; } element.onclick = (e): void => { if (firstElement !== undefined) { this.dispatchRowClickEvent(rowData, [firstElement, element]); } else { this.dispatchRowClickEvent(rowData, [element]); } }; element.onmouseenter = (): void => { this.dispatchRowHoverEvent(rowData, [element]); }; // @ts-ignore (element as unknown).data = rowData.data; //@ts-ignore if (rowData.data.isSelected !== undefined) { //@ts-ignore this.setSelectedRow(rowData.data.isSelected, [element]); } else { this.setSelectedRow(false, [element]); } //@ts-ignore if (rowData.data.isHover !== undefined) { //@ts-ignore this.setMouseIn(rowData.data.isHover, [element]); } else { this.setMouseIn(false, [element]); } if (this.getItemTextColor) { // @ts-ignore element.style.color = this.getItemTextColor((element as unknown).data); } } setSelectedRow(isSelected: boolean, rows: unknown[]): void { if (isSelected) { rows.forEach((row) => { // @ts-ignore if (row.classList.contains('mouse-in')) { // @ts-ignore row.classList.remove('mouse-in'); } // @ts-ignore row.classList.add('mouse-select'); }); } else { rows.forEach((row) => { // @ts-ignore row.classList.remove('mouse-select'); }); } } setMouseIn(isMouseIn: boolean, rows: unknown[]): void { if (isMouseIn) { rows.forEach((row) => { // @ts-ignore row.classList.add('mouse-in'); }); } else { rows.forEach((row) => { // @ts-ignore row.classList.remove('mouse-in'); }); } } scrollToData(data: unknown): void { if (this.recycleDs.length > 0) { let filter = this.recycleDs.filter((item) => { // @ts-ignore return item.data === data; }); if (filter.length > 0) { // @ts-ignore this.tableElement!.scrollTop = filter[0].top; } this.setCurrentSelection(data); } } expandList(datasource: unknown[]): void { let source = this.recycleDs.filter((item) => { // @ts-ignore return datasource.indexOf(item.data) !== -1; }); if (source.length > 0) { source.forEach((item) => { // @ts-ignore item.expanded = true; // @ts-ignore item.rowHidden = false; }); } this.reMeauseHeight(); } clearAllSelection(rowObjectData: unknown = undefined): void { this.recycleDs.forEach((item) => { // @ts-ignore if (rowObjectData || (item.data !== rowObjectData && item.data.isSelected)) { // @ts-ignore item.data.isSelected = false; } }); this.setSelectedRow(false, this.currentTreeDivList); this.setSelectedRow(false, this.currentRecycleList); } clearAllHover(rowObjectData: unknown): void { this.recycleDs.forEach((item) => { // @ts-ignore if (item.data !== rowObjectData && item.data.isHover) { // @ts-ignore item.data.isHover = false; } }); this.setMouseIn(false, this.currentTreeDivList); this.setMouseIn(false, this.currentRecycleList); } mouseOut(): void { // @ts-ignore this.recycleDs.forEach((item) => (item.data.isHover = false)); this.setMouseIn(false, this.currentTreeDivList); this.setMouseIn(false, this.currentRecycleList); this.dispatchEvent( new CustomEvent('row-hover', { detail: { data: undefined, }, composed: true, }) ); } setCurrentSelection(data: unknown): void { // @ts-ignore if (data.isSelected !== undefined) { this.currentTreeDivList.forEach((item) => { // @ts-ignore if ((item as unknown).data === data) { // @ts-ignore this.setSelectedRow(data.isSelected, [item]); } }); this.currentRecycleList.forEach((item) => { // @ts-ignore if ((item as unknown).data === data) { // @ts-ignore this.setSelectedRow(data.isSelected, [item]); } }); } } setCurrentHover(data: unknown): void { this.setMouseIn(false, this.currentTreeDivList); this.setMouseIn(false, this.currentRecycleList); // @ts-ignore if (data.isHover !== undefined) { this.currentTreeDivList.forEach((item) => { // @ts-ignore if ((item as unknown).data === data) { // @ts-ignore this.setMouseIn(data.isHover, [item]); } }); this.currentRecycleList.forEach((item) => { // @ts-ignore if ((item as unknown).data === data) { // @ts-ignore this.setMouseIn(data.isHover, [item]); } }); } } dispatchRowClickEventIcon(rowObject: unknown, elements: unknown[]): void { this.dispatchEvent( new CustomEvent('icon-click', { detail: { // @ts-ignore ...rowObject.data, // @ts-ignore data: rowObject.data, callBack: (isSelected: boolean): void => { //是否爲单选 if (isSelected) { // @ts-ignore this.clearAllSelection(rowObject.data); } // @ts-ignore this.setSelectedRow(rowObject.data.isSelected, elements); }, }, composed: true, }) ); } dispatchRowClickEvent(rowObject: unknown, elements: unknown[]): void { this.dispatchEvent( new CustomEvent('row-click', { detail: { // @ts-ignore ...rowObject.data, // @ts-ignore data: rowObject.data, callBack: (isSelected: boolean): void => { //是否爲单选 if (isSelected) { // @ts-ignore this.clearAllSelection(rowObject.data); } // @ts-ignore rowObject.data.isSelected = true; // @ts-ignore this.setSelectedRow(rowObject.data.isSelected, elements); }, }, composed: true, }) ); } dispatchRowHoverEvent(rowObject: unknown, elements: unknown[]): void { this.dispatchEvent( new CustomEvent('row-hover', { detail: { // @ts-ignore data: rowObject.data, callBack: (): void => { // @ts-ignore this.clearAllHover(rowObject.data); // @ts-ignore this.setMouseIn(rowObject.data.isHover, elements); }, }, composed: true, }) ); } setHighLight(isSearch: boolean, element: unknown): void { if (isSearch) { // @ts-ignore element.setAttribute('high-light', ''); } else { // @ts-ignore element.removeAttribute('high-light'); } } } if (!customElements.get('lit-page-table')) { customElements.define('lit-page-table', LitPageTable); }