1/* 2 * Copyright (C) 2022 Huawei Device Co., Ltd. 3 * Licensed under the Apache License, Version 2.0 (the "License"); 4 * you may not use this file except in compliance with the License. 5 * You may obtain a copy of the License at 6 * 7 * http://www.apache.org/licenses/LICENSE-2.0 8 * 9 * Unless required by applicable law or agreed to in writing, software 10 * distributed under the License is distributed on an "AS IS" BASIS, 11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 * See the License for the specific language governing permissions and 13 * limitations under the License. 14 */ 15 16import { LitTableColumn } from './lit-table-column'; 17import { LitProgressBar } from './../progress-bar/LitProgressBar'; 18import { element } from '../BaseElement'; 19import '../utils/Template'; 20import { TableRowObject } from './TableRowObject'; 21import { ExcelFormater } from '../utils/ExcelFormater'; 22import { LitIcon } from '../icon/LitIcon'; 23import { NodeType } from '../../js-heap/model/DatabaseStruct'; 24import { ConstructorType } from '../../js-heap/model/UiStruct'; 25import { JsCpuProfilerStatisticsStruct } from '../../trace/bean/JsStruct'; 26import { 27 iconPadding, 28 iconWidth, 29 createDownUpSvg, 30 litTableHtml, 31 exportData, 32 formatExportData, 33 recursionExportTableData, 34 addCopyEventListener, 35 addSelectAllBox, 36 fixed, 37 formatName, 38} from './LitTableHtml'; 39 40@element('lit-table') 41export class LitTable extends HTMLElement { 42 meauseRowElement: HTMLDivElement | undefined; 43 currentRecycleList: HTMLDivElement[] = []; 44 currentTreeDivList: HTMLDivElement[] = []; 45 public rememberScrollTop = false; 46 public getItemTextColor?: (data: unknown) => string; 47 public itemTextHandleMap: Map<string, (value: unknown) => string> = new Map<string, (value: unknown) => string>(); 48 public exportTextHandleMap: Map<string, (value: unknown) => string> = new Map<string, (value: unknown) => string>(); 49 public ds: Array<unknown> = []; 50 public recycleDs: Array<unknown> = []; 51 public gridTemplateColumns: Array<string> = []; 52 public tableColumns: NodeListOf<LitTableColumn> | undefined; 53 public treeElement: HTMLDivElement | undefined | null; 54 public columns: Array<Element> | null | undefined; 55 public exportLoading: boolean = false; 56 public exportProgress: LitProgressBar | null | undefined; 57 public tableElement: HTMLDivElement | null | undefined; 58 private normalDs: Array<unknown> = []; 59 /*Grid css layout descriptions are obtained according to the clustern[] nested structure*/ 60 private st: HTMLSlotElement | null | undefined; 61 private theadElement: HTMLDivElement | null | undefined; 62 private tbodyElement: HTMLDivElement | undefined | null; 63 private colCount: number = 0; 64 private isRecycleList: boolean = true; 65 private isScrollXOutSide: boolean = false; 66 private value: Array<unknown> = []; 67 private _mode = TableMode.Expand; 68 private columnResizeEnable: boolean = true; 69 private _isSearch: boolean = false; 70 private maxLength: number = 0; 71 72 constructor() { 73 super(); 74 const shadowRoot = this.attachShadow({ mode: 'open' }); 75 shadowRoot.innerHTML = litTableHtml; 76 } 77 78 static get observedAttributes(): string[] { 79 return [ 80 'scroll-y', 81 'selectable', 82 'no-head', 83 'grid-line', 84 'defaultOrderColumn', 85 'hideDownload', 86 'noRecycle', 87 'loading', 88 'expand', 89 ]; 90 } 91 92 set mode(mode: TableMode) { 93 this._mode = mode; 94 } 95 96 set loading(value: boolean) { 97 this.exportProgress!.loading = value; 98 } 99 100 get hideDownload(): boolean { 101 return this.hasAttribute('hideDownload'); 102 } 103 104 set hideDownload(value) { 105 if (value) { 106 this.setAttribute('hideDownload', ''); 107 } else { 108 this.removeAttribute('hideDownload'); 109 } 110 } 111 112 get selectable(): boolean { 113 return this.hasAttribute('selectable'); 114 } 115 116 set selectable(value) { 117 if (value) { 118 this.setAttribute('selectable', ''); 119 } else { 120 this.removeAttribute('selectable'); 121 } 122 } 123 124 get scrollY(): string { 125 return this.getAttribute('scroll-y') || 'auto'; 126 } 127 128 set scrollY(value) { 129 this.setAttribute('scroll-y', value); 130 } 131 132 get dataSource(): unknown[] { 133 return this.ds || []; 134 } 135 136 set dataSource(value) { 137 if (this.hasAttribute('noRecycle')) { 138 this.ds = value; 139 this.isRecycleList = false; 140 this.renderTable(); 141 } else { 142 this.columnResizeEnable = false; 143 this.recycleDataSource = value; 144 } 145 } 146 147 set noRecycle(value) { 148 if (value) { 149 this.setAttribute('noRecycle', ''); 150 } else { 151 this.removeAttribute('noRecycle'); 152 } 153 } 154 155 get noRecycle(): boolean { 156 return this.hasAttribute('noRecycle'); 157 } 158 159 get recycleDataSource(): unknown[] { 160 return this.ds || []; 161 } 162 163 set isSearch(value: boolean) { 164 this._isSearch = value; 165 } 166 167 set recycleDataSource(value) { 168 // 处理数据按小数点位置对齐 169 if (value && value.length) { 170 // 找出数字部分的最大长度 171 value.forEach((item: unknown) => { 172 // 提取数字部分(包括小数点) 173 // @ts-ignore 174 if (item.durFormat) { 175 // @ts-ignore 176 const match = item.durFormat.match(/^(\d+(\.\d+)?)/); 177 if (match && match[1]) { 178 // 计算长度(包括小数点) 179 const length = match[1].length; 180 this.maxLength = Math.max(this.maxLength, length); 181 } 182 } 183 // @ts-ignore 184 if (item.percent) { 185 // @ts-ignore 186 const match = String(item.percent).match(/^(\d+(\.\d+)?)/); 187 if (match && match[1]) { 188 const length = match[1].length; 189 this.maxLength = Math.max(this.maxLength, length); 190 } 191 } 192 }); 193 } 194 if (this.tableElement) { 195 this.isScrollXOutSide = this.tableElement!.scrollWidth > this.tableElement!.clientWidth; 196 this.isRecycleList = true; 197 this.ds = value; 198 if (this.rememberScrollTop) { 199 this.tableElement!.scrollTop = 0; 200 this.tableElement!.scrollLeft = 0; 201 } else { 202 this.tableElement!.scrollTop = 0; 203 } 204 if (this.hasAttribute('tree') && this.querySelector('lit-table-column')?.hasAttribute('retract')) { 205 if ((value.length === 0 || this.value.length !== 0) && value !== this.value && !this._isSearch) { 206 if (this.shadowRoot!.querySelector<LitIcon>('.top')) { 207 this.shadowRoot!.querySelector<LitIcon>('.top')!.name = 'up'; 208 } 209 if (this.shadowRoot!.querySelector<LitIcon>('.bottom')) { 210 this.shadowRoot!.querySelector<LitIcon>('.bottom')!.name = 'down'; 211 } 212 } 213 this.value = value; 214 this._isSearch = false; 215 this.recycleDs = this.meauseTreeRowElement(value, RedrawTreeForm.Retract); 216 } else { 217 this.recycleDs = this.meauseAllRowHeight(value); 218 } 219 } 220 } 221 222 get snapshotDataSource(): unknown[] { 223 return this.ds || []; 224 } 225 226 set snapshotDataSource(value) { 227 this.ds = value; 228 if (this.hasAttribute('tree')) { 229 this.recycleDs = this.meauseTreeRowElement(value, RedrawTreeForm.Default); 230 } else { 231 this.recycleDs = this.meauseAllRowHeight(value); 232 } 233 } 234 235 move1px(): void { 236 this.tableElement!.scrollTop = this.tableElement!.scrollTop + 1; 237 } 238 239 dataExportInit(): void { 240 let exportDiv = this.shadowRoot!.querySelector<HTMLDivElement>('.export'); 241 exportDiv && 242 (exportDiv.onclick = (): void => { 243 this.exportData(); 244 }); 245 } 246 247 exportData(): void { 248 exportData(this); 249 } 250 251 exportExcelData(): void { 252 let now = Date.now(); 253 ExcelFormater.testExport( 254 [ 255 { 256 columns: this.columns as unknown[], 257 tables: this.ds, 258 sheetName: `${now}`, 259 }, 260 ], 261 `${now}` 262 ); 263 } 264 265 formatExportData(dataSource: unknown[]): unknown[] { 266 return formatExportData(dataSource, this); 267 } 268 269 formatExportCsvData(dataSource: unknown[]): string { 270 if (dataSource === undefined || dataSource.length === 0) { 271 return ''; 272 } 273 if (this.columns === undefined) { 274 return ''; 275 } 276 let str = ''; 277 str += this.columns!.map((column) => { 278 let dataIndex = column.getAttribute('data-index'); 279 let columnName = column.getAttribute('title'); 280 if (columnName === '') { 281 columnName = dataIndex; 282 } 283 return columnName; 284 }).join(','); 285 str += recursionExportTableData(this.columns || [], dataSource); 286 return str; 287 } 288 289 injectColumns(): void { 290 this.columns = this.st!.assignedElements(); 291 this.columns.forEach((column) => { 292 if (column.tagName === 'LIT-TABLE-COLUMN') { 293 this.gridTemplateColumns.push(column.getAttribute('width') || '1fr'); 294 } 295 }); 296 } 297 /** 298 * 设置表格每条数据的展开/收起状态 299 * @param list 表格数据 300 * @param status 展开/收起状态 301 * @param depth 展开深度,用来实现和图标的联动 302 * @param profundity 展开深度,用来实现逐级展开 303 */ 304 public setStatus(list: unknown, status: boolean, depth: number = 0, profundity?: number): void { 305 this.tableElement!.scrollTop = 0; 306 // 添加depth参数,让切换图标的代码在递归中只走一遍 307 if (depth === 0) { 308 if (status) { 309 this.shadowRoot!.querySelector<LitIcon>('.top')!.name = 'down'; 310 this.shadowRoot!.querySelector<LitIcon>('.bottom')!.name = 'up'; 311 } else { 312 this.shadowRoot!.querySelector<LitIcon>('.top')!.name = 'up'; 313 this.shadowRoot!.querySelector<LitIcon>('.bottom')!.name = 'down'; 314 } 315 } // @ts-ignore 316 for (let item of list) { 317 if (profundity) { 318 if (depth < profundity) { 319 item.status = true; 320 status = true; 321 } else { 322 item.status = false; 323 status = false; 324 } 325 } else { 326 item.status = status; 327 } 328 if (item.children !== undefined && item.children.length > 0) { 329 this.setStatus(item.children, status, depth + 1, profundity); 330 } 331 } 332 } 333 334 //当 custom element首次被插入文档DOM时,被调用。 335 connectedCallback(): void { 336 this.st = this.shadowRoot?.querySelector('#slot'); 337 this.tableElement = this.shadowRoot?.querySelector('.table'); 338 this.exportProgress = this.shadowRoot?.querySelector('#export_progress_bar'); 339 this.theadElement = this.shadowRoot?.querySelector('.thead'); 340 this.treeElement = this.shadowRoot?.querySelector('.tree'); 341 this.tbodyElement = this.shadowRoot?.querySelector('.body'); 342 this.tableColumns = this.querySelectorAll<LitTableColumn>('lit-table-column'); 343 this.colCount = this.tableColumns!.length; 344 this.dataExportInit(); 345 addCopyEventListener(this); 346 this.st?.addEventListener('slotchange', () => { 347 this.theadElement!.innerHTML = ''; 348 setTimeout(() => { 349 this.columns = this.st!.assignedElements(); 350 let rowElement = document.createElement('div'); 351 rowElement.classList.add('th'); 352 addSelectAllBox(rowElement, this); 353 let area: Array<unknown> = []; 354 this.gridTemplateColumns = []; 355 this.resolvingArea(this.columns, 0, 0, area, rowElement); 356 area.forEach((rows, j, array) => { 357 for (let i = 0; i < this.colCount; i++) { 358 // @ts-ignore 359 if (!rows[i]) { 360 // @ts-ignore 361 rows[i] = array[j - 1][i]; 362 } 363 } 364 }); 365 if (this.selectable) { 366 // @ts-ignore 367 let s = area.map((a) => '"_checkbox_ ' + a.map((aa: unknown) => aa.t).join(' ') + '"').join(' '); 368 rowElement.style.gridTemplateColumns = '60px ' + this.gridTemplateColumns.join(' '); 369 rowElement.style.gridTemplateRows = `repeat(${area.length},1fr)`; 370 rowElement.style.gridTemplateAreas = s; 371 } else { 372 // @ts-ignore 373 let s = area.map((a) => '"' + a.map((aa: unknown) => aa.t).join(' ') + '"').join(' '); 374 rowElement.style.gridTemplateColumns = this.gridTemplateColumns.join(' '); 375 rowElement.style.gridTemplateRows = `repeat(${area.length},1fr)`; 376 rowElement.style.gridTemplateAreas = s; 377 } 378 this.theadElement!.innerHTML = ''; 379 this.theadElement!.append(rowElement); 380 }); 381 }); 382 this.shadowRoot!.addEventListener('load', function (event) { }); 383 this.tableElement!.addEventListener('mouseout', (ev) => this.mouseOut()); 384 this.treeElement && (this.treeElement!.style.transform = 'translateY(0px)'); 385 this.tbodyElement && (this.tbodyElement!.style.transform = 'translateY(0px)'); 386 } 387 388 resolvingArea(columns: unknown, x: unknown, y: unknown, area: Array<unknown>, rowElement: HTMLDivElement): void { 389 // @ts-ignore 390 columns.forEach((a: unknown, i: unknown) => { 391 // @ts-ignore 392 if (!area[y]) { 393 // @ts-ignore 394 area[y] = []; 395 } // @ts-ignore 396 let key = a.getAttribute('key') || a.getAttribute('title'); // @ts-ignore 397 if (a.tagName === 'LIT-TABLE-GROUP') { 398 // @ts-ignore 399 let len = a.querySelectorAll('lit-table-column').length; // @ts-ignore 400 let children = [...a.children].filter((a) => a.tagName !== 'TEMPLATE'); 401 if (children.length > 0) { 402 // @ts-ignore 403 this.resolvingArea(children, x, y + 1, area, rowElement); 404 } 405 for (let j = 0; j < len; j++) { 406 // @ts-ignore 407 area[y][x] = { x, y, t: key }; // @ts-ignore 408 x++; 409 } 410 let h = document.createElement('div'); 411 h.classList.add('td'); // @ts-ignore 412 h.style.justifyContent = a.getAttribute('align'); 413 h.style.borderBottom = '1px solid #f0f0f0'; 414 h.style.gridArea = key; // @ts-ignore 415 h.innerText = a.title; // @ts-ignore 416 if (a.hasAttribute('fixed')) { 417 // @ts-ignore 418 fixed(h, a.getAttribute('fixed'), '#42b983'); 419 } 420 rowElement.append(h); // @ts-ignore 421 } else if (a.tagName === 'LIT-TABLE-COLUMN') { 422 // @ts-ignore 423 area[y][x] = { x, y, t: key }; // @ts-ignore 424 x++; // @ts-ignore 425 let head = this.resolvingAreaColumn(rowElement, a, i, key); // @ts-ignore 426 this.gridTemplateColumns.push(a.getAttribute('width') || '1fr'); // @ts-ignore 427 let labelArr = a.title.split('/'); 428 for (let i = 0; i < labelArr.length; i++) { 429 let titleLabel = document.createElement('label'); 430 titleLabel.style.cursor = 'pointer'; 431 i === 0 ? (titleLabel.textContent = labelArr[i]) : (titleLabel.textContent = '/' + labelArr[i]); 432 head.appendChild(titleLabel); 433 } // @ts-ignore 434 if (a.hasAttribute('fixed')) { 435 // @ts-ignore 436 fixed(head, a.getAttribute('fixed'), '#42b983'); 437 } 438 rowElement.append(head); 439 } 440 }); 441 } 442 443 resolvingAreaColumn(rowElement: HTMLDivElement, column: unknown, index: number, key: string): HTMLDivElement { 444 let head: unknown = document.createElement('div'); // @ts-ignore 445 head.classList.add('td'); 446 if ((this.hasAttribute('tree') && index > 1) || (!this.hasAttribute('tree') && index > 0)) { 447 let resizeDiv: HTMLDivElement = document.createElement('div'); 448 resizeDiv.classList.add('resize'); // @ts-ignore 449 head.appendChild(resizeDiv); 450 this.resizeEventHandler(rowElement, resizeDiv, index); 451 } // @ts-ignore 452 this.resolvingAreaColumnRetract(column, head); 453 this.resolvingAreaColumnOrder(column, index, key, head); // @ts-ignore 454 this.resolvingAreaColumnButton(column, key, head); // @ts-ignore 455 head.style.justifyContent = column.getAttribute('align'); // @ts-ignore 456 head.style.gridArea = key; // @ts-ignore 457 return head; 458 } 459 460 resolvingAreaColumnRetract(column: unknown, columnHead: HTMLDivElement): void { 461 // @ts-ignore 462 if (column.hasAttribute('retract')) { 463 let expand = document.createElement('div'); 464 expand.classList.add('expand'); 465 expand.style.display = 'grid'; 466 columnHead.append(expand); 467 let top = document.createElement('lit-icon') as LitIcon; 468 top.classList.add('top'); 469 top.name = 'up'; 470 expand.append(top); 471 let bottom = document.createElement('lit-icon') as LitIcon; 472 bottom.classList.add('bottom'); 473 bottom.name = 'down'; 474 expand.append(bottom); 475 expand.addEventListener('click', (e) => { 476 if (top.name === 'up' && bottom.name === 'down') { 477 top.name = 'down'; 478 bottom.name = 'up'; 479 // 一键展开 480 this.setStatus(this.value, true); 481 this.recycleDs = this.meauseTreeRowElement(this.value, RedrawTreeForm.Expand); 482 } else { 483 top.name = 'up'; 484 bottom.name = 'down'; 485 // 一键收起 486 this.setStatus(this.value, false); 487 this.recycleDs = this.meauseTreeRowElement(this.value, RedrawTreeForm.Retract); 488 } 489 e.stopPropagation(); 490 }); 491 } 492 } 493 494 resolvingAreaColumnButton(column: unknown, key: string, head: HTMLDivElement): void { 495 // @ts-ignore 496 if (column.hasAttribute('button')) { 497 let buttonIcon = document.createElement('button'); 498 buttonIcon.innerHTML = 'GetBusyTime(ms)'; 499 buttonIcon.classList.add('button-icon'); 500 head.appendChild(buttonIcon); 501 buttonIcon.addEventListener('click', (event) => { 502 this.dispatchEvent( 503 new CustomEvent('button-click', { 504 detail: { 505 key: key, 506 }, 507 composed: true, 508 }) 509 ); 510 event.stopPropagation(); 511 }); 512 } 513 } 514 515 resolvingAreaColumnOrder(column: unknown, index: number, key: string, columnHead: unknown): void { 516 // @ts-ignore 517 if (column.hasAttribute('order')) { 518 // @ts-ignore 519 (columnHead as unknown).sortType = 0; // @ts-ignore 520 columnHead.classList.add('td-order'); // @ts-ignore 521 columnHead.style.position = 'relative'; // @ts-ignore 522 let { upSvg, downSvg } = createDownUpSvg(index, columnHead); // @ts-ignore 523 columnHead.onclick = (): void => { 524 if (this.isResize || this.resizeColumnIndex !== -1) { 525 return; 526 } 527 this?.shadowRoot?.querySelectorAll('.td-order svg').forEach((it: unknown) => { 528 // @ts-ignore 529 it.setAttribute('fill', 'let(--dark-color1,#212121)'); // @ts-ignore 530 it.sortType = 0; // @ts-ignore 531 it.style.display = 'none'; 532 }); // @ts-ignore 533 if (columnHead.sortType === undefined || columnHead.sortType === null) { 534 // @ts-ignore 535 columnHead.sortType = 0; // @ts-ignore 536 } else if (columnHead.sortType === 2) { 537 // @ts-ignore 538 columnHead.sortType = 0; 539 } else { 540 // @ts-ignore 541 columnHead.sortType += 1; 542 } 543 upSvg.setAttribute('fill', 'let(--dark-color1,#212121)'); 544 downSvg.setAttribute('fill', 'let(--dark-color1,#212121)'); // @ts-ignore 545 upSvg.style.display = columnHead.sortType === 1 ? 'block' : 'none'; // @ts-ignore 546 downSvg.style.display = columnHead.sortType === 2 ? 'block' : 'none'; // @ts-ignore 547 switch (columnHead.sortType) { 548 case 1: 549 this.theadElement!.setAttribute('sort', ''); 550 break; 551 case 2: 552 break; 553 default: 554 this.theadElement!.removeAttribute('sort'); 555 break; 556 } 557 this.dispatchEvent( 558 new CustomEvent('column-click', { 559 detail: { 560 // @ts-ignore 561 sort: columnHead.sortType, 562 key: key, 563 }, 564 composed: true, 565 }) 566 ); 567 }; 568 } 569 } 570 571 private isResize: boolean = false; 572 private resizeColumnIndex: number = -1; 573 private resizeDownX: number = 0; 574 private columnMinWidth: number = 50; 575 private beforeResizeWidth: number = 0; 576 577 resizeEventHandler(header: HTMLDivElement, element: HTMLDivElement, index: number): void { 578 this.resizeMouseMoveEventHandler(header); 579 header.addEventListener('mouseup', (event) => { 580 if (!this.columnResizeEnable) { 581 return; 582 } 583 this.isResize = false; 584 this.resizeDownX = 0; 585 header.style.cursor = 'pointer'; 586 setTimeout(() => { 587 this.resizeColumnIndex = -1; 588 }, 100); 589 event.stopPropagation(); 590 event.preventDefault(); 591 }); 592 header.addEventListener('mouseleave', (event) => { 593 if (!this.columnResizeEnable) { 594 return; 595 } 596 event.stopPropagation(); 597 event.preventDefault(); 598 this.isResize = false; 599 this.resizeDownX = 0; 600 this.resizeColumnIndex = -1; 601 header.style.cursor = 'pointer'; 602 }); 603 element.addEventListener('mousedown', (event) => { 604 if (event.button === 0) { 605 if (!this.columnResizeEnable) { 606 return; 607 } 608 this.isResize = true; 609 this.resizeColumnIndex = index; 610 this.resizeDownX = event.clientX; 611 let pre = header.childNodes.item(this.resizeColumnIndex - 1) as HTMLDivElement; 612 this.beforeResizeWidth = pre.clientWidth; 613 event.stopPropagation(); 614 } 615 }); 616 element.addEventListener('click', (event) => { 617 event.stopPropagation(); 618 }); 619 } 620 621 resizeMouseMoveEventHandler(header: HTMLDivElement): void { 622 header.addEventListener('mousemove', (event) => { 623 if (!this.columnResizeEnable) { 624 return; 625 } 626 if (this.isResize) { 627 let width = event.clientX - this.resizeDownX; 628 header.style.cursor = 'col-resize'; 629 let preWidth = Math.max(this.beforeResizeWidth + width, this.columnMinWidth); 630 this.gridTemplateColumns[header.childNodes.length - 1] = '1fr'; 631 for (let i = 0; i < header.childNodes.length; i++) { 632 let node = header.childNodes.item(i) as HTMLDivElement; 633 this.gridTemplateColumns[i] = `${node.clientWidth}px`; 634 } 635 this.gridTemplateColumns[this.resizeColumnIndex - 1] = `${preWidth}px`; 636 let lastNode = header.childNodes.item(header.childNodes.length - 1) as HTMLDivElement; 637 let totalWidth = 0; 638 this.gridTemplateColumns.forEach((it) => { 639 totalWidth += parseInt(it); 640 }); 641 totalWidth = Math.max(totalWidth, this.shadowRoot!.querySelector<HTMLDivElement>('.table')!.scrollWidth); 642 this.gridTemplateColumns[this.gridTemplateColumns.length - 1] = `${totalWidth - lastNode.offsetLeft}px`; 643 header.style.gridTemplateColumns = this.gridTemplateColumns.join(' '); 644 let preNode = header.childNodes.item(this.resizeColumnIndex - 1) as HTMLDivElement; 645 preNode.style.width = `${preWidth}px`; 646 this.shadowRoot!.querySelectorAll<HTMLDivElement>('.tr').forEach((tr) => { 647 if (this.hasAttribute('tree')) { 648 tr.style.gridTemplateColumns = this.gridTemplateColumns.slice(1).join(' '); 649 } else { 650 tr.style.gridTemplateColumns = this.gridTemplateColumns.join(' '); 651 } 652 }); 653 event.preventDefault(); 654 event.stopPropagation(); 655 } else { 656 header.style.cursor = 'pointer'; 657 } 658 }); 659 } 660 661 adoptedCallback(): void { } 662 663 getCheckRows(): unknown[] { 664 // @ts-ignore 665 return [...this.shadowRoot!.querySelectorAll('div[class=tr][checked]')] // @ts-ignore 666 .map((a) => (a as unknown).data) 667 .map((a) => { 668 if ('children' in a) { 669 Reflect.deleteProperty(a, 'chlidren'); 670 } 671 return a; 672 }); 673 } 674 675 deleteRowsCondition(fn: unknown): void { 676 this.shadowRoot!.querySelectorAll('div[class=tr]').forEach((tr) => { 677 // @ts-ignore 678 if (fn(tr.data)) { 679 tr.remove(); 680 } 681 }); 682 } 683 684 meauseElementHeight(rowData: unknown): number { 685 return 27; 686 } 687 688 meauseTreeElementHeight(rowData: unknown, depth: number): number { 689 return 27; 690 } 691 692 getVisibleObjects(list: unknown[]): { visibleObjects: TableRowObject[]; totalHeight: number } { 693 let headHeight = 0; 694 let totalHeight = headHeight; 695 let visibleObjects: TableRowObject[] = []; 696 let itemHandler = (rowData: unknown, index: number): void => { 697 let height = this.meauseElementHeight(rowData); 698 let tableRowObject = new TableRowObject(); 699 tableRowObject.height = height; 700 tableRowObject.top = totalHeight; 701 tableRowObject.data = rowData; 702 tableRowObject.rowIndex = index; 703 if ( 704 Math.max(totalHeight, this.tableElement!.scrollTop + headHeight) <= 705 Math.min(totalHeight + height, this.tableElement!.scrollTop + this.tableElement!.clientHeight + headHeight) 706 ) { 707 let newTableElement = this.addTableElement(tableRowObject, false, false, true, totalHeight); 708 let td = newTableElement?.querySelectorAll('.td'); //@ts-ignore 709 if (tableRowObject.data.rowName === 'cpu-profiler') { 710 td[0].innerHTML = ''; 711 this.createTextColor(tableRowObject, td[0]); 712 } 713 } 714 totalHeight += height; 715 visibleObjects.push(tableRowObject); 716 }; 717 let realIndex = 0; 718 list.forEach((item, index) => { 719 if (Array.isArray(item)) { 720 item.forEach((rowData, childIndex) => { 721 itemHandler(rowData, realIndex); 722 realIndex++; 723 }); 724 } else { 725 itemHandler(item, index); 726 } 727 }); 728 return { visibleObjects, totalHeight }; 729 } 730 731 meauseAllRowHeight(list: unknown[]): TableRowObject[] { 732 this.tbodyElement!.innerHTML = ''; 733 this.meauseRowElement = undefined; 734 let head = this.shadowRoot!.querySelector('.th'); 735 this.tbodyElement && (this.tbodyElement.style.width = head?.clientWidth + 'px'); 736 this.currentRecycleList = []; 737 let { visibleObjects, totalHeight } = this.getVisibleObjects(list); 738 this.tbodyElement && (this.tbodyElement.style.height = totalHeight + (this.isScrollXOutSide ? 0 : 0) + 'px'); 739 this.tableElement && 740 (this.tableElement.onscroll = (event): void => { 741 let tblScrollTop = this.tableElement!.scrollTop; 742 let skip = 0; 743 for (let i = 0; i < visibleObjects.length; i++) { 744 if ( 745 visibleObjects[i].top <= tblScrollTop && 746 visibleObjects[i].top + visibleObjects[i].height >= tblScrollTop 747 ) { 748 skip = i; 749 break; 750 } 751 } 752 let reduce = this.currentRecycleList.map((item) => item.clientHeight).reduce((a, b) => a + b, 0); 753 if (reduce === 0) { 754 return; 755 } 756 while (reduce <= this.tableElement!.clientHeight) { 757 let newTableElement = this.addTableElement(visibleObjects[skip], false, false, false); 758 reduce += newTableElement.clientHeight; 759 } 760 for (let i = 0; i < this.currentRecycleList.length; i++) { 761 this.freshLineHandler(i, skip, visibleObjects); 762 } 763 }); 764 return visibleObjects; 765 } 766 767 freshLineHandler(index: number, skip: number, visibleObjects: TableRowObject[]): void { 768 this.freshCurrentLine(this.currentRecycleList[index], visibleObjects[index + skip]); 769 if (visibleObjects[index + skip]) { 770 //@ts-ignore 771 if (visibleObjects[index + skip].data.rowName === 'cpu-profiler') { 772 this.createTextColor(visibleObjects[index + skip], this.currentRecycleList[index].childNodes[0]); 773 } 774 } 775 } 776 777 newTableRowObject(item: unknown, totalHeight: number, depth: number, parentNode?: TableRowObject): TableRowObject { 778 let tableRowObject = new TableRowObject(); 779 tableRowObject.depth = depth; 780 tableRowObject.data = item; 781 tableRowObject.top = totalHeight; 782 tableRowObject.height = this.meauseTreeElementHeight(tableRowObject, depth); 783 if (parentNode) { 784 parentNode!.children.push(tableRowObject); 785 } 786 return tableRowObject; 787 } 788 789 resetAllHeight( 790 list: unknown[], 791 depth: number, 792 totalHeight: number, 793 visibleObjects: TableRowObject[], 794 parentNode?: TableRowObject, 795 form?: RedrawTreeForm 796 ): number { 797 let th = totalHeight; 798 let headHeight = this.theadElement?.clientHeight || 0; 799 list.forEach((item) => { 800 let tableRowObject = this.newTableRowObject(item, th, depth, parentNode); // @ts-ignore 801 if (this._mode === TableMode.Expand && form === RedrawTreeForm.Retract && !item.status) { 802 tableRowObject.expanded = false; 803 } else if (this._mode === TableMode.Expand && form === RedrawTreeForm.Default) { 804 tableRowObject.expanded = true; 805 } 806 if ( 807 // @ts-ignore 808 (this._mode === TableMode.Retract && !item.status) || // @ts-ignore 809 (this._mode === TableMode.Expand && !item.status && form !== RedrawTreeForm.Expand) 810 ) { 811 tableRowObject.expanded = false; // @ts-ignore 812 if (item.children !== undefined && item.children.length > 0) { 813 this.newTableRowObject(item, th, depth, tableRowObject); 814 } 815 } 816 if ( 817 Math.max(th, this.tableElement!.scrollTop) <= 818 Math.min( 819 th + tableRowObject.height, 820 this.tableElement!.scrollTop + this.tableElement!.clientHeight - headHeight 821 ) 822 ) { 823 this.addTableElement(tableRowObject, true, false, true, th); 824 } 825 th += tableRowObject.height; 826 visibleObjects.push(tableRowObject); 827 th = this.resetAllHeightChildrenHandler(item, depth, th, visibleObjects, tableRowObject, form); 828 }); 829 return th; 830 } 831 832 resetAllHeightChildrenHandler( 833 item: unknown, 834 depth: number, 835 totalHeight: number, 836 visibleObjects: TableRowObject[], 837 tableRowObject?: TableRowObject, 838 form?: RedrawTreeForm 839 ): number { 840 let th = totalHeight; // @ts-ignore 841 if (item.hasNext) { 842 // js memory的表格 843 // @ts-ignore 844 if (item.parents !== undefined && item.parents.length > 0 && item.status) { 845 // @ts-ignore 846 th = this.resetAllHeight(item.parents, depth + 1, totalHeight, visibleObjects, tableRowObject); // @ts-ignore 847 } else if (item.children !== undefined && item.children.length > 0 && item.status) { 848 // @ts-ignore 849 th = this.resetAllHeight(item.children, depth + 1, totalHeight, visibleObjects, tableRowObject); 850 } 851 } else { 852 // 其他数据 853 if ( 854 // @ts-ignore 855 item.children !== undefined && // @ts-ignore 856 item.children.length > 0 && 857 form === RedrawTreeForm.Expand && 858 this._mode === TableMode.Expand 859 ) { 860 // @ts-ignore 861 item.status = true; // @ts-ignore 862 th = this.resetAllHeight(item.children, depth + 1, totalHeight, visibleObjects, tableRowObject); // @ts-ignore 863 } else if (item.children !== undefined && item.children.length > 0 && item.status) { 864 // @ts-ignore 865 th = this.resetAllHeight(item.children, depth + 1, totalHeight, visibleObjects, tableRowObject); 866 } 867 } 868 return th; 869 } 870 871 measureReset(): void { 872 this.meauseRowElement = undefined; 873 this.tbodyElement!.innerHTML = ''; 874 this.treeElement!.innerHTML = ''; 875 this.currentRecycleList = []; 876 this.currentTreeDivList = []; 877 } 878 879 meauseTreeRowElement(list: unknown[], form?: RedrawTreeForm): TableRowObject[] { 880 this.measureReset(); 881 let visibleObjects: TableRowObject[] = []; 882 let totalHeight = 0; 883 totalHeight = this.resetAllHeight(list, 0, totalHeight, visibleObjects); 884 this.tbodyElement && (this.tbodyElement.style.height = totalHeight + 'px'); 885 this.treeElement!.style.height = this.tableElement!.clientHeight - this.theadElement!.clientHeight + 'px'; 886 this.tableElement && 887 (this.tableElement.onscroll = (event): void => { 888 let visibleObjects = this.recycleDs.filter((item) => { 889 // @ts-ignore 890 return !item.rowHidden; 891 }); 892 let top = this.tableElement!.scrollTop; 893 this.treeElement && (this.treeElement!.style.transform = `translateY(${top}px)`); 894 let skip = 0; 895 for (let index = 0; index < visibleObjects.length; index++) { 896 // @ts-ignore 897 if (visibleObjects[index].top <= top && visibleObjects[index].top + visibleObjects[index].height >= top) { 898 skip = index; 899 break; 900 } 901 } 902 // 如果滚动高度大于数据全部收起的高度,并且this.currentRecycleList数组长度为0要给this.currentRecycleList赋值,不然tab页没有数据 903 if ( 904 visibleObjects[0] && // @ts-ignore 905 this.tableElement!.scrollTop >= this.value.length * visibleObjects[0].height && 906 this.currentRecycleList.length === 0 907 ) { 908 // @ts-ignore 909 this.addTableElement(visibleObjects[skip], true, false, false); 910 } 911 let reduce = this.currentRecycleList.map((item) => item.clientHeight).reduce((a, b) => a + b, 0); 912 if (reduce === 0) { 913 return; 914 } 915 while (reduce <= this.tableElement!.clientHeight) { 916 // @ts-ignore 917 let newTableElement = this.addTableElement(visibleObjects[skip], true, false, false); 918 reduce += newTableElement.clientHeight; 919 } 920 for (let i = 0; i < this.currentRecycleList.length; i++) { 921 this.freshCurrentLine( 922 this.currentRecycleList[i], // @ts-ignore 923 visibleObjects[i + skip], 924 this.treeElement?.children[i] as HTMLElement 925 ); 926 } 927 }); 928 return visibleObjects; 929 } 930 931 private addTableElement( 932 rowData: TableRowObject, 933 isTree: boolean, 934 last: boolean, 935 translate: boolean, 936 totalHeight?: number 937 ): HTMLDivElement { 938 let newTableElement; 939 if (isTree) { 940 newTableElement = this.createNewTreeTableElement(rowData); 941 } else { 942 newTableElement = this.createNewTableElement(rowData); 943 } 944 if (translate) { 945 newTableElement.style.transform = `translateY(${totalHeight}px)`; 946 } 947 this.tbodyElement?.append(newTableElement); 948 if (last) { 949 if (this.hasAttribute('tree')) { 950 if (this.treeElement?.lastChild) { 951 (this.treeElement?.lastChild as HTMLElement).style.height = rowData.height + 'px'; 952 } 953 } 954 } 955 this.currentRecycleList.push(newTableElement); 956 return newTableElement; 957 } 958 959 createNewTreeTableElement(rowData: TableRowObject): HTMLDivElement { 960 let rowTreeElement = document.createElement('div'); 961 rowTreeElement.classList.add('tr'); 962 let treeTop = 0; 963 if (this.treeElement!.children?.length > 0) { 964 let transX = Number((this.treeElement?.lastChild as HTMLElement).style.transform.replace(/[^0-9]/gi, '')); 965 treeTop += transX + rowData.height; 966 } 967 this?.columns?.forEach((column: unknown, index) => { 968 // @ts-ignore 969 let dataIndex = column.getAttribute('data-index') || '1'; 970 let td: unknown; 971 if (index === 0) { 972 td = this.firstElementTdHandler(rowTreeElement, dataIndex, rowData, column); 973 } else { 974 td = this.otherElementHandler(dataIndex, rowData, column); // @ts-ignore 975 this.dispatchTdClickEvent(td, column, rowData);// @ts-ignore 976 rowTreeElement.append(td); 977 } 978 }); 979 let lastChild = this.treeElement?.lastChild as HTMLElement; 980 if (lastChild) { 981 lastChild.style.transform = `translateY(${treeTop}px)`; 982 } // @ts-ignore 983 (rowTreeElement as unknown).data = rowData.data; 984 rowTreeElement.style.gridTemplateColumns = this.gridTemplateColumns.slice(1).join(' '); 985 rowTreeElement.style.position = 'absolute'; 986 rowTreeElement.style.top = '0px'; 987 rowTreeElement.style.left = '0px'; 988 rowTreeElement.style.cursor = 'pointer'; //@ts-ignore 989 this.setHighLight(rowData.data.isSearch, rowTreeElement); 990 this.addRowElementEvent(rowTreeElement, rowData); 991 return rowTreeElement; 992 } 993 994 addRowElementEvent(rowTreeElement: HTMLDivElement, rowData: unknown): void { 995 rowTreeElement.onmouseenter = (): void => { 996 // @ts-ignore 997 if ((rowTreeElement as unknown).data.isSelected) { 998 return; 999 } 1000 let indexOf = this.currentRecycleList.indexOf(rowTreeElement); 1001 this.currentTreeDivList.forEach((row) => { 1002 row.classList.remove('mouse-in'); 1003 }); 1004 if (indexOf >= 0 && indexOf < this.currentTreeDivList.length) { 1005 this.setMouseIn(true, [this.currentTreeDivList[indexOf]]); 1006 } 1007 }; 1008 rowTreeElement.onmouseleave = (): void => { 1009 // @ts-ignore 1010 if ((rowTreeElement as unknown).data.isSelected) { 1011 return; 1012 } 1013 let indexOf = this.currentRecycleList.indexOf(rowTreeElement); 1014 if (indexOf >= 0 && indexOf < this.treeElement!.children.length) { 1015 this.setMouseIn(false, [this.treeElement?.children[indexOf] as HTMLElement]); 1016 } 1017 }; 1018 rowTreeElement.onmouseup = (e: MouseEvent): void => { 1019 let indexOf = this.currentRecycleList.indexOf(rowTreeElement); 1020 this.dispatchRowClickEvent(rowData, [this.treeElement?.children[indexOf] as HTMLElement, rowTreeElement], e); 1021 e.stopPropagation(); 1022 }; 1023 } 1024 1025 firstElementTdHandler(tr: HTMLDivElement, dataIndex: string, row: unknown, column: unknown): HTMLElement { 1026 let td: unknown; // @ts-ignore 1027 let text = formatName(dataIndex, row.data[dataIndex], this); // @ts-ignore 1028 if (column.template) { 1029 // @ts-ignore 1030 td = column.template.render(row.data).content.cloneNode(true); // @ts-ignore 1031 td.template = column.template; // @ts-ignore 1032 td.title = row.data[dataIndex]; 1033 } else { 1034 td = document.createElement('div'); // @ts-ignore 1035 if (row.data.rowName === 'js-memory' || row.data.rowName === 'cpu-profiler') { 1036 // @ts-ignore 1037 td.innerHTML = ''; 1038 } else { 1039 // @ts-ignore 1040 td.innerHTML = text; 1041 } // @ts-ignore 1042 td.dataIndex = dataIndex; //@ts-ignore 1043 if (text.indexOf('<') === -1) { 1044 // @ts-ignore 1045 td.title = text; 1046 } 1047 } // @ts-ignore 1048 if (row.data.children && row.data.children.length > 0 && !row.data.hasNext) { 1049 let btn = this.createExpandBtn(row); // @ts-ignore 1050 td.insertBefore(btn, td.firstChild); 1051 } // @ts-ignore 1052 if (row.data.hasNext) { 1053 // @ts-ignore 1054 td.title = row.data.objectName; 1055 let btn = this.createBtn(row); // @ts-ignore 1056 td.insertBefore(btn, td.firstChild); 1057 } // @ts-ignore 1058 td.style.paddingLeft = row.depth * iconWidth + 'px'; // @ts-ignore 1059 if (!row.data.children || row.data.children.length === 0) { 1060 // @ts-ignore 1061 td.style.paddingLeft = iconWidth * row.depth + iconWidth + iconPadding * 2 + 'px'; 1062 } 1063 this.jsMemoryHandler(row, td); // @ts-ignore 1064 if (row.data.rowName === 'cpu-profiler') { 1065 this.createTextColor(row, td); 1066 } // @ts-ignore 1067 (td as unknown).data = row.data; // @ts-ignore 1068 td.classList.add('tree-first-body'); // @ts-ignore 1069 td.style.position = 'absolute'; // @ts-ignore 1070 td.style.top = '0px'; // @ts-ignore 1071 td.style.left = '0px'; // @ts-ignore 1072 td.style.height = `${row.height}px`; // @ts-ignore 1073 this.addFirstElementEvent(td, tr, row); // @ts-ignore 1074 this.setHighLight(row.data.isSearch, td); // @ts-ignore 1075 this.treeElement!.style.width = column.getAttribute('width'); // @ts-ignore 1076 this.treeElement?.append(td); // @ts-ignore 1077 this.currentTreeDivList.push(td); // @ts-ignore 1078 return td; 1079 } 1080 1081 addFirstElementEvent(td: HTMLDivElement, tr: HTMLDivElement, rowData: unknown): void { 1082 td.onmouseenter = (): void => { 1083 let indexOf = this.currentTreeDivList.indexOf(td); 1084 this.currentRecycleList.forEach((row) => { 1085 row.classList.remove('mouse-in'); 1086 }); 1087 if (indexOf >= 0 && indexOf < this.currentRecycleList.length && td.innerHTML !== '') { 1088 this.setMouseIn(true, [tr]); 1089 } 1090 }; 1091 td.onmouseleave = (): void => { 1092 let indexOf = this.currentTreeDivList.indexOf(td); 1093 if (indexOf >= 0 && indexOf < this.currentRecycleList.length) { 1094 this.setMouseIn(false, [tr]); 1095 } 1096 }; 1097 td.onmouseup = (e: MouseEvent): void => { 1098 let indexOf = this.currentTreeDivList.indexOf(td); 1099 this.dispatchRowClickEvent(rowData, [td, tr], e); 1100 e.stopPropagation(); 1101 }; 1102 } 1103 1104 otherElementHandler(dataIndex: string, rowData: unknown, column: unknown): HTMLDivElement { 1105 // @ts-ignore 1106 let tdDiv: unknown = document.createElement('div'); // @ts-ignore 1107 tdDiv.classList.add('td'); // @ts-ignore 1108 tdDiv.style.overflow = 'hidden'; // @ts-ignore 1109 tdDiv.style.textOverflow = 'ellipsis'; // @ts-ignore 1110 tdDiv.style.whiteSpace = 'nowrap'; // @ts-ignore 1111 let text = formatName(dataIndex, rowData.data[dataIndex], this); //@ts-ignore 1112 if (text.indexOf('<') === -1) { 1113 // @ts-ignore 1114 if (dataIndex === 'selfTimeStr' && rowData.data.chartFrameChildren) { 1115 // @ts-ignore 1116 tdDiv.title = rowData.data.selfTime + 'ns'; // @ts-ignore 1117 } else if (dataIndex === 'totalTimeStr' && rowData.data.chartFrameChildren) { 1118 // @ts-ignore 1119 tdDiv.title = rowData.data.totalTime + 'ns'; 1120 } else { 1121 // @ts-ignore 1122 tdDiv.title = text; 1123 } 1124 } // @ts-ignore 1125 tdDiv.dataIndex = dataIndex; // @ts-ignore 1126 tdDiv.style.justifyContent = column.getAttribute('align') || 'flex-start'; // @ts-ignore 1127 if (column.template) { 1128 // @ts-ignore 1129 tdDiv.appendChild(column.template.render(rowData.data).content.cloneNode(true)); // @ts-ignore 1130 tdDiv.template = column.template; 1131 } else { 1132 // @ts-ignore 1133 tdDiv.innerHTML = text; 1134 } // @ts-ignore 1135 return tdDiv; 1136 } 1137 1138 createNewTableElement(rowData: unknown): HTMLDivElement { 1139 let newTableElement = document.createElement('div'); 1140 newTableElement.classList.add('tr'); 1141 this?.columns?.forEach((column: unknown) => { 1142 // @ts-ignore 1143 let dataIndex = column.getAttribute('data-index') || '1'; 1144 let td = this.createColumnTd(dataIndex, column, rowData); 1145 //@ts-ignore 1146 this.dispatchTdClickEvent(td, column, rowData); 1147 newTableElement.append(td); 1148 }); 1149 newTableElement.onmouseup = (e: MouseEvent): void => { 1150 this.dispatchRowClickEvent(rowData, [newTableElement], e); 1151 e.stopPropagation(); 1152 }; 1153 newTableElement.onmouseenter = (): void => { 1154 this.dispatchRowHoverEvent(rowData, [newTableElement]); 1155 }; // @ts-ignore 1156 if (rowData.data.isSelected !== undefined) { 1157 // @ts-ignore 1158 this.setSelectedRow(rowData.data.isSelected, [newTableElement]); 1159 } // @ts-ignore 1160 (newTableElement as unknown).data = rowData.data; 1161 newTableElement.style.cursor = 'pointer'; 1162 newTableElement.style.gridTemplateColumns = this.gridTemplateColumns.join(' '); 1163 newTableElement.style.position = 'absolute'; 1164 newTableElement.style.top = '0px'; 1165 newTableElement.style.left = '0px'; 1166 if (this.getItemTextColor) { 1167 // @ts-ignore 1168 newTableElement.style.color = this.getItemTextColor(rowData.data); 1169 } 1170 return newTableElement; 1171 } 1172 1173 createColumnTd(dataIndex: string, column: unknown, rowData: unknown): HTMLDivElement { 1174 let td: unknown; 1175 td = document.createElement('div'); // @ts-ignore 1176 td.classList.add('td'); // @ts-ignore 1177 td.style.overflow = 'hidden'; // @ts-ignore 1178 td.style.textOverflow = 'ellipsis'; // @ts-ignore 1179 td.style.whiteSpace = 'nowrap'; // @ts-ignore 1180 td.dataIndex = dataIndex; // @ts-ignore 1181 td.style.justifyContent = column.getAttribute('align') || 'flex-start'; // @ts-ignore 1182 let text = formatName(dataIndex, rowData.data[dataIndex], this); //@ts-ignore 1183 if (text.indexOf('<') === -1) { 1184 // @ts-ignore 1185 if (dataIndex === 'totalTimeStr' && rowData.data.chartFrameChildren) { 1186 // @ts-ignore 1187 td.title = rowData.data.totalTime + 'ns'; 1188 } else { 1189 // @ts-ignore 1190 td.title = text; 1191 } 1192 } 1193 // 如果表格中有模板的情况,将模板中的数据放进td中,没有模板,直接将文本放进td 1194 // 但是对于Current Selection tab页来说,表格前两列是时间,第三列是input标签,第四列是button标签 1195 // 而第一行的数据只有第四列一个button,和模板中的数据并不一样,所以要特别处理一下 1196 // @ts-ignore 1197 if (column.template) { 1198 if ( 1199 // @ts-ignore 1200 (dataIndex === 'color' && rowData.data.color === undefined) || // @ts-ignore 1201 (dataIndex === 'text' && rowData.data.text === undefined) 1202 ) { 1203 // @ts-ignore 1204 td.innerHTML = ''; // @ts-ignore 1205 td.template = ''; // @ts-ignore 1206 } else if (dataIndex === 'operate' && rowData.data.operate && rowData.data.operate.innerHTML === 'RemoveAll') { 1207 let removeAll = document.createElement('button'); 1208 removeAll.className = 'removeAll'; 1209 removeAll.innerHTML = 'RemoveAll'; 1210 removeAll.style.background = 'var(--dark-border1,#262f3c)'; 1211 removeAll.style.color = 'white'; 1212 removeAll.style.borderRadius = '10px'; 1213 removeAll.style.fontSize = '10px'; 1214 removeAll.style.height = '18px'; 1215 removeAll.style.lineHeight = '18px'; 1216 removeAll.style.minWidth = '7em'; 1217 removeAll.style.border = 'none'; 1218 removeAll.style.cursor = 'pointer'; 1219 removeAll.style.outline = 'inherit'; // @ts-ignore 1220 td.appendChild(removeAll); 1221 } else { 1222 // @ts-ignore 1223 td.appendChild(column.template.render(rowData.data).content.cloneNode(true)); // @ts-ignore 1224 td.template = column.template; 1225 } 1226 } else { 1227 // @ts-ignore 1228 td.innerHTML = text; 1229 } // @ts-ignore 1230 return td; 1231 } 1232 1233 createBtn(rowData: unknown): unknown { 1234 let btn: unknown = document.createElement('lit-icon'); // @ts-ignore 1235 btn.classList.add('tree-icon'); // @ts-ignore 1236 if (rowData.data.expanded) { 1237 // @ts-ignore 1238 btn.name = 'plus-square'; 1239 } else { 1240 // @ts-ignore 1241 btn.name = 'minus-square'; 1242 } // @ts-ignore 1243 btn.addEventListener('mouseup', (e: MouseEvent): void => { 1244 if (e.button === 0) { 1245 // @ts-ignore 1246 rowData.data.status = false; 1247 const resetNodeHidden = (hidden: boolean, rowData: unknown): void => { 1248 if (hidden) { 1249 // @ts-ignore 1250 rowData.children.forEach((child: unknown) => { 1251 // @ts-ignore 1252 child.rowHidden = false; 1253 }); 1254 } else { 1255 // @ts-ignore 1256 rowData.children.forEach((child: unknown) => { 1257 // @ts-ignore 1258 child.rowHidden = true; 1259 resetNodeHidden(hidden, child); 1260 }); 1261 } 1262 }; 1263 // @ts-ignore 1264 if (rowData.data.expanded) { 1265 // @ts-ignore 1266 rowData.data.status = true; 1267 this.dispatchRowClickEventIcon(rowData, [btn]); // @ts-ignore 1268 rowData.data.expanded = false; 1269 resetNodeHidden(true, rowData); 1270 } else { 1271 // @ts-ignore 1272 rowData.data.expanded = true; // @ts-ignore 1273 rowData.data.status = false; 1274 resetNodeHidden(false, rowData); 1275 } 1276 this.reMeauseHeight(); 1277 } 1278 e.stopPropagation(); 1279 }); 1280 return btn; 1281 } 1282 1283 resetExpandNodeHidden = (hidden: boolean, rowData: unknown): void => { 1284 // @ts-ignore 1285 if (rowData.children.length > 0) { 1286 if (hidden) { 1287 // @ts-ignore 1288 rowData.children.forEach((child: unknown) => { 1289 // @ts-ignore 1290 child.rowHidden = true; 1291 this.resetExpandNodeHidden(hidden, child); 1292 }); 1293 } else { 1294 // @ts-ignore 1295 rowData.children.forEach((child: unknown) => { 1296 // @ts-ignore 1297 child.rowHidden = !rowData.expanded; // @ts-ignore 1298 if (rowData.expanded) { 1299 this.resetExpandNodeHidden(hidden, child); 1300 } 1301 }); 1302 } 1303 } 1304 }; 1305 1306 setChildrenStatus(rowData: unknown, data: unknown): void { 1307 // @ts-ignore 1308 for (let d of data) { 1309 // @ts-ignore 1310 if (rowData.data === d) { 1311 d.status = false; 1312 } 1313 if (d.children !== undefined && d.children.length > 0) { 1314 this.setChildrenStatus(rowData, d.children); 1315 } 1316 } 1317 } 1318 createExpandBtn(rowData: unknown): LitIcon { 1319 // @ts-ignore 1320 let btn: unknown = document.createElement('lit-icon'); // @ts-ignore 1321 btn.classList.add('tree-icon'); 1322 // @ts-ignore 1323 if (rowData.expanded) { 1324 // @ts-ignore 1325 btn.name = 'minus-square'; 1326 } else { 1327 // @ts-ignore 1328 btn.name = 'plus-square'; 1329 } // @ts-ignore 1330 btn.onmouseup = (e: MouseEvent): void => { 1331 if (e.button === 0) { 1332 // @ts-ignore 1333 if (rowData.expanded && this._mode === TableMode.Retract) { 1334 // @ts-ignore 1335 rowData.data.status = false; // @ts-ignore 1336 rowData.expanded = false; 1337 this.resetExpandNodeHidden(true, rowData); // @ts-ignore 1338 } else if (!rowData.expanded && this._mode === TableMode.Retract) { 1339 // @ts-ignore 1340 rowData.expanded = true; // @ts-ignore 1341 rowData.data.status = true; 1342 this.recycleDs = this.meauseTreeRowElement(this.value, RedrawTreeForm.Retract); 1343 this.resetExpandNodeHidden(false, rowData); 1344 } // @ts-ignore 1345 if (this._mode === TableMode.Expand && rowData.expanded) { 1346 // 点击收起的时候将点击的那条数据的status改为false 1347 this.setChildrenStatus(rowData, this.value); // @ts-ignore 1348 rowData.expanded = false; 1349 this.resetExpandNodeHidden(true, rowData); // @ts-ignore 1350 } else if (this._mode === TableMode.Expand && !rowData.expanded) { 1351 // @ts-ignore 1352 if (rowData.data.children) { 1353 // @ts-ignore 1354 rowData.data.status = true; 1355 } 1356 this.recycleDs = this.meauseTreeRowElement(this.value, RedrawTreeForm.Default); // @ts-ignore 1357 rowData.expanded = true; 1358 this.resetExpandNodeHidden(false, rowData); 1359 } 1360 this.reMeauseHeight(); 1361 } 1362 e.stopPropagation(); 1363 }; // @ts-ignore 1364 return btn; 1365 } 1366 1367 reMeauseHeight(): void { 1368 if (this.currentRecycleList.length === 0 && this.ds.length !== 0) { 1369 this.recycleDataSource = this.ds; 1370 return; 1371 } 1372 let totalHeight = 0; 1373 this.recycleDs.forEach((it) => { 1374 // @ts-ignore 1375 if (!it.rowHidden) { 1376 // @ts-ignore 1377 it.top = totalHeight; // @ts-ignore 1378 totalHeight += it.height; 1379 } 1380 }); 1381 this.tbodyElement && (this.tbodyElement.style.height = totalHeight + (this.isScrollXOutSide ? 0 : 0) + 'px'); 1382 this.treeElement && 1383 (this.treeElement.style.height = this.tableElement!.clientHeight - this.theadElement!.clientHeight + 'px'); 1384 let visibleObjects = this.recycleDs.filter((item) => { 1385 // @ts-ignore 1386 return !item.rowHidden; 1387 }); 1388 if (this.tableElement) { 1389 let top = this.tableElement!.scrollTop; 1390 let skip = 0; 1391 for (let i = 0; i < visibleObjects.length; i++) { 1392 // @ts-ignore 1393 if (visibleObjects[i].top <= top && visibleObjects[i].top + visibleObjects[i].height >= top) { 1394 skip = i; 1395 break; 1396 } 1397 } 1398 let reduce = this.currentRecycleList.map((item) => item.clientHeight).reduce((a, b) => a + b, 0); 1399 if (reduce === 0) { 1400 return; 1401 } 1402 while (reduce <= this.tableElement!.clientHeight + 1) { 1403 let isTree = this.hasAttribute('tree'); // @ts-ignore 1404 let newTableElement = this.addTableElement(visibleObjects[skip], isTree, isTree, false); 1405 reduce += newTableElement.clientHeight; 1406 } 1407 for (let i = 0; i < this.currentRecycleList.length; i++) { 1408 if (this.hasAttribute('tree')) { 1409 this.freshCurrentLine( 1410 this.currentRecycleList[i], // @ts-ignore 1411 visibleObjects[i + skip], 1412 this.treeElement?.children[i] as HTMLElement 1413 ); 1414 } else { 1415 // @ts-ignore 1416 this.freshLineHandler(i, skip, visibleObjects); 1417 } 1418 } 1419 } 1420 } 1421 1422 getWheelStatus(element: unknown): void { 1423 // @ts-ignore 1424 element.addEventListener('wheel', (event: WheelEvent) => { 1425 // @ts-ignore 1426 if (element.scrollWidth !== element.offsetWidth) { 1427 event.preventDefault(); 1428 } // @ts-ignore 1429 element.scrollLeft += event.deltaY; 1430 }); 1431 } 1432 1433 renderTable(): void { 1434 if (!this.columns) { 1435 return; 1436 } 1437 if (!this.ds) { 1438 return; 1439 } // If no data source is set, it is returned directly 1440 this.normalDs = []; 1441 this.tbodyElement!.innerHTML = ''; // Clear the table contents 1442 this.ds.forEach((rowData: unknown) => { 1443 let tblRowElement = document.createElement('div'); 1444 tblRowElement.classList.add('tr'); 1445 // @ts-ignore 1446 tblRowElement.data = rowData; 1447 let gridTemplateColumns: Array<unknown> = []; 1448 // If the table is configured with selectable (select row mode) add a checkbox at the head of the line alone 1449 this.renderTableRowSelect(tblRowElement); 1450 this.tableColumns!.forEach((tblColumn) => { 1451 tblColumn.addEventListener('contextmenu', (e) => { 1452 e.preventDefault(); 1453 }); 1454 let dataIndex = tblColumn.getAttribute('data-index') || '1'; 1455 gridTemplateColumns.push(tblColumn.getAttribute('width') || '1fr'); 1456 this.renderTableRowColumnElement(tblColumn, tblRowElement, dataIndex, rowData); 1457 }); 1458 if (this.selectable) { 1459 // If the table with selection is preceded by a 60px column 1460 tblRowElement.style.gridTemplateColumns = '60px ' + gridTemplateColumns.join(' '); 1461 } else { 1462 tblRowElement.style.gridTemplateColumns = gridTemplateColumns.join(' '); 1463 } 1464 this.renderTableRowElementEvent(tblRowElement, rowData); 1465 this.normalDs.push(tblRowElement); 1466 this.tbodyElement!.append(tblRowElement); 1467 }); 1468 } 1469 1470 renderTableRowSelect(tblRowElement: HTMLDivElement): void { 1471 if (this.selectable) { 1472 let tblBox = document.createElement('div'); 1473 tblBox.style.display = 'flex'; 1474 tblBox.style.justifyContent = 'center'; 1475 tblBox.style.alignItems = 'center'; 1476 tblBox.classList.add('td'); 1477 let checkbox = document.createElement('lit-checkbox'); 1478 checkbox.classList.add('row-checkbox'); 1479 checkbox.onchange = (e: unknown): void => { 1480 // Checkbox checking affects whether the div corresponding to the row has a checked attribute for marking 1481 // @ts-ignore 1482 if (e.detail.checked) { 1483 tblRowElement.setAttribute('checked', ''); 1484 } else { 1485 tblRowElement.removeAttribute('checked'); 1486 } 1487 }; 1488 this.getWheelStatus(tblBox); 1489 tblBox.appendChild(checkbox); 1490 tblRowElement.appendChild(tblBox); 1491 } 1492 } 1493 1494 renderTableRowColumnElement( 1495 tblColumn: LitTableColumn, 1496 tblRowElement: HTMLDivElement, 1497 dataIndex: string, 1498 rowData: unknown 1499 ): void { 1500 if (tblColumn.template) { 1501 // If you customize the rendering, you get the nodes from the template 1502 // @ts-ignore 1503 let cloneNode = tblColumn.template.render(rowData).content.cloneNode(true); 1504 let tblCustomDiv = document.createElement('div'); 1505 tblCustomDiv.classList.add('td'); 1506 tblCustomDiv.style.wordBreak = 'break-all'; 1507 tblCustomDiv.style.whiteSpace = 'pre-wrap'; 1508 tblCustomDiv.style.justifyContent = tblColumn.getAttribute('align') || ''; 1509 if (tblColumn.hasAttribute('fixed')) { 1510 fixed(tblCustomDiv, tblColumn.getAttribute('fixed') || '', '#ffffff'); 1511 } 1512 this.getWheelStatus(tblCustomDiv); 1513 tblCustomDiv.append(cloneNode); 1514 tblRowElement.append(tblCustomDiv); 1515 } else { 1516 let tblDiv = document.createElement('div'); 1517 tblDiv.classList.add('td'); 1518 tblDiv.style.wordBreak = 'break-all'; 1519 tblDiv.style.whiteSpace = 'pre-wrap'; // @ts-ignore 1520 tblDiv.title = rowData[dataIndex]; 1521 tblDiv.style.justifyContent = tblColumn.getAttribute('align') || ''; 1522 if (tblColumn.hasAttribute('fixed')) { 1523 fixed(tblDiv, tblColumn.getAttribute('fixed') || '', '#ffffff'); 1524 } 1525 this.getWheelStatus(tblDiv); // @ts-ignore 1526 tblDiv.innerHTML = formatName(dataIndex, rowData[dataIndex], this); 1527 tblRowElement.append(tblDiv); 1528 } 1529 } 1530 1531 renderTableRowElementEvent(tblRowElement: HTMLDivElement, rowData: unknown): void { 1532 tblRowElement.onmouseup = (e: MouseEvent): void => { 1533 e.stopPropagation(); 1534 this.dispatchEvent( 1535 new CustomEvent('row-click', { 1536 detail: { 1537 rowData, 1538 data: rowData, 1539 callBack: (isSelected: boolean): void => { 1540 //是否爲单选 1541 if (isSelected) { 1542 this.clearAllSelection(rowData); 1543 } // @ts-ignore 1544 this.setSelectedRow(rowData.isSelected, [tblRowElement]); 1545 }, 1546 }, 1547 composed: true, 1548 }) 1549 ); 1550 e.stopPropagation(); 1551 }; 1552 } 1553 1554 //自定义td点击事件 1555 dispatchTdClickEvent(td: unknown, column: unknown, rowData: unknown): void { 1556 // @ts-ignore 1557 if (column.hasAttribute('tdJump')) { 1558 //@ts-ignore 1559 td.style.color = '#208aed'; 1560 //@ts-ignore 1561 td.style.textDecoration = 'underline'; 1562 //@ts-ignore 1563 td.onclick = (event: unknown): void => { 1564 this.dispatchEvent( 1565 new CustomEvent('td-click', { 1566 detail: { 1567 //@ts-ignore 1568 ...rowData.data, 1569 }, 1570 composed: true, 1571 }) 1572 ); 1573 // @ts-ignore 1574 event.stopPropagation(); 1575 }; 1576 } 1577 } 1578 1579 freshCurrentLine(element: HTMLElement, rowObject: TableRowObject, firstElement?: HTMLElement): void { 1580 if (!rowObject) { 1581 if (firstElement) { 1582 firstElement.style.display = 'none'; 1583 } 1584 element.style.display = 'none'; 1585 return; 1586 } 1587 let childIndex = -1; //@ts-ignore 1588 this.setHighLight(rowObject.data.isSearch, element); 1589 element.childNodes.forEach((child) => { 1590 if (child.nodeType !== 1) { 1591 return; 1592 } 1593 childIndex++; 1594 let idx = firstElement !== undefined ? childIndex + 1 : childIndex; 1595 this.freshLineFirstElementHandler(firstElement, rowObject, childIndex); 1596 if (idx < this.columns!.length) { 1597 //@ts-ignore 1598 let dataIndex = this.columns![idx].getAttribute('data-index') || '1'; //@ts-ignore 1599 let text = formatName(dataIndex, rowObject.data[dataIndex], this); // @ts-ignore 1600 if ((this.columns![idx] as unknown).template) { 1601 (child as HTMLElement).innerHTML = ''; 1602 (child as HTMLElement).appendChild( 1603 // @ts-ignore 1604 (this.columns![idx] as unknown).template.render(rowObject.data).content.cloneNode(true) 1605 ); 1606 // @ts-ignore 1607 (child as HTMLElement).title = text; 1608 } else { 1609 //@ts-ignore 1610 if (rowObject.data.rowName === 'cpu-profiler' && dataIndex === 'symbolName') { 1611 (child as HTMLElement).innerHTML = ''; 1612 } else { 1613 //@ts-ignore 1614 if (rowObject.data.durFormat) { //ebpf泳道下的analysis页 1615 // 提取数字部分(包括小数点) 1616 if (dataIndex === 'durFormat') { 1617 // @ts-ignore 1618 const match = text.match(/^(\d+(\.\d+)?)(.*)$/); 1619 if (match && match[1] && match[3]) { 1620 // 计算需要添加的空格数 1621 const padding = '\xa0\xa0'.repeat(this.maxLength - match[1].length); 1622 // 构造新的durFormat字符串 1623 text = padding + match[1] + match[3]; 1624 } 1625 } 1626 if (dataIndex === 'percent') { 1627 // @ts-ignore 1628 const match = text.match(/^(\d+(\.\d+)?)(.*)$/); 1629 if (match && match[1]) { 1630 const padding = '\xa0\xa0'.repeat(this.maxLength - match[1].length); 1631 text = padding + match[1]; 1632 } 1633 } 1634 } 1635 //@ts-ignore 1636 (child as HTMLElement).innerHTML = text; 1637 } //@ts-ignore 1638 if (dataIndex === 'selfTimeStr' && rowObject.data.chartFrameChildren) { 1639 //@ts-ignore 1640 (child as HTMLElement).title = rowObject.data.selfTime + 'ns'; //@ts-ignore 1641 } else if (dataIndex === 'totalTimeStr' && rowObject.data.chartFrameChildren) { 1642 //@ts-ignore 1643 (child as HTMLElement).title = rowObject.data.totalTime + 'ns'; 1644 } else if (dataIndex === 'timeStr' && rowObject.data instanceof JsCpuProfilerStatisticsStruct) { 1645 (child as HTMLElement).title = rowObject.data.time + 'ns'; 1646 } else { 1647 //@ts-ignore 1648 (child as HTMLElement).title = text; 1649 } 1650 } 1651 } 1652 }); 1653 this.freshLineStyleAndEvents(element, rowObject, firstElement); 1654 } 1655 1656 freshLineStyleAndEvents(element: HTMLElement, rowObject: TableRowObject, firstElement?: HTMLElement): void { 1657 if (element.style.display === 'none') { 1658 element.style.display = 'grid'; 1659 } 1660 element.style.transform = `translateY(${rowObject.top}px)`; 1661 if (firstElement && firstElement.style.display === 'none') { 1662 firstElement.style.display = 'flex'; 1663 } 1664 element.onmouseup = (e: MouseEvent): void => { 1665 if (firstElement !== undefined) { 1666 this.dispatchRowClickEvent(rowObject, [firstElement, element], e); 1667 } else { 1668 this.dispatchRowClickEvent(rowObject, [element], e); 1669 } 1670 e.stopPropagation(); 1671 }; 1672 element.onmouseenter = (): void => { 1673 this.dispatchRowHoverEvent(rowObject, [element]); // @ts-ignore 1674 if ((element as unknown).data.isSelected) { 1675 return; 1676 } 1677 let indexOf = this.currentRecycleList.indexOf(element as HTMLDivElement); 1678 this.currentTreeDivList.forEach((row) => { 1679 row.classList.remove('mouse-in'); 1680 }); 1681 if (indexOf >= 0 && indexOf < this.currentTreeDivList.length) { 1682 this.setMouseIn(true, [this.currentTreeDivList[indexOf]]); 1683 } 1684 }; 1685 this.querySelectorAll('lit-table-column').forEach((item, i) => { 1686 if (this.hasAttribute('tree')) { 1687 this.dispatchTdClickEvent(element.childNodes[i - 1], item, rowObject); 1688 } else { 1689 this.dispatchTdClickEvent(element.childNodes[i], item, rowObject); 1690 } 1691 }); 1692 // @ts-ignore 1693 (element as unknown).data = rowObject.data; //@ts-ignore 1694 if (rowObject.data.isSelected !== undefined) { 1695 //@ts-ignore 1696 this.setSelectedRow(rowObject.data.isSelected, [element]); 1697 } else { 1698 this.setSelectedRow(false, [element]); 1699 } //@ts-ignore 1700 if (rowObject.data.isHover !== undefined) { 1701 //@ts-ignore 1702 this.setMouseIn(rowObject.data.isHover, [element]); 1703 } else { 1704 this.setMouseIn(false, [element]); 1705 } 1706 if (this.getItemTextColor) { 1707 // @ts-ignore 1708 element.style.color = this.getItemTextColor((element as unknown).data); 1709 } 1710 } 1711 1712 freshLineFirstElementHandler(firstElement: unknown, rowObject: TableRowObject, childIndex: number): void { 1713 if (firstElement !== undefined && childIndex === 0) { 1714 //@ts-ignore 1715 this.setHighLight(rowObject.data.isSearch, firstElement); // @ts-ignore 1716 (firstElement as unknown).data = rowObject.data; // @ts-ignore 1717 if ((this.columns![0] as unknown).template) { 1718 // @ts-ignore 1719 firstElement.innerHTML = (this.columns![0] as unknown).template 1720 .render(rowObject.data) 1721 .content.cloneNode(true).innerHTML; 1722 } else { 1723 let dataIndex = this.columns![0].getAttribute('data-index') || '1'; //@ts-ignore 1724 let text = formatName(dataIndex, rowObject.data[dataIndex], this); //@ts-ignore 1725 if (rowObject.data.rowName === 'js-memory' || rowObject.data.rowName === 'cpu-profiler') { 1726 // @ts-ignore 1727 firstElement.innerHTML = ''; 1728 } else { 1729 // @ts-ignore 1730 firstElement.innerHTML = text; 1731 } // @ts-ignore 1732 firstElement.title = text; 1733 } //@ts-ignore 1734 if (rowObject.children && rowObject.children.length > 0 && !rowObject.data.hasNext) { 1735 let btn = this.createExpandBtn(rowObject); // @ts-ignore 1736 firstElement.insertBefore(btn, firstElement.firstChild); 1737 } // @ts-ignore 1738 firstElement.style.paddingLeft = iconWidth * rowObject.depth + 'px'; 1739 if (!rowObject.children || rowObject.children.length === 0) { 1740 // @ts-ignore 1741 firstElement.style.paddingLeft = iconWidth * rowObject.depth + iconWidth + iconPadding * 2 + 'px'; 1742 } //@ts-ignore 1743 if (rowObject.data.hasNext) { 1744 let btn = this.createBtn(rowObject); // @ts-ignore 1745 firstElement.title = rowObject.data.objectName; // @ts-ignore 1746 firstElement.insertBefore(btn, firstElement.firstChild); // @ts-ignore 1747 firstElement.style.paddingLeft = iconWidth * rowObject.depth + 'px'; 1748 } 1749 this.jsMemoryHandler(rowObject, firstElement); //@ts-ignore 1750 if (rowObject.data.rowName === 'cpu-profiler') { 1751 this.createTextColor(rowObject, firstElement); 1752 } // @ts-ignore 1753 firstElement.onmouseup = (e: MouseEvent): void => { 1754 this.dispatchRowClickEvent(rowObject, [firstElement, element], e); 1755 e.stopPropagation(); 1756 }; // @ts-ignore 1757 firstElement.style.transform = `translateY(${rowObject.top - this.tableElement!.scrollTop}px)`; //@ts-ignore 1758 if (rowObject.data.isSelected !== undefined) { 1759 //@ts-ignore 1760 this.setSelectedRow(rowObject.data.isSelected, [firstElement]); 1761 } else { 1762 this.setSelectedRow(false, [firstElement]); 1763 } 1764 } 1765 } 1766 1767 setSelectedRow(isSelected: boolean, rows: unknown[]): void { 1768 if (isSelected) { 1769 rows.forEach((row) => { 1770 // @ts-ignore 1771 if (row.classList) { 1772 // @ts-ignore 1773 if (row.classList.contains('mouse-in')) { 1774 // @ts-ignore 1775 row.classList.remove('mouse-in'); 1776 } // @ts-ignore 1777 row.classList.add('mouse-select'); 1778 } 1779 }); 1780 } else { 1781 rows.forEach((row) => { 1782 // @ts-ignore 1783 row.classList && row.classList.remove('mouse-select'); 1784 }); 1785 } 1786 } 1787 1788 setMouseIn(isMouseIn: boolean, rows: unknown[]): void { 1789 if (isMouseIn) { 1790 rows.forEach((row) => { 1791 // @ts-ignore 1792 row.classList.add('mouse-in'); 1793 }); 1794 } else { 1795 rows.forEach((row) => { 1796 // @ts-ignore 1797 row.classList.remove('mouse-in'); 1798 }); 1799 } 1800 } 1801 1802 scrollToData(data: unknown): void { 1803 if (this.isRecycleList) { 1804 if (this.recycleDs.length > 0) { 1805 let filter = this.recycleDs.filter((item) => { 1806 // @ts-ignore 1807 return item.data === data; 1808 }); 1809 if (filter.length > 0) { 1810 // @ts-ignore 1811 this.tableElement!.scrollTop = filter[0].top; 1812 } 1813 this.setCurrentSelection(data); 1814 } 1815 } else { 1816 if (this.normalDs.length > 0) { 1817 let filter = this.normalDs.filter((item) => { 1818 // @ts-ignore 1819 return item.data === data; 1820 }); 1821 if (filter.length > 0) { 1822 // @ts-ignore 1823 this.tableElement!.scrollTop = filter[0].top; 1824 } 1825 } 1826 } 1827 } 1828 1829 expandList(datasource: unknown[]): void { 1830 let filter = this.recycleDs.filter((item) => { 1831 // @ts-ignore 1832 return datasource.indexOf(item.data) !== -1; 1833 }); 1834 if (filter.length > 0) { 1835 filter.forEach((item) => { 1836 // @ts-ignore 1837 item.expanded = true; // @ts-ignore 1838 item.rowHidden = false; 1839 }); 1840 } 1841 this.reMeauseHeight(); 1842 } 1843 1844 clearAllSelection(rowObjectData: unknown): void { 1845 if (this.isRecycleList) { 1846 this.recycleDs.forEach((item) => { 1847 // @ts-ignore 1848 if (item.data !== rowObjectData && item.data.isSelected) { 1849 // @ts-ignore 1850 item.data.isSelected = false; 1851 } 1852 }); 1853 this.setSelectedRow(false, this.currentTreeDivList); 1854 this.setSelectedRow(false, this.currentRecycleList); 1855 } else { 1856 this.dataSource.forEach((item) => { 1857 // @ts-ignore 1858 if (item !== rowObjectData && item.isSelected) { 1859 // @ts-ignore 1860 item.isSelected = false; 1861 } 1862 }); 1863 this.setSelectedRow(false, this.normalDs); 1864 } 1865 } 1866 1867 clearAllHover(rowObjectData: unknown): void { 1868 if (this.isRecycleList) { 1869 this.recycleDs.forEach((item) => { 1870 // @ts-ignore 1871 if (item.data !== rowObjectData && item.data.isHover) { 1872 // @ts-ignore 1873 item.data.isHover = false; 1874 } 1875 }); 1876 this.setMouseIn(false, this.currentTreeDivList); 1877 this.setMouseIn(false, this.currentRecycleList); 1878 } else { 1879 this.dataSource.forEach((item) => { 1880 // @ts-ignore 1881 if (item !== rowObjectData && item.isHover) { 1882 // @ts-ignore 1883 item.isHover = false; 1884 } 1885 }); 1886 this.setMouseIn(false, this.normalDs); 1887 } 1888 } 1889 1890 mouseOut(): void { 1891 if (this.isRecycleList) { 1892 // @ts-ignore 1893 this.recycleDs.forEach((item) => (item.data.isHover = false)); 1894 this.setMouseIn(false, this.currentTreeDivList); 1895 this.setMouseIn(false, this.currentRecycleList); 1896 } else { 1897 // @ts-ignore 1898 this.dataSource.forEach((item) => (item.isHover = false)); 1899 this.setMouseIn(false, this.normalDs); 1900 } 1901 this.dispatchEvent( 1902 new CustomEvent('row-hover', { 1903 detail: { 1904 data: undefined, 1905 }, 1906 composed: true, 1907 }) 1908 ); 1909 } 1910 1911 setCurrentSelection(selectionData: unknown): void { 1912 if (this.isRecycleList) { 1913 // @ts-ignore 1914 if (selectionData.isSelected !== undefined) { 1915 this.currentTreeDivList.forEach((itemEl) => { 1916 // @ts-ignore 1917 if ((itemEl as unknown).data === selectionData) { 1918 // @ts-ignore 1919 this.setSelectedRow(selectionData.isSelected, [itemEl]); 1920 } 1921 }); 1922 this.currentRecycleList.forEach((recycleItem) => { 1923 // @ts-ignore 1924 if ((recycleItem as unknown).data === selectionData) { 1925 // @ts-ignore 1926 this.setSelectedRow(selectionData.isSelected, [recycleItem]); 1927 } 1928 }); 1929 } 1930 } else { 1931 // @ts-ignore 1932 if (selectionData.isSelected !== undefined) { 1933 this.normalDs.forEach((item) => { 1934 // @ts-ignore 1935 if ((item as unknown).data === selectionData) { 1936 // @ts-ignore 1937 this.setSelectedRow(selectionData.isSelected, [item]); 1938 } 1939 }); 1940 } 1941 } 1942 } 1943 1944 setCurrentHover(data: unknown): void { 1945 if (this.isRecycleList) { 1946 this.setMouseIn(false, this.currentTreeDivList); 1947 this.setMouseIn(false, this.currentRecycleList); // @ts-ignore 1948 if (data.isHover !== undefined) { 1949 this.currentTreeDivList.forEach((hoverItem) => { 1950 // @ts-ignore 1951 if ((hoverItem as unknown).data === data) { 1952 // @ts-ignore 1953 this.setMouseIn(data.isHover, [hoverItem]); 1954 } 1955 }); 1956 this.currentRecycleList.forEach((hoverItem) => { 1957 // @ts-ignore 1958 if ((hoverItem as unknown).data === data) { 1959 // @ts-ignore 1960 this.setMouseIn(data.isHover, [hoverItem]); 1961 } 1962 }); 1963 } 1964 } else { 1965 this.setMouseIn(false, this.normalDs); // @ts-ignore 1966 if (data.isHover !== undefined) { 1967 this.normalDs.forEach((item): void => { 1968 // @ts-ignore 1969 if ((item as unknown).data === data) { 1970 // @ts-ignore 1971 this.setMouseIn(data.isHover, [item]); 1972 } 1973 }); 1974 } 1975 } 1976 } 1977 1978 dispatchRowClickEventIcon(rowData: unknown, elements: unknown[]): void { 1979 this.dispatchEvent( 1980 new CustomEvent('icon-click', { 1981 detail: { 1982 // @ts-ignore 1983 ...rowData.data, 1984 // @ts-ignore 1985 data: rowData.data, 1986 callBack: (isSelected: boolean): void => { 1987 //是否爲单选 1988 if (isSelected) { 1989 // @ts-ignore 1990 this.clearAllSelection(rowData.data); 1991 } // @ts-ignore 1992 this.setSelectedRow(rowData.data.isSelected, elements); 1993 }, 1994 }, 1995 composed: true, 1996 }) 1997 ); 1998 } 1999 2000 dispatchRowClickEvent(rowObject: unknown, elements: unknown[], event: MouseEvent): void { 2001 this.dispatchEvent( 2002 new CustomEvent('row-click', { 2003 detail: { 2004 button: event.button, // @ts-ignore 2005 ...rowObject.data, // @ts-ignore 2006 data: rowObject.data, 2007 callBack: (isSelected: boolean): void => { 2008 //是否爲单选 2009 if (isSelected) { 2010 // @ts-ignore 2011 this.clearAllSelection(rowObject.data); 2012 } // @ts-ignore 2013 this.setSelectedRow(rowObject.data.isSelected, elements); 2014 }, 2015 }, 2016 composed: true, 2017 }) 2018 ); 2019 event.stopPropagation(); 2020 } 2021 2022 dispatchRowHoverEvent(rowObject: unknown, elements: unknown[]): void { 2023 this.dispatchEvent( 2024 new CustomEvent('row-hover', { 2025 detail: { 2026 // @ts-ignore 2027 data: rowObject.data, 2028 callBack: (): void => { 2029 // @ts-ignore 2030 this.clearAllHover(rowObject.data); // @ts-ignore 2031 this.setMouseIn(rowObject.data.isHover, elements); 2032 }, 2033 }, 2034 composed: true, 2035 }) 2036 ); 2037 } 2038 2039 setHighLight(isSearch: boolean, element: unknown): void { 2040 if (isSearch) { 2041 // @ts-ignore 2042 element.setAttribute('high-light', ''); 2043 } else { 2044 // @ts-ignore 2045 element.removeAttribute('high-light'); 2046 } 2047 } 2048 2049 createTextColor(rowData: unknown, divElement: unknown): void { 2050 let nodeText = document.createElement('text'); 2051 nodeText.classList.add('functionName'); // @ts-ignore 2052 nodeText.textContent = rowData.data.name; // @ts-ignore 2053 divElement.append(nodeText); // @ts-ignore 2054 if (rowData.data.scriptName !== 'unknown') { 2055 let scriptText = document.createElement('text'); 2056 scriptText.classList.add('scriptName'); // @ts-ignore 2057 scriptText.textContent = rowData.data.scriptName; // @ts-ignore 2058 divElement.append(scriptText); 2059 scriptText.style.color = '#a1a1a1'; 2060 } // @ts-ignore 2061 divElement.title = rowData.data.symbolName; 2062 } 2063 2064 jsMemoryHandler(rowData: unknown, td: unknown): void { 2065 // @ts-ignore 2066 if (rowData.data.rowName === 'js-memory') { 2067 let nodeText = document.createElement('text'); 2068 nodeText.classList.add('nodeName'); // @ts-ignore 2069 nodeText.textContent = rowData.data.nodeName; // @ts-ignore 2070 td.append(nodeText); 2071 let countText = document.createElement('text'); 2072 countText.classList.add('countName'); // @ts-ignore 2073 countText.textContent = rowData.data.count; // @ts-ignore 2074 td.append(countText); 2075 let nodeIdText = document.createElement('text'); 2076 nodeIdText.classList.add('nodeIdText'); // @ts-ignore 2077 nodeIdText.textContent = rowData.data.nodeId; // @ts-ignore 2078 td.append(nodeIdText); // @ts-ignore 2079 if (rowData.data.edgeName !== '') { 2080 let edgeNameText = document.createElement('text'); 2081 edgeNameText.classList.add('edgeNameText'); // @ts-ignore 2082 edgeNameText.textContent = rowData.data.edgeName; // @ts-ignore 2083 td.insertBefore(edgeNameText, nodeText); 2084 let span = document.createElement('span'); 2085 span.classList.add('span'); // @ts-ignore 2086 if (rowData.data.type === ConstructorType.RetainersType) { 2087 // @ts-ignore 2088 span.textContent = '\xa0' + 'in' + '\xa0'; // @ts-ignore 2089 nodeIdText.textContent = ` @${rowData.data.id}`; 2090 } else { 2091 span.textContent = '\xa0' + '::' + '\xa0'; 2092 } 2093 edgeNameText.append(span); 2094 } 2095 if ( 2096 // @ts-ignore 2097 (rowData.data.nodeType === NodeType.STRING || // @ts-ignore 2098 rowData.data.nodeType === NodeType.CONCATENATED_STRING || // @ts-ignore 2099 rowData.data.nodeType === NodeType.SLICED_STRING) && // @ts-ignore 2100 rowData.data.type !== ConstructorType.ClassType 2101 ) { 2102 nodeText.style.color = '#d53d3d'; // @ts-ignore 2103 nodeText.textContent = '"' + rowData.data.nodeName + '"'; 2104 } // @ts-ignore 2105 td.title = rowData.data.objectName; 2106 } 2107 } 2108} 2109 2110// 表格默认是展开还是收起的 2111export enum TableMode { 2112 Expand, // 默认展开 2113 Retract, // 默认收起 2114} 2115 2116// 重绘的表格是要全部展开,全部收起,还是一层一层手动打开 2117export enum RedrawTreeForm { 2118 Expand, // 一键展开 2119 Retract, // 一键收起 2120 Default, //点击加号,逐层展开 2121} 2122