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