• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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.js';
17import { LitProgressBar } from './../progress-bar/LitProgressBar.js';
18import { element } from '../BaseElement.js';
19import '../utils/Template.js';
20import { TableRowObject } from './TableRowObject.js';
21import { ExcelFormater } from '../utils/ExcelFormater.js';
22import { JSONToCSV } from '../utils/CSVFormater.js';
23import { NodeType } from '../../js-heap/model/DatabaseStruct.js';
24import { ConstructorType } from '../../js-heap/model/UiStruct.js';
25
26@element('lit-table')
27export class LitTable extends HTMLElement {
28  meauseRowElement: HTMLDivElement | undefined;
29  currentRecycleList: HTMLDivElement[] = [];
30  currentTreeDivList: HTMLDivElement[] = [];
31  public rememberScrollTop = false;
32  public getItemTextColor?: (data: any) => string;
33  public itemTextHandleMap: Map<string,(value: any) => string> = new Map<string, (value: any) => string>();
34  private ds: Array<any> = [];
35  public recycleDs: Array<any> = [];
36  private normalDs: Array<any> = [];
37  private gridTemplateColumns: any;
38  /*Grid css layout descriptions are obtained according to the clustern[] nested structure*/
39  private st: HTMLSlotElement | null | undefined;
40  private tableElement: HTMLDivElement | null | undefined;
41  private exportProgress: LitProgressBar | null | undefined;
42  private theadElement: HTMLDivElement | null | undefined;
43  private columns: Array<Element> | null | undefined;
44  private tbodyElement: HTMLDivElement | undefined | null;
45  private treeElement: HTMLDivElement | undefined | null;
46  private tableColumns: NodeListOf<LitTableColumn> | undefined;
47  private colCount: number = 0;
48  private currentScrollTop: number = 0;
49  private isRecycleList: boolean = true;
50  private isScrollXOutSide: boolean = false;
51  private exportLoading: boolean = false;
52  private _loading: boolean = false;
53
54  constructor() {
55    super();
56    const shadowRoot = this.attachShadow({ mode: 'open' });
57    shadowRoot.innerHTML = `
58        <style>
59        :host{
60            display: grid;
61            grid-template-columns: repeat(1,1fr);
62            width: 100%;
63            position: relative;
64            font-weight: 500;
65            flex:1;
66        }
67        .tr{
68            display: grid;
69            grid-column-gap: 5px;
70            min-width:100%;
71        }
72        .tr:nth-of-type(even){
73        }
74        .tr{
75            background-color: var(--dark-background,#FFFFFF);
76        }
77        .tr:hover{
78            background-color: var(--dark-background6,#DEEDFF);
79        }
80        .tr[selected]{
81            background-color: var(--dark-background6,#DEEDFF);
82        }
83        .tr[high-light]{
84            font-weight: 600;
85        }
86        .td{
87            box-sizing: border-box;
88            padding: 3px;
89            display: flex;
90            justify-content: flex-start;
91            align-items: center;
92            width: 100%;
93            height: auto;
94            cursor: pointer;
95        }
96        .td text{
97            overflow: hidden;
98            text-overflow: ellipsis;
99            white-space: nowrap;
100        }
101        .td-order{
102        }
103        .td-order:before{
104
105        }
106        :host([grid-line]) .td{
107            border-left: 1px solid #f0f0f0;
108        }
109        :host([grid-line]) .td:last-of-type{
110            border-right: 1px solid #f0f0f0;
111        }
112        .table{
113            width: 100%;
114             color: var(--dark-color2,#262626);
115        }
116        .thead{
117            display: grid;
118            position: sticky;
119            top: 0;
120            font-weight: bold;
121            font-size: .9rem;
122            color: var(--dark-color1,#000);
123            background-color: var(--dark-background,#FFFFFF);
124            z-index: 1;
125        }
126        .tbody{
127            width: 100%;
128            top: 0;
129            left: 0;
130            right:0;
131            bottom:0;
132            display: flex;
133            flex-direction: row
134            row-gap: 1px;
135            column-gap: 1px;
136        }
137        .tree{
138            overflow-x:hidden;
139            overflow-y:hidden;
140            display: grid;
141            grid-template-columns: 1fr;
142            row-gap: 1px;
143            column-gap: 1px;
144            position:relative;
145        }
146        .tree:hover{
147            overflow-x: overlay;
148        }
149        .tree-first-body{
150            min-width: 100%;
151            box-sizing: border-box;
152            display:flex;
153            align-items:center;
154            white-space: nowrap;
155            font-weight: 500;
156            cursor: pointer;
157        }
158        .tree-first-body[high-light]{
159            font-weight: 600;
160        }
161        .tree-first-body:hover{
162            background-color: var(--dark-background6,#DEEDFF); /*antd #fafafa 42b983*/
163        }
164        .body{
165            display: grid;
166            grid-template-columns: 1fr;
167            row-gap: 1px;
168            column-gap: 1px;
169            flex:1;
170            position: relative;
171        }
172        :host([grid-line])  .tbody{
173            border-bottom: 1px solid #f0f0f0;
174            background-color: #f0f0f0;
175        }
176        .th{
177            grid-column-gap: 5px;
178            display: grid;
179            background-color: var(--dark-background,#FFFFFF);
180        }
181
182        .tree-icon{
183            font-size: 1.2rem;
184            width: 20px;
185            height: 20px;
186            padding-right: 5px;
187            padding-left: 5px;
188            cursor: pointer;
189        }
190        .tree-icon:hover{
191            color: #42b983;
192        }
193        .row-checkbox,row-checkbox-all{
194
195        }
196        :host([no-head]) .thead{
197            display: none;
198        }
199        .up-svg{
200            position: absolute;
201            right: 5px;
202            top: 8px;
203            bottom: 8px;
204            width: 15px;
205            height: 15px;
206        }
207        .down-svg{
208            position: absolute;
209            top: 8px;
210            right: 5px;
211            bottom: 8px;
212            width: 15px;
213            height: 15px;
214        }
215        .mouse-select{
216            background-color: var(--dark-background6,#DEEDFF);
217        }
218        .mouse-in{
219            background-color: var(--dark-background6,#DEEDFF);
220        }
221        .export{
222            height:32px;
223            width: 32px;
224            cursor:pointer;
225            display:none;
226            align-items:center;
227            justify-content:center;
228            border-radius:5px;
229            box-sizing: border-box;
230            background-color: #000000;
231            opacity: 0.3;
232            position:absolute;
233            right:20px;
234            bottom:20px;
235            z-index: 999999;
236        }
237        .progress{
238            position: absolute;
239            height: 1px;
240            top: 0;
241            left: 0;
242            right: 0;
243            z-index: 999999;
244        }
245        :host([hideDownload]) .export{
246            display: none;
247        }
248        </style>
249        <lit-progress-bar id="export_progress_bar" class="progress"></lit-progress-bar>
250        <slot id="slot" style="display: none"></slot>
251        <slot name="head"></slot>
252        <div class="export">
253            <lit-icon size="18" style="color: #ffffff" name="copyhovered" ></lit-icon>
254        </div>
255        <div class="table" style="overflow-x:auto;">
256            <div class="thead"></div>
257            <div class="tbody">
258                <div class="tree"></div>
259                <div class="body"></div>
260            </div>
261        </div>
262        `;
263  }
264
265  static get observedAttributes() {
266    return ['scroll-y', 'selectable', 'no-head', 'grid-line', 'defaultOrderColumn', 'hideDownload', 'loading'];
267  }
268
269  set loading(value: boolean) {
270    this._loading = value;
271    this.exportProgress!.loading = value;
272  }
273
274  get hideDownload() {
275    return this.hasAttribute('hideDownload');
276  }
277
278  set hideDownload(value) {
279    if (value) {
280      this.setAttribute('hideDownload', '');
281    } else {
282      this.removeAttribute('hideDownload');
283    }
284  }
285
286  get selectable() {
287    return this.hasAttribute('selectable');
288  }
289
290  set selectable(value) {
291    if (value) {
292      this.setAttribute('selectable', '');
293    } else {
294      this.removeAttribute('selectable');
295    }
296  }
297
298  get scrollY() {
299    return this.getAttribute('scroll-y') || 'auto';
300  }
301
302  set scrollY(value) {
303    this.setAttribute('scroll-y', value);
304  }
305
306  get dataSource() {
307    return this.ds || [];
308  }
309
310  set dataSource(value) {
311    this.ds = value;
312    this.isRecycleList = false;
313    if (this.hasAttribute('tree')) {
314      this.renderTreeTable();
315    } else {
316      this.renderTable();
317    }
318  }
319
320  get recycleDataSource() {
321    return this.ds || [];
322  }
323
324  set recycleDataSource(value) {
325    this.isScrollXOutSide = this.tableElement!.scrollWidth > this.tableElement!.clientWidth;
326    this.isRecycleList = true;
327    this.ds = value;
328    if (this.rememberScrollTop) {
329      this.currentScrollTop = this.tableElement!.scrollTop;
330      this.tableElement!.scrollTop = 0;
331      this.tableElement!.scrollLeft = 0;
332    } else {
333      this.tableElement!.scrollTop = 0;
334      this.tableElement!.scrollLeft = 0;
335    }
336    if (this.hasAttribute('tree')) {
337      this.recycleDs = this.meauseTreeRowElement(value);
338    } else {
339      this.recycleDs = this.meauseAllRowHeight(value);
340    }
341  }
342
343  get snapshotDataSource() {
344    return this.ds || [];
345  }
346
347  set snapshotDataSource(value) {
348    this.ds = value;
349    if (this.hasAttribute('tree')) {
350      this.recycleDs = this.meauseTreeRowElement(value);
351    } else {
352      this.recycleDs = this.meauseAllRowHeight(value);
353    }
354  }
355
356  move1px() {
357    this.tableElement!.scrollTop = this.tableElement!.scrollTop + 1;
358  }
359
360  dataExportInit() {
361    let exportDiv = this.shadowRoot!.querySelector<HTMLDivElement>('.export');
362    exportDiv &&
363      (exportDiv.onclick = () => {
364        this.exportData();
365      });
366  }
367
368  exportData() {
369    if (this.exportLoading || this.ds.length === 0) {
370      return;
371    }
372    this.exportLoading = true;
373    this.exportProgress!.loading = true;
374    let date = new Date();
375    JSONToCSV.csvExport({
376      columns: this.columns as any[],
377      tables: this.ds,
378      fileName: date.getTime() + '',
379    }).then((res) => {
380      this.exportLoading = false;
381      this.exportProgress!.loading = false;
382    });
383  }
384
385  exportExcelData() {
386    let now = Date.now();
387    ExcelFormater.testExport(
388      [
389        {
390          columns: this.columns as any[],
391          tables: this.ds,
392          sheetName: now + '',
393        },
394      ],
395      now + ''
396    );
397  }
398
399  formatExportData(dataSource: any[]): any[] {
400    if (dataSource == undefined || dataSource.length == 0) {
401      return [];
402    }
403    if (this.columns == undefined) {
404      return [];
405    }
406    return dataSource.map((item) => {
407      let formatData: any = {};
408      this.columns!.forEach((column) => {
409        let dataIndex = column.getAttribute('data-index');
410        let columnName = column.getAttribute('title');
411        if (columnName == '') {
412          columnName = dataIndex;
413        }
414        if (dataIndex && columnName && item[dataIndex] != undefined) {
415          formatData[columnName] = item[dataIndex];
416        }
417      });
418      if (item.children != undefined) {
419        formatData.children = this.formatExportData(item.children);
420      }
421      return formatData;
422    });
423  }
424
425  formatExportCsvData(dataSource: any[]): string {
426    if (dataSource == undefined || dataSource.length == 0) {
427      return '';
428    }
429    if (this.columns == undefined) {
430      return '';
431    }
432    let str = '';
433    str += this.columns!.map((column) => {
434      let dataIndex = column.getAttribute('data-index');
435      let columnName = column.getAttribute('title');
436      if (columnName == '') {
437        columnName = dataIndex;
438      }
439      return columnName;
440    }).join(',');
441    str += this.recursionExportTableData(this.columns, dataSource);
442    return str;
443  }
444
445  recursionExportTableData(columns: any[], dataSource: any[]): string {
446    let concatStr = '\r\n';
447    dataSource.forEach((item, index) => {
448      concatStr += columns
449        .map((column) => {
450          let dataIndex = column.getAttribute('data-index');
451          return `"${item[dataIndex] || ''}"    `;
452        })
453        .join(',');
454      if (item.children != undefined) {
455        concatStr += this.recursionExportTableData(columns, item.children);
456      }
457      if (index != dataSource.length - 1) {
458        concatStr += '\r\n';
459      }
460    });
461    return concatStr;
462  }
463
464  //当 custom element首次被插入文档DOM时,被调用。
465  connectedCallback() {
466    this.st = this.shadowRoot?.querySelector('#slot');
467    this.tableElement = this.shadowRoot?.querySelector('.table');
468    this.exportProgress = this.shadowRoot?.querySelector('#export_progress_bar');
469    this.theadElement = this.shadowRoot?.querySelector('.thead');
470    this.treeElement = this.shadowRoot?.querySelector('.tree');
471    this.tbodyElement = this.shadowRoot?.querySelector('.body');
472    this.tableColumns = this.querySelectorAll<LitTableColumn>('lit-table-column');
473    this.colCount = this.tableColumns!.length;
474    this.dataExportInit();
475    this.tableElement?.addEventListener('copy', (e) => {
476      // @ts-ignore
477      let clipboardData = e.clipboardData || window.clipboardData;
478      if (!clipboardData) return;
479      // @ts-ignore
480      let text = window.getSelection().toString();
481      if (text) {
482        e.preventDefault();
483        let length = this.tableColumns?.length || 1;
484        let strings = text.split('\n');
485        let formatStr = '';
486        for (let i = 0; i < strings.length; i++) {
487          if (i % length != 0) {
488            formatStr += '    ';
489          }
490          formatStr += strings[i];
491          if (i != 0 && i % length == length - 1) {
492            formatStr += '\n';
493          }
494        }
495        clipboardData.setData('text/plain', formatStr);
496      }
497    });
498    this.st?.addEventListener('slotchange', () => {
499      this.theadElement!.innerHTML = '';
500      setTimeout(() => {
501        this.columns = this.st!.assignedElements();
502        let rowElement = document.createElement('div');
503        rowElement.classList.add('th');
504        if (this.selectable) {
505          let box = document.createElement('div');
506          box.style.display = 'flex';
507          box.style.justifyContent = 'center';
508          box.style.alignItems = 'center';
509          box.style.gridArea = '_checkbox_';
510          box.classList.add('td');
511          box.style.backgroundColor = '#ffffff66';
512          let checkbox = document.createElement('lit-checkbox');
513          checkbox.classList.add('row-checkbox-all');
514          checkbox.onchange = (e: any) => {
515            this.shadowRoot!.querySelectorAll('.row-checkbox').forEach((a: any) => (a.checked = e.detail.checked));
516            if (e.detail.checked) {
517              this.shadowRoot!.querySelectorAll('.tr').forEach((a) => a.setAttribute('checked', ''));
518            } else {
519              this.shadowRoot!.querySelectorAll('.tr').forEach((a) => a.removeAttribute('checked'));
520            }
521          };
522          box.appendChild(checkbox);
523          rowElement.appendChild(box);
524        }
525        let area: Array<any> = [],
526          gridTemplateColumns: Array<any> = [];
527        let resolvingArea = (columns: any, x: any, y: any) => {
528          columns.forEach((a: any, i: any) => {
529            if (!area[y]) area[y] = [];
530            let key = a.getAttribute('key') || a.getAttribute('title');
531            if (a.tagName === 'LIT-TABLE-GROUP') {
532              let len = a.querySelectorAll('lit-table-column').length;
533              let children = [...a.children].filter((a) => a.tagName !== 'TEMPLATE');
534              if (children.length > 0) {
535                resolvingArea(children, x, y + 1);
536              }
537              for (let j = 0; j < len; j++) {
538                area[y][x] = { x, y, t: key };
539                x++;
540              }
541              let h = document.createElement('div');
542              h.classList.add('td');
543              h.style.justifyContent = a.getAttribute('align');
544              h.style.borderBottom = '1px solid #f0f0f0';
545              h.style.gridArea = key;
546              h.innerText = a.title;
547              if (a.hasAttribute('fixed')) {
548                this.fixed(h, a.getAttribute('fixed'), '#42b983');
549              }
550              rowElement.append(h);
551            } else if (a.tagName === 'LIT-TABLE-COLUMN') {
552              area[y][x] = { x, y, t: key };
553              x++;
554              let h: any = document.createElement('div');
555              h.classList.add('td');
556              if (a.hasAttribute('order')) {
557                h.sortType = 0;
558                h.classList.add('td-order');
559                h.style.position = 'relative';
560                let NS = 'http://www.w3.org/2000/svg';
561                let upSvg: any = document.createElementNS(NS, 'svg');
562                let upPath: any = document.createElementNS(NS, 'path');
563                upSvg.setAttribute('fill', 'let(--dark-color1,#212121)');
564                upSvg.setAttribute('viewBox', '0 0 1024 1024');
565                upSvg.setAttribute('stroke', 'let(--dark-color1,#212121)');
566                upSvg.classList.add('up-svg');
567                upPath.setAttribute(
568                  'd',
569                  'M858.9 689L530.5 308.2c-9.4-10.9-27.5-10.9-37 0L165.1 689c-12.2 14.2-1.2 35 18.5 35h656.8c19.7 0 30.7-20.8 18.5-35z'
570                );
571                upSvg.appendChild(upPath);
572                let downSvg: any = document.createElementNS(NS, 'svg');
573                let downPath: any = document.createElementNS(NS, 'path');
574                downSvg.setAttribute('fill', 'let(--dark-color1,#212121)');
575                downSvg.setAttribute('viewBox', '0 0 1024 1024');
576                downSvg.setAttribute('stroke', 'let(--dark-color1,#212121)');
577                downSvg.classList.add('down-svg');
578                downPath.setAttribute(
579                  'd',
580                  'M840.4 300H183.6c-19.7 0-30.7 20.8-18.5 35l328.4 380.8c9.4 10.9 27.5 10.9 37 0L858.9 335c12.2-14.2 1.2-35-18.5-35z'
581                );
582                downSvg.appendChild(downPath);
583                if (i == 0) {
584                  h.sortType = 0; // 默认以第一列 降序排序 作为默认排序
585                  upSvg.setAttribute('fill', 'let(--dark-color1,#212121)');
586                  downSvg.setAttribute('fill', 'let(--dark-color1,#212121)');
587                }
588                upSvg.style.display = 'none';
589                downSvg.style.display = 'none';
590                h.appendChild(upSvg);
591                h.appendChild(downSvg);
592                h.onclick = () => {
593                  this?.shadowRoot?.querySelectorAll('.td-order svg').forEach((it: any) => {
594                    it.setAttribute('fill', 'let(--dark-color1,#212121)');
595                    it.sortType = 0;
596                    it.style.display = 'none';
597                  });
598                  if (h.sortType == undefined || h.sortType == null) {
599                    h.sortType = 0;
600                  } else if (h.sortType === 2) {
601                    h.sortType = 0;
602                  } else {
603                    h.sortType += 1;
604                  }
605                  switch (h.sortType) {
606                    case 1:
607                      this.theadElement!.setAttribute('sort', '');
608                      upSvg.setAttribute('fill', 'let(--dark-color1,#212121)');
609                      downSvg.setAttribute('fill', 'let(--dark-color1,#212121)');
610                      upSvg.style.display = 'block';
611                      downSvg.style.display = 'none';
612                      break;
613                    case 2:
614                      upSvg.setAttribute('fill', 'let(--dark-color1,#212121)');
615                      downSvg.setAttribute('fill', 'let(--dark-color1,#212121)');
616                      upSvg.style.display = 'none';
617                      downSvg.style.display = 'block';
618                      break;
619                    default:
620                      upSvg.setAttribute('fill', 'let(--dark-color1,#212121)');
621                      downSvg.setAttribute('fill', 'let(--dark-color1,#212121)');
622                      upSvg.style.display = 'none';
623                      downSvg.style.display = 'none';
624                      this.theadElement!.removeAttribute('sort');
625                      break;
626                  }
627                  this.dispatchEvent(
628                    new CustomEvent('column-click', {
629                      detail: {
630                        sort: h.sortType,
631                        key: key,
632                      },
633                      composed: true,
634                    })
635                  );
636                };
637              }
638              h.style.justifyContent = a.getAttribute('align');
639              gridTemplateColumns.push(a.getAttribute('width') || '1fr');
640              h.style.gridArea = key;
641              let titleLabel = document.createElement('label');
642              titleLabel.textContent = a.title;
643              h.appendChild(titleLabel);
644              if (a.hasAttribute('fixed')) {
645                this.fixed(h, a.getAttribute('fixed'), '#42b983');
646              }
647              rowElement.append(h);
648            }
649          });
650        };
651        resolvingArea(this.columns, 0, 0);
652        area.forEach((rows, j, array) => {
653          for (let i = 0; i < this.colCount; i++) {
654            if (!rows[i]) rows[i] = array[j - 1][i];
655          }
656        });
657        this.gridTemplateColumns = gridTemplateColumns.join(' ');
658        if (this.selectable) {
659          let s = area.map((a) => '"_checkbox_ ' + a.map((aa: any) => aa.t).join(' ') + '"').join(' ');
660          rowElement.style.gridTemplateColumns = '60px ' + gridTemplateColumns.join(' ');
661          rowElement.style.gridTemplateRows = `repeat(${area.length},1fr)`;
662          rowElement.style.gridTemplateAreas = s;
663        } else {
664          let s = area.map((a) => '"' + a.map((aa: any) => aa.t).join(' ') + '"').join(' ');
665          rowElement.style.gridTemplateColumns = gridTemplateColumns.join(' ');
666          rowElement.style.gridTemplateRows = `repeat(${area.length},1fr)`;
667          rowElement.style.gridTemplateAreas = s;
668        }
669        this.theadElement!.innerHTML = '';
670        this.theadElement!.append(rowElement);
671        this.treeElement!.style.top = this.theadElement?.clientHeight + 'px';
672      });
673    });
674
675    this.shadowRoot!.addEventListener('load', function (event) {});
676    this.tableElement!.addEventListener('mouseout', (ev) => this.mouseOut());
677  }
678
679  // Is called when the custom element is removed from the document DOM.
680  disconnectedCallback() {}
681
682  // It is called when the custom element is moved to a new document.
683  adoptedCallback() {}
684
685  // It is called when a custom element adds, deletes, or modifies its own properties.
686  attributeChangedCallback(name: string, oldValue: string, newValue: string) {}
687
688  fixed(td: HTMLElement, placement: string, bgColor: string) {
689    td.style.position = 'sticky';
690    if (placement === 'left') {
691      td.style.left = '0px';
692      td.style.boxShadow = '3px 0px 5px #33333333';
693    } else if (placement === 'right') {
694      td.style.right = '0px';
695      td.style.boxShadow = '-3px 0px 5px #33333333';
696    }
697  }
698
699  renderTable() {
700    if (!this.columns) return;
701    if (!this.ds) return; // If no data source is set, it is returned directly
702    this.normalDs = [];
703    this.tbodyElement!.innerHTML = ''; // Clear the table contents
704    this.ds.forEach((rowData: any) => {
705      let tblRowElement = document.createElement('div');
706      tblRowElement.classList.add('tr');
707      // @ts-ignore
708      tblRowElement.data = rowData;
709      let gridTemplateColumns: Array<any> = [];
710      // If the table is configured with selectable (select row mode) add a checkbox at the head of the line alone
711      if (this.selectable) {
712        let tblBox = document.createElement('div');
713        tblBox.style.display = 'flex';
714        tblBox.style.justifyContent = 'center';
715        tblBox.style.alignItems = 'center';
716        tblBox.classList.add('td');
717        let checkbox = document.createElement('lit-checkbox');
718        checkbox.classList.add('row-checkbox');
719        checkbox.onchange = (e: any) => {
720          // Checkbox checking affects whether the div corresponding to the row has a checked attribute for marking
721          if (e.detail.checked) {
722            tblRowElement.setAttribute('checked', '');
723          } else {
724            tblRowElement.removeAttribute('checked');
725          }
726        };
727        tblBox.appendChild(checkbox);
728        tblRowElement.appendChild(tblBox);
729      }
730      this.tableColumns!.forEach((tblColumn) => {
731        let dataIndex = tblColumn.getAttribute('data-index') || '1';
732        gridTemplateColumns.push(tblColumn.getAttribute('width') || '1fr');
733        if (tblColumn.template) {
734          // If you customize the rendering, you get the nodes from the template
735          // @ts-ignore
736          let cloneNode = tblColumn.template.render(rowData).content.cloneNode(true);
737          let tblCustomDiv = document.createElement('div');
738          tblCustomDiv.classList.add('td');
739          tblCustomDiv.style.wordBreak = 'break-all';
740          tblCustomDiv.style.whiteSpace = 'pre-wrap';
741          tblCustomDiv.style.justifyContent = tblColumn.getAttribute('align') || '';
742          if (tblColumn.hasAttribute('fixed')) {
743            this.fixed(tblCustomDiv, tblColumn.getAttribute('fixed') || '', '#ffffff');
744          }
745          tblCustomDiv.append(cloneNode);
746          tblRowElement.append(tblCustomDiv);
747        } else {
748          let tblDiv = document.createElement('div');
749          tblDiv.classList.add('td');
750          tblDiv.style.wordBreak = 'break-all';
751          tblDiv.style.whiteSpace = 'pre-wrap';
752          tblDiv.title = rowData[dataIndex];
753          tblDiv.style.justifyContent = tblColumn.getAttribute('align') || '';
754          if (tblColumn.hasAttribute('fixed')) {
755            this.fixed(tblDiv, tblColumn.getAttribute('fixed') || '', '#ffffff');
756          }
757          tblDiv.innerHTML = this.formatName(dataIndex, rowData[dataIndex]);
758          tblRowElement.append(tblDiv);
759        }
760      });
761      if (this.selectable) {
762        // If the table with selection is preceded by a 60px column
763        tblRowElement.style.gridTemplateColumns = '60px ' + gridTemplateColumns.join(' ');
764      } else {
765        tblRowElement.style.gridTemplateColumns = gridTemplateColumns.join(' ');
766      }
767      tblRowElement.onclick = (e) => {
768        this.dispatchEvent(
769          new CustomEvent('row-click', {
770            detail: {
771              rowData,
772              data: rowData,
773              callBack: (isSelected: boolean) => {
774                //是否爲单选
775                if (isSelected) {
776                  this.clearAllSelection(rowData);
777                }
778                this.setSelectedRow(rowData.isSelected, [tblRowElement]);
779              },
780            },
781            composed: true,
782          })
783        );
784      };
785      this.normalDs.push(tblRowElement);
786      this.tbodyElement!.append(tblRowElement);
787    });
788  }
789
790  renderTreeTable() {
791    if (!this.columns) return;
792    if (!this.ds) return;
793    this.tbodyElement!.innerHTML = '';
794    this.treeElement!.innerHTML = '';
795    let ids = JSON.parse(this.getAttribute('tree') || `["id","pid"]`);
796    let toTreeData = (data: any, id: any, pid: any) => {
797      let cloneData = JSON.parse(JSON.stringify(data));
798      return cloneData.filter((father: any) => {
799        let branchArr = cloneData.filter((child: any) => father[id] == child[pid]);
800        branchArr.length > 0 ? (father['children'] = branchArr) : '';
801        return !father[pid];
802      });
803    };
804    let treeData = toTreeData(this.ds, ids[0], ids[1]);
805    let offset = 30;
806    let offsetVal = offset;
807    const drawRow = (arr: any, parentNode: any) => {
808      arr.forEach((rowData: any) => {
809        let treeTblRowElement = document.createElement('div');
810        treeTblRowElement.classList.add('tr');
811        // @ts-ignore
812        treeTblRowElement.data = rowData;
813        let gridTemplateColumns: Array<any> = [];
814        if (this.selectable) {
815          let treeTblDiv = document.createElement('div');
816          treeTblDiv.style.display = 'flex';
817          treeTblDiv.style.justifyContent = 'center';
818          treeTblDiv.style.alignItems = 'center';
819          treeTblDiv.classList.add('td');
820          let checkbox = document.createElement('lit-checkbox');
821          checkbox.classList.add('row-checkbox');
822          checkbox.onchange = (e: any) => {
823            if (e.detail.checked) {
824              treeTblRowElement.setAttribute('checked', '');
825            } else {
826              treeTblRowElement.removeAttribute('checked');
827            }
828            const changeChildNode = (rowElement: any, checked: any) => {
829              let id = rowElement.getAttribute('id');
830              let pid = rowElement.getAttribute('pid');
831              this.shadowRoot!.querySelectorAll(`div[pid=${id}]`).forEach((element) => {
832                // @ts-ignore
833                element.querySelector('.row-checkbox')!.checked = checked;
834                if (checked) {
835                  element.setAttribute('checked', '');
836                } else {
837                  element.removeAttribute('checked');
838                }
839                changeChildNode(element, checked);
840              });
841            };
842            changeChildNode(treeTblRowElement, e.detail.checked);
843          };
844          treeTblDiv.appendChild(checkbox);
845          treeTblRowElement.appendChild(treeTblDiv);
846        }
847        this.tableColumns!.forEach((treeTblColumn, index) => {
848          let dataIndex = treeTblColumn.getAttribute('data-index');
849          let treeTblEl;
850          if (index !== 0) {
851            gridTemplateColumns.push(treeTblColumn.getAttribute('width') || '1fr');
852            if (treeTblColumn.template) {
853              // @ts-ignore
854              let cloneNode = treeTblColumn.template.render(rowData).content.cloneNode(true);
855              treeTblEl = document.createElement('div');
856              treeTblEl.classList.add('td');
857              treeTblEl.style.wordBreak = 'break-all';
858              treeTblEl.style.justifyContent = treeTblColumn.getAttribute('align') || '';
859              if (treeTblColumn.hasAttribute('fixed')) {
860                this.fixed(treeTblEl, treeTblColumn.getAttribute('fixed') || '', '#ffffff');
861              }
862              treeTblEl.append(cloneNode);
863            } else {
864              treeTblEl = document.createElement('div');
865              treeTblEl.style.justifyContent = treeTblColumn.getAttribute('align') || '';
866              treeTblEl.style.wordBreak = 'break-all';
867              treeTblEl.classList.add('td');
868              if (treeTblColumn.hasAttribute('fixed')) {
869                this.fixed(treeTblEl, treeTblColumn.getAttribute('fixed') || '', '#ffffff');
870              }
871              // @ts-ignore
872              treeTblEl.innerHTML = this.formatName(dataIndex, rowData[dataIndex]);
873            }
874            treeTblRowElement.append(treeTblEl);
875          } else {
876            this.treeElement!.style.width = treeTblColumn.getAttribute('width') || '260px';
877            let treeElement = document.createElement('div');
878            treeElement.classList.add('tree-first-body');
879            if (treeTblColumn.template) {
880              // @ts-ignore
881              let firstCloneNode = treeTblColumn.template.render(rowData).content.cloneNode(true);
882              treeTblEl = document.createElement('div');
883              treeTblEl.classList.add('td');
884              treeTblEl.style.justifyContent = treeTblColumn.getAttribute('align') || '';
885              if (treeTblColumn.hasAttribute('fixed')) {
886                this.fixed(treeTblEl, treeTblColumn.getAttribute('fixed') || '', '#ffffff');
887              }
888              treeTblEl.append(firstCloneNode);
889            } else {
890              treeTblEl = document.createElement('div');
891              treeTblEl.style.justifyContent = treeTblColumn.getAttribute('align') || '';
892              treeTblEl.classList.add('td');
893              if (treeTblColumn.hasAttribute('fixed')) {
894                this.fixed(treeTblEl, treeTblColumn.getAttribute('fixed') || '', '#ffffff');
895              }
896              // @ts-ignore
897              treeTblEl.innerHTML = this.formatName(dataIndex, rowData[dataIndex]);
898            }
899            if (rowData.children && rowData.children.length > 0) {
900              let treeTblIcon = document.createElement('lit-icon');
901              treeTblIcon.classList.add('tree-icon');
902              // @ts-ignore
903              treeTblIcon.name = 'minus-square';
904              treeElement.append(treeTblIcon);
905              treeElement.append(treeTblEl);
906              treeElement.style.paddingLeft = offsetVal - 30 + 'px';
907            } else {
908              treeElement.append(treeTblEl);
909              treeElement.style.paddingLeft = offsetVal + 'px';
910            }
911            this.treeElement!.append(treeElement);
912          }
913        });
914        if (this.selectable) {
915          treeTblRowElement.style.gridTemplateColumns = '60px ' + gridTemplateColumns.join(' ');
916        } else {
917          treeTblRowElement.style.gridTemplateColumns = gridTemplateColumns.join(' ');
918        }
919        treeTblRowElement.onclick = (e) => {
920          this.dispatchEvent(
921            new CustomEvent('row-click', {
922              detail: rowData,
923              composed: true,
924            })
925          );
926        };
927        treeTblRowElement.style.cursor = 'pointer';
928        parentNode.append(treeTblRowElement);
929        treeTblRowElement.setAttribute('id', rowData[ids[0]]);
930        treeTblRowElement.setAttribute('pid', rowData[ids[1]]);
931        treeTblRowElement.setAttribute('expend', '');
932        if (rowData.children && rowData.children.length > 0) {
933          offsetVal = offsetVal + offset;
934          drawRow(rowData.children, parentNode);
935          offsetVal = offsetVal - offset;
936        }
937      });
938    };
939    drawRow(treeData, this.tbodyElement);
940  }
941
942  getCheckRows() {
943    // @ts-ignore
944    return [...this.shadowRoot!.querySelectorAll('div[class=tr][checked]')]
945      .map((a) => (a as any).data)
946      .map((a) => {
947        delete a['children'];
948        return a;
949      });
950  }
951
952  deleteRowsCondition(fn: any) {
953    this.shadowRoot!.querySelectorAll('div[class=tr]').forEach((tr) => {
954      // @ts-ignore
955      if (fn(tr.data)) {
956        tr.remove();
957      }
958    });
959  }
960
961  meauseElementHeight(rowData: any) {
962    return 27;
963  }
964
965  meauseTreeElementHeight(rowData: any, depth: number) {
966    return 27;
967  }
968
969
970
971  meauseAllRowHeight(list: any[]): TableRowObject[] {
972    this.tbodyElement!.innerHTML = '';
973    this.meauseRowElement = undefined;
974    let head = this.shadowRoot!.querySelector('.th');
975    this.tbodyElement && (this.tbodyElement.style.width = head?.clientWidth + 'px');
976    this.currentRecycleList = [];
977    let headHeight = 0;
978    let totalHeight = headHeight;
979    let visibleObjects: TableRowObject[] = [];
980    let itemHandler = (rowData: any, index: number) => {
981      let height = this.meauseElementHeight(rowData);
982      let tableRowObject = new TableRowObject();
983      tableRowObject.height = height;
984      tableRowObject.top = totalHeight;
985      tableRowObject.data = rowData;
986      tableRowObject.rowIndex = index;
987      if (
988        Math.max(totalHeight, this.tableElement!.scrollTop + headHeight) <=
989        Math.min(totalHeight + height, this.tableElement!.scrollTop + this.tableElement!.clientHeight + headHeight)
990      ) {
991        let newTableElement = this.createNewTableElement(tableRowObject);
992        newTableElement.style.transform = `translateY(${totalHeight}px)`;
993        this.tbodyElement?.append(newTableElement);
994        this.currentRecycleList.push(newTableElement);
995        let td = newTableElement?.querySelectorAll('.td');
996        if (tableRowObject.data.rowName === 'cpu-profiler') {
997          this.createTextColor(tableRowObject, td[0]);
998        }
999      }
1000      totalHeight += height;
1001      visibleObjects.push(tableRowObject);
1002    }
1003    let realIndex = 0;
1004    list.forEach((item, index) => {
1005      if (Array.isArray(item)) {
1006        item.forEach((rowData, childIndex) => {
1007          itemHandler(rowData, realIndex);
1008          realIndex++;
1009        });
1010      } else {
1011        itemHandler(item, index);
1012      }
1013    });
1014    this.tbodyElement && (this.tbodyElement.style.height = totalHeight + (this.isScrollXOutSide ? 0 : 0) + 'px');
1015    this.tableElement &&
1016      (this.tableElement.onscroll = (event) => {
1017        let tblScrollTop = this.tableElement!.scrollTop;
1018        let skip = 0;
1019        for (let i = 0; i < visibleObjects.length; i++) {
1020          if (
1021            visibleObjects[i].top <= tblScrollTop &&
1022            visibleObjects[i].top + visibleObjects[i].height >= tblScrollTop
1023          ) {
1024            skip = i;
1025            break;
1026          }
1027        }
1028        let reduce = this.currentRecycleList.map((item) => item.clientHeight).reduce((a, b) => a + b, 0);
1029        if (reduce == 0) {
1030          return;
1031        }
1032        while (reduce <= this.tableElement!.clientHeight) {
1033          let newTableElement = this.createNewTableElement(visibleObjects[skip]);
1034          this.tbodyElement?.append(newTableElement);
1035          this.currentRecycleList.push(newTableElement);
1036          reduce += newTableElement.clientHeight;
1037        }
1038        for (let i = 0; i < this.currentRecycleList.length; i++) {
1039          this.freshCurrentLine(this.currentRecycleList[i], visibleObjects[i + skip]);
1040          if (visibleObjects[i + skip]) {
1041            if (visibleObjects[i + skip].data.rowName === 'cpu-profiler') {
1042              this.createTextColor(visibleObjects[i + skip], this.currentRecycleList[i].childNodes[0]);
1043            }
1044          }
1045        }
1046      });
1047    return visibleObjects;
1048  }
1049
1050  meauseTreeRowElement(list: any[]): TableRowObject[] {
1051    this.meauseRowElement = undefined;
1052    this.tbodyElement!.innerHTML = '';
1053    this.treeElement!.innerHTML = '';
1054    let headHeight = this.theadElement?.clientHeight || 0;
1055    let totalHeight = 0;
1056    let visibleObjects: TableRowObject[] = [];
1057    this.currentRecycleList = [];
1058    this.currentTreeDivList = [];
1059    let resetAllHeight = (list: any[], depth: number, parentNode?: TableRowObject) => {
1060      list.forEach((item) => {
1061        let tableRowObject = new TableRowObject();
1062        tableRowObject.depth = depth;
1063        tableRowObject.data = item;
1064        tableRowObject.top = totalHeight;
1065        tableRowObject.height = this.meauseTreeElementHeight(tableRowObject, depth);
1066        if (parentNode != undefined) {
1067          parentNode.children.push(tableRowObject);
1068        }
1069        if (
1070          Math.max(totalHeight, this.tableElement!.scrollTop) <=
1071          Math.min(
1072            totalHeight + tableRowObject.height,
1073            this.tableElement!.scrollTop + this.tableElement!.clientHeight - headHeight
1074          )
1075        ) {
1076          let newTableElement = this.createNewTreeTableElement(tableRowObject);
1077          newTableElement.style.transform = `translateY(${totalHeight}px)`;
1078          this.tbodyElement?.append(newTableElement);
1079          if (this.treeElement?.lastChild) {
1080            (this.treeElement?.lastChild as HTMLElement).style.height = tableRowObject.height + 'px';
1081          }
1082          this.currentRecycleList.push(newTableElement);
1083        }
1084        totalHeight += tableRowObject.height;
1085        visibleObjects.push(tableRowObject);
1086        if (item.hasNext) {
1087          if (item.parents != undefined && item.parents.length > 0 && item.status) {
1088            resetAllHeight(item.parents, depth + 1, tableRowObject);
1089          } else if (item.children != undefined && item.children.length > 0 && item.status) {
1090            resetAllHeight(item.children, depth + 1, tableRowObject);
1091          }
1092        } else {
1093          if (item.children != undefined && item.children.length > 0) {
1094            resetAllHeight(item.children, depth + 1, tableRowObject);
1095          }
1096        }
1097      });
1098    };
1099    resetAllHeight(list, 0);
1100    this.tbodyElement && (this.tbodyElement.style.height = totalHeight + 'px');
1101    this.treeElement!.style.height = this.tableElement!.clientHeight - this.theadElement!.clientHeight + 'px';
1102    this.tableElement &&
1103      (this.tableElement.onscroll = (event) => {
1104        let visibleObjects = this.recycleDs.filter((item) => {
1105          return !item.rowHidden;
1106        });
1107        let top = this.tableElement!.scrollTop;
1108        this.treeElement!.style.transform = `translateY(${top}px)`;
1109        let skip = 0;
1110        for (let index = 0; index < visibleObjects.length; index++) {
1111          if (visibleObjects[index].top <= top && visibleObjects[index].top + visibleObjects[index].height >= top) {
1112            skip = index;
1113            break;
1114          }
1115        }
1116        let reduce = this.currentRecycleList.map((item) => item.clientHeight).reduce((a, b) => a + b, 0);
1117        if (reduce == 0) {
1118          return;
1119        }
1120        while (reduce <= this.tableElement!.clientHeight) {
1121          let newTableElement = this.createNewTreeTableElement(visibleObjects[skip]);
1122          this.tbodyElement?.append(newTableElement);
1123          if (this.treeElement?.lastChild) {
1124            (this.treeElement?.lastChild as HTMLElement).style.height = visibleObjects[skip].height + 'px';
1125          }
1126          this.currentRecycleList.push(newTableElement);
1127          reduce += newTableElement.clientHeight;
1128        }
1129        for (let i = 0; i < this.currentRecycleList.length; i++) {
1130          this.freshCurrentLine(
1131            this.currentRecycleList[i],
1132            visibleObjects[i + skip],
1133            this.treeElement?.children[i] as HTMLElement
1134          );
1135        }
1136      });
1137    return visibleObjects;
1138  }
1139
1140  createNewTreeTableElement(rowData: TableRowObject): any {
1141    let newTableElement = document.createElement('div');
1142    newTableElement.classList.add('tr');
1143    let gridTemplateColumns: Array<any> = [];
1144    let treeTop = 0;
1145    if (this.treeElement!.children?.length > 0) {
1146      let transX = Number((this.treeElement?.lastChild as HTMLElement).style.transform.replace(/[^0-9]/gi, ''));
1147      treeTop += transX + rowData.height;
1148    }
1149    this?.columns?.forEach((column: any, index) => {
1150      let dataIndex = column.getAttribute('data-index') || '1';
1151      let td: any;
1152      if (index === 0) {
1153        if (column.template) {
1154          td = column.template.render(rowData.data).content.cloneNode(true);
1155          td.template = column.template;
1156          td.title = rowData.data[dataIndex];
1157        } else {
1158          td = document.createElement('div');
1159          td.innerHTML = this.formatName(dataIndex, rowData.data[dataIndex]);
1160          td.dataIndex = dataIndex;
1161          td.title = rowData.data[dataIndex];
1162        }
1163        if (rowData.data.children && rowData.data.children.length > 0 && !rowData.data.hasNext) {
1164          let btn = this.createExpandBtn(rowData);
1165          td.insertBefore(btn, td.firstChild);
1166        }
1167        if (rowData.data.hasNext) {
1168          td.title = rowData.data.objectName;
1169          let btn = this.createBtn(rowData);
1170          td.insertBefore(btn, td.firstChild);
1171        }
1172        td.style.paddingLeft = rowData.depth * 15 + 'px';
1173        if (!rowData.data.children || rowData.data.children.length === 0) {
1174          td.style.paddingLeft = (15 * rowData.depth + 16) + 'px';
1175        }
1176        if (rowData.data.rowName === 'js-memory') {
1177          let nodeText = document.createElement('text');
1178          nodeText.classList.add('nodeName');
1179          nodeText.textContent = rowData.data.nodeName;
1180          td.append(nodeText);
1181          let countText = document.createElement('text');
1182          countText.classList.add('countName');
1183          countText.textContent = rowData.data.count;
1184          td.append(countText);
1185          let nodeIdText = document.createElement('text');
1186          nodeIdText.classList.add('nodeIdText');
1187          nodeIdText.textContent = rowData.data.nodeId;
1188          td.append(nodeIdText);
1189          if (rowData.data.edgeName != '') {
1190            let edgeNameText = document.createElement('text');
1191            edgeNameText.classList.add('edgeNameText');
1192            edgeNameText.textContent = rowData.data.edgeName;
1193            td.insertBefore(edgeNameText, nodeText);
1194            let span = document.createElement('span');
1195            span.classList.add('span');
1196            if (rowData.data.type === ConstructorType.RetainersType) {
1197              span.textContent = '\xa0' + 'in' + '\xa0';
1198              nodeIdText.textContent = ` @${rowData.data.id}`;
1199            } else {
1200              span.textContent = '\xa0' + '::' + '\xa0';
1201            }
1202            edgeNameText.append(span);
1203          }
1204          if (
1205            (rowData.data.nodeType == NodeType.STRING ||
1206              rowData.data.nodeType == NodeType.CONCATENATED_STRING ||
1207              rowData.data.nodeType == NodeType.SLICED_STRING) &&
1208            rowData.data.type != ConstructorType.ClassType
1209          ) {
1210            nodeText.style.color = '#d53d3d';
1211            nodeText.textContent = '"' + rowData.data.nodeName + '"';
1212          }
1213          td.title = rowData.data.objectName;
1214        }
1215        if (rowData.data.rowName === 'cpu-profiler') {
1216          this.createTextColor(rowData, td);
1217        }
1218        (td as any).data = rowData.data;
1219        td.classList.add('tree-first-body');
1220        td.style.position = 'absolute';
1221        td.style.top = '0px';
1222        td.style.left = '0px';
1223        td.onmouseenter = () => {
1224          let indexOf = this.currentTreeDivList.indexOf(td);
1225          this.currentRecycleList.forEach((row) => {
1226            row.classList.remove('mouse-in');
1227          });
1228          if (indexOf >= 0 && indexOf < this.currentRecycleList.length && td.innerHTML != '') {
1229            this.setMouseIn(true, [newTableElement]);
1230          }
1231        };
1232        td.onmouseleave = () => {
1233          let indexOf = this.currentTreeDivList.indexOf(td);
1234          if (indexOf >= 0 && indexOf < this.currentRecycleList.length) {
1235            this.setMouseIn(false, [newTableElement]);
1236          }
1237        };
1238        td.onclick = () => {
1239          let indexOf = this.currentTreeDivList.indexOf(td);
1240          this.dispatchRowClickEvent(rowData, [td, newTableElement]);
1241        };
1242        this.setHighLight(rowData.data.isSearch, td);
1243        this.treeElement!.style.width = column.getAttribute('width');
1244        this.treeElement?.append(td);
1245        this.currentTreeDivList.push(td);
1246      } else {
1247        gridTemplateColumns.push(column.getAttribute('width') || '1fr');
1248        td = document.createElement('div');
1249        td.classList.add('td');
1250        td.style.overflow = 'hidden';
1251        td.style.textOverflow = 'ellipsis';
1252        td.style.whiteSpace = 'nowrap';
1253        td.title = rowData.data[dataIndex];
1254        td.dataIndex = dataIndex;
1255        td.style.justifyContent = column.getAttribute('align') || 'flex-start';
1256        if (column.template) {
1257          td.appendChild(column.template.render(rowData.data).content.cloneNode(true));
1258          td.template = column.template;
1259        } else {
1260          td.innerHTML = this.formatName(dataIndex, rowData.data[dataIndex]);
1261        }
1262        newTableElement.append(td);
1263      }
1264    });
1265    let lastChild = this.treeElement?.lastChild as HTMLElement;
1266    if (lastChild) {
1267      lastChild.style.transform = `translateY(${treeTop}px)`;
1268    }
1269    (newTableElement as any).data = rowData.data;
1270    newTableElement.style.gridTemplateColumns = gridTemplateColumns.join(' ');
1271    newTableElement.style.position = 'absolute';
1272    newTableElement.style.top = '0px';
1273    newTableElement.style.left = '0px';
1274    newTableElement.style.cursor = 'pointer';
1275    this.setHighLight(rowData.data.isSearch, newTableElement);
1276    newTableElement.onmouseenter = () => {
1277      if ((newTableElement as any).data.isSelected) return;
1278      let indexOf = this.currentRecycleList.indexOf(newTableElement);
1279      this.currentTreeDivList.forEach((row) => {
1280        row.classList.remove('mouse-in');
1281      });
1282      if (indexOf >= 0 && indexOf < this.treeElement!.children.length) {
1283        this.setMouseIn(true, [this.treeElement?.children[indexOf] as HTMLElement]);
1284      }
1285    };
1286    newTableElement.onmouseleave = () => {
1287      if ((newTableElement as any).data.isSelected) return;
1288      let indexOf = this.currentRecycleList.indexOf(newTableElement);
1289      if (indexOf >= 0 && indexOf < this.treeElement!.children.length) {
1290        this.setMouseIn(false, [this.treeElement?.children[indexOf] as HTMLElement]);
1291      }
1292    };
1293    newTableElement.onclick = (e) => {
1294      let indexOf = this.currentRecycleList.indexOf(newTableElement);
1295      this.dispatchRowClickEvent(rowData, [this.treeElement?.children[indexOf] as HTMLElement, newTableElement]);
1296    };
1297    return newTableElement;
1298  }
1299
1300  createBtn(rowData: any) {
1301    let btn: any = document.createElement('lit-icon');
1302    btn.classList.add('tree-icon');
1303    if (rowData.data.expanded) {
1304      btn.name = 'plus-square';
1305    } else {
1306      btn.name = 'minus-square';
1307    }
1308    btn.addEventListener('click', (e: any) => {
1309      rowData.data.status = false;
1310      const resetNodeHidden = (hidden: boolean, rowData: any) => {
1311        if (hidden) {
1312          rowData.children.forEach((child: any) => {
1313            child.rowHidden = false;
1314          });
1315        } else {
1316          rowData.children.forEach((child: any) => {
1317            child.rowHidden = true;
1318            resetNodeHidden(hidden, child);
1319          });
1320        }
1321      };
1322
1323      if (rowData.data.expanded) {
1324        rowData.data.status = true;
1325        this.dispatchRowClickEventIcon(rowData, [btn]);
1326        rowData.data.expanded = false;
1327        resetNodeHidden(true, rowData);
1328      } else {
1329        rowData.data.expanded = true;
1330        rowData.data.status = false;
1331        resetNodeHidden(false, rowData);
1332      }
1333      this.reMeauseHeight();
1334    });
1335    return btn;
1336  }
1337
1338  createExpandBtn(rowData: any) {
1339    let btn: any = document.createElement('lit-icon');
1340    btn.classList.add('tree-icon');
1341    // @ts-ignore
1342    if (rowData.expanded) {
1343      btn.name = 'minus-square';
1344    } else {
1345      btn.name = 'plus-square';
1346    }
1347    btn.onclick = (e: Event) => {
1348      const resetNodeHidden = (hidden: boolean, rowData: any) => {
1349        if (rowData.children.length > 0) {
1350          if (hidden) {
1351            rowData.children.forEach((child: any) => {
1352              child.rowHidden = true;
1353              resetNodeHidden(hidden, child);
1354            });
1355          } else {
1356            rowData.children.forEach((child: any) => {
1357              child.rowHidden = !rowData.expanded;
1358              if (rowData.expanded) {
1359                resetNodeHidden(hidden, child);
1360              }
1361            });
1362          }
1363        }
1364      };
1365
1366      if (rowData.expanded) {
1367        rowData.expanded = false;
1368        resetNodeHidden(true, rowData);
1369      } else {
1370        rowData.expanded = true;
1371        resetNodeHidden(false, rowData);
1372      }
1373      this.reMeauseHeight();
1374      e.stopPropagation();
1375    };
1376    return btn;
1377  }
1378
1379  reMeauseHeight() {
1380    if (this.currentRecycleList.length == 0) {
1381      return;
1382    }
1383    let totalHeight = 0;
1384    this.recycleDs.forEach((it) => {
1385      if (!it.rowHidden) {
1386        it.top = totalHeight;
1387        totalHeight += it.height;
1388      }
1389    });
1390    this.tbodyElement && (this.tbodyElement.style.height = totalHeight + (this.isScrollXOutSide ? 0 : 0) + 'px');
1391    this.treeElement!.style.height = this.tableElement!.clientHeight - this.theadElement!.clientHeight + 'px';
1392    let visibleObjects = this.recycleDs.filter((item) => {
1393      return !item.rowHidden;
1394    });
1395    let top = this.tableElement!.scrollTop;
1396    let skip = 0;
1397    for (let i = 0; i < visibleObjects.length; i++) {
1398      if (visibleObjects[i].top <= top && visibleObjects[i].top + visibleObjects[i].height >= top) {
1399        skip = i;
1400        break;
1401      }
1402    }
1403    let reduce = this.currentRecycleList.map((item) => item.clientHeight).reduce((a, b) => a + b, 0);
1404    if (reduce == 0) {
1405      return;
1406    }
1407    while (reduce <= this.tableElement!.clientHeight) {
1408      let newTableElement;
1409      if (this.hasAttribute('tree')) {
1410        newTableElement = this.createNewTreeTableElement(visibleObjects[skip]);
1411      } else {
1412        newTableElement = this.createNewTableElement(visibleObjects[skip]);
1413      }
1414      this.tbodyElement?.append(newTableElement);
1415      if (this.hasAttribute('tree')) {
1416        if (this.treeElement?.lastChild) {
1417          (this.treeElement?.lastChild as HTMLElement).style.height = visibleObjects[skip].height + 'px';
1418        }
1419      }
1420      this.currentRecycleList.push(newTableElement);
1421      reduce += newTableElement.clientHeight;
1422    }
1423    for (let i = 0; i < this.currentRecycleList.length; i++) {
1424      if (this.hasAttribute('tree')) {
1425        this.freshCurrentLine(
1426          this.currentRecycleList[i],
1427          visibleObjects[i + skip],
1428          this.treeElement?.children[i] as HTMLElement
1429        );
1430      } else {
1431        this.freshCurrentLine(this.currentRecycleList[i], visibleObjects[i + skip]);
1432        if (visibleObjects[i + skip]) {
1433          if (visibleObjects[i + skip].data.rowName === 'cpu-profiler') {
1434            this.createTextColor(visibleObjects[i + skip], this.currentRecycleList[i].childNodes[0]);
1435          }
1436        }
1437      }
1438    }
1439  }
1440
1441  createNewTableElement(rowData: any): any {
1442    let newTableElement = document.createElement('div');
1443    newTableElement.classList.add('tr');
1444    let gridTemplateColumns: Array<any> = [];
1445    this?.columns?.forEach((column: any) => {
1446      let dataIndex = column.getAttribute('data-index') || '1';
1447      gridTemplateColumns.push(column.getAttribute('width') || '1fr');
1448      let td: any;
1449      td = document.createElement('div');
1450      td.classList.add('td');
1451      td.style.overflow = 'hidden';
1452      td.style.textOverflow = 'ellipsis';
1453      td.style.whiteSpace = 'nowrap';
1454      td.dataIndex = dataIndex;
1455      td.style.justifyContent = column.getAttribute('align') || 'flex-start';
1456      td.title = rowData.data[dataIndex];
1457      if (column.template) {
1458        td.appendChild(column.template.render(rowData.data).content.cloneNode(true));
1459        td.template = column.template;
1460      } else {
1461        td.innerHTML = this.formatName(dataIndex, rowData.data[dataIndex]);
1462      }
1463      newTableElement.append(td);
1464    });
1465    newTableElement.onclick = () => {
1466      this.dispatchRowClickEvent(rowData, [newTableElement]);
1467    };
1468    newTableElement.onmouseenter = () => {
1469      this.dispatchRowHoverEvent(rowData, [newTableElement]);
1470    };
1471    if (rowData.data.isSelected != undefined) {
1472      this.setSelectedRow(rowData.data.isSelected, [newTableElement]);
1473    }
1474    (newTableElement as any).data = rowData.data;
1475    newTableElement.style.cursor = 'pointer';
1476    newTableElement.style.gridTemplateColumns = gridTemplateColumns.join(' ');
1477    newTableElement.style.position = 'absolute';
1478    newTableElement.style.top = '0px';
1479    newTableElement.style.left = '0px';
1480    if (this.getItemTextColor) {
1481      newTableElement.style.color = this.getItemTextColor(rowData.data);
1482    }
1483    return newTableElement;
1484  }
1485
1486  freshCurrentLine(element: HTMLElement, rowObject: TableRowObject, firstElement?: HTMLElement) {
1487    if (!rowObject) {
1488      if (firstElement) {
1489        firstElement.style.display = 'none';
1490      }
1491      element.style.display = 'none';
1492      return;
1493    }
1494    let childIndex = -1;
1495    this.setHighLight(rowObject.data.isSearch, element);
1496    element.childNodes.forEach((child) => {
1497      if (child.nodeType != 1) return;
1498      childIndex++;
1499      let idx = firstElement != undefined ? childIndex + 1 : childIndex;
1500      if (firstElement != undefined && childIndex == 0) {
1501        this.setHighLight(rowObject.data.isSearch, firstElement);
1502        (firstElement as any).data = rowObject.data;
1503        if ((this.columns![0] as any).template) {
1504          firstElement.innerHTML = (this.columns![0] as any).template
1505            .render(rowObject.data)
1506            .content.cloneNode(true).innerHTML;
1507        } else {
1508          let dataIndex = this.columns![0].getAttribute('data-index') || '1';
1509          firstElement.innerHTML = this.formatName(dataIndex, rowObject.data[dataIndex]);
1510          firstElement.title = rowObject.data[dataIndex];
1511        }
1512        if (rowObject.children && rowObject.children.length > 0 && !rowObject.data.hasNext) {
1513          let btn = this.createExpandBtn(rowObject);
1514          firstElement.insertBefore(btn, firstElement.firstChild);
1515        }
1516        firstElement.style.paddingLeft = 15 * rowObject.depth + 'px';
1517        if (!rowObject.children || rowObject.children.length === 0) {
1518          firstElement.style.paddingLeft = 15 * rowObject.depth + 16 + 'px';
1519        }
1520        if (rowObject.data.hasNext) {
1521          let btn = this.createBtn(rowObject);
1522          firstElement.title = rowObject.data.objectName;
1523          firstElement.insertBefore(btn, firstElement.firstChild);
1524          firstElement.style.paddingLeft = 15 * rowObject.depth + 'px';
1525        }
1526        if (rowObject.data.rowName === 'js-memory') {
1527          let nodeText = document.createElement('text');
1528          nodeText.classList.add('nodeName');
1529          nodeText.textContent = rowObject.data.nodeName;
1530          firstElement.append(nodeText);
1531          let countText = document.createElement('text');
1532          countText.classList.add('countName');
1533          countText.textContent = rowObject.data.count;
1534          firstElement.append(countText);
1535          let nodeIdText = document.createElement('text');
1536          nodeIdText.classList.add('nodeIdText');
1537          nodeIdText.textContent = rowObject.data.nodeId;
1538          firstElement.append(nodeIdText);
1539          if (rowObject.data.edgeName != '') {
1540            let edgeNameText = document.createElement('text');
1541            edgeNameText.classList.add('edgeNameText');
1542            edgeNameText.textContent = rowObject.data.edgeName;
1543            firstElement.insertBefore(edgeNameText, nodeText);
1544            let span = document.createElement('span');
1545            span.classList.add('span');
1546            if (rowObject.data.type === ConstructorType.RetainersType) {
1547              span.textContent = '\xa0' + 'in' + '\xa0';
1548              nodeIdText.textContent = ` @${rowObject.data.id}`;
1549            } else {
1550              span.textContent = '\xa0' + '::' + '\xa0';
1551            }
1552            edgeNameText.append(span);
1553          }
1554          if (
1555            (rowObject.data.nodeType == NodeType.STRING ||
1556              rowObject.data.nodeType == NodeType.CONCATENATED_STRING ||
1557              rowObject.data.nodeType == NodeType.SLICED_STRING) &&
1558            rowObject.data.type != ConstructorType.ClassType
1559          ) {
1560            nodeText.style.color = '#d53d3d';
1561            nodeText.textContent = '"' + rowObject.data.nodeName + '"';
1562          }
1563          firstElement.title = rowObject.data.objectName;
1564        }
1565        if (rowObject.data.rowName === 'cpu-profiler') {
1566          this.createTextColor(rowObject, firstElement);
1567        }
1568        firstElement.onclick = () => {
1569          this.dispatchRowClickEvent(rowObject, [firstElement, element]);
1570        };
1571        firstElement.style.transform = `translateY(${rowObject.top - this.tableElement!.scrollTop}px)`;
1572        if (rowObject.data.isSelected != undefined) {
1573          this.setSelectedRow(rowObject.data.isSelected, [firstElement]);
1574        } else {
1575          this.setSelectedRow(false, [firstElement]);
1576        }
1577      }
1578      let dataIndex = this.columns![idx].getAttribute('data-index') || '1';
1579      if ((this.columns![idx] as any).template) {
1580        (child as HTMLElement).innerHTML = '';
1581        (child as HTMLElement).appendChild(
1582          (this.columns![idx] as any).template.render(rowObject.data).content.cloneNode(true)
1583        );
1584        (child as HTMLElement).title = rowObject.data[dataIndex];
1585      } else {
1586        (child as HTMLElement).innerHTML = this.formatName(dataIndex, rowObject.data[dataIndex]);
1587        (child as HTMLElement).title = rowObject.data[dataIndex];
1588      }
1589    });
1590    if (element.style.display == 'none') {
1591      element.style.display = 'grid';
1592    }
1593    element.style.transform = `translateY(${rowObject.top}px)`;
1594    if (firstElement && firstElement.style.display == 'none') {
1595      firstElement.style.display = 'flex';
1596    }
1597    element.onclick = (e) => {
1598      if (firstElement != undefined) {
1599        this.dispatchRowClickEvent(rowObject, [firstElement, element]);
1600      } else {
1601        this.dispatchRowClickEvent(rowObject, [element]);
1602      }
1603    };
1604    element.onmouseenter = () => {
1605      this.dispatchRowHoverEvent(rowObject, [element]);
1606    };
1607    (element as any).data = rowObject.data;
1608    if (rowObject.data.isSelected != undefined) {
1609      this.setSelectedRow(rowObject.data.isSelected, [element]);
1610    } else {
1611      this.setSelectedRow(false, [element]);
1612    }
1613    if (rowObject.data.isHover != undefined) {
1614      this.setMouseIn(rowObject.data.isHover, [element]);
1615    } else {
1616      this.setMouseIn(false, [element]);
1617    }
1618    if (this.getItemTextColor) {
1619      element.style.color = this.getItemTextColor((element as any).data);
1620    }
1621  }
1622
1623  setSelectedRow(isSelected: boolean, rows: any[]) {
1624    if (isSelected) {
1625      rows.forEach((row) => {
1626        if (row.classList.contains('mouse-in')) row.classList.remove('mouse-in');
1627        row.classList.add('mouse-select');
1628      });
1629    } else {
1630      rows.forEach((row) => {
1631        row.classList.remove('mouse-select');
1632      });
1633    }
1634  }
1635
1636  setMouseIn(isMouseIn: boolean, rows: any[]) {
1637    if (isMouseIn) {
1638      rows.forEach((row) => {
1639        row.classList.add('mouse-in');
1640      });
1641    } else {
1642      rows.forEach((row) => {
1643        row.classList.remove('mouse-in');
1644      });
1645    }
1646  }
1647
1648  scrollToData(data: any) {
1649    if (this.isRecycleList) {
1650      if (this.recycleDs.length > 0) {
1651        let filter = this.recycleDs.filter((item) => {
1652          return item.data == data;
1653        });
1654        if (filter.length > 0) {
1655          this.tableElement!.scrollTop = filter[0].top;
1656        }
1657        this.setCurrentSelection(data);
1658      }
1659    } else {
1660      if (this.normalDs.length > 0) {
1661        let filter = this.normalDs.filter((item) => {
1662          return item.data == data;
1663        });
1664        if (filter.length > 0) {
1665          this.tableElement!.scrollTop = filter[0].top;
1666        }
1667      }
1668    }
1669  }
1670
1671  expandList(datasource: any[]) {
1672    let filter = this.recycleDs.filter((item) => {
1673      return datasource.indexOf(item.data) != -1;
1674    });
1675    if (filter.length > 0) {
1676      filter.forEach((item) => {
1677        item.expanded = true;
1678        item.rowHidden = false;
1679      });
1680    }
1681    this.reMeauseHeight();
1682  }
1683
1684  clearAllSelection(rowObjectData: any) {
1685    if (this.isRecycleList) {
1686      this.recycleDs.forEach((item) => {
1687        if (item.data != rowObjectData && item.data.isSelected) {
1688          item.data.isSelected = false;
1689        }
1690      });
1691      this.setSelectedRow(false, this.currentTreeDivList);
1692      this.setSelectedRow(false, this.currentRecycleList);
1693    } else {
1694      this.dataSource.forEach((item) => {
1695        if (item != rowObjectData && item.isSelected) {
1696          item.isSelected = false;
1697        }
1698      });
1699      this.setSelectedRow(false, this.normalDs);
1700    }
1701  }
1702
1703  clearAllHover(rowObjectData: any) {
1704    if (this.isRecycleList) {
1705      this.recycleDs.forEach((item) => {
1706        if (item.data != rowObjectData && item.data.isHover) {
1707          item.data.isHover = false;
1708        }
1709      });
1710      this.setMouseIn(false, this.currentTreeDivList);
1711      this.setMouseIn(false, this.currentRecycleList);
1712    } else {
1713      this.dataSource.forEach((item) => {
1714        if (item != rowObjectData && item.isHover) {
1715          item.isHover = false;
1716        }
1717      });
1718      this.setMouseIn(false, this.normalDs);
1719    }
1720  }
1721
1722  mouseOut() {
1723    if (this.isRecycleList) {
1724      this.recycleDs.forEach((item) => (item.data.isHover = false));
1725      this.setMouseIn(false, this.currentTreeDivList);
1726      this.setMouseIn(false, this.currentRecycleList);
1727    } else {
1728      this.dataSource.forEach((item) => (item.isHover = false));
1729      this.setMouseIn(false, this.normalDs);
1730    }
1731    this.dispatchEvent(
1732      new CustomEvent('row-hover', {
1733        detail: {
1734          data: undefined,
1735        },
1736        composed: true,
1737      })
1738    );
1739  }
1740
1741  setCurrentSelection(selectionData: any) {
1742    if (this.isRecycleList) {
1743      if (selectionData.isSelected != undefined) {
1744        this.currentTreeDivList.forEach((itemEl) => {
1745          if ((itemEl as any).data == selectionData) {
1746            this.setSelectedRow(selectionData.isSelected, [itemEl]);
1747          }
1748        });
1749        this.currentRecycleList.forEach((recycleItem) => {
1750          if ((recycleItem as any).data == selectionData) {
1751            this.setSelectedRow(selectionData.isSelected, [recycleItem]);
1752          }
1753        });
1754      }
1755    } else {
1756      if (selectionData.isSelected != undefined) {
1757        this.normalDs.forEach((item) => {
1758          if ((item as any).data == selectionData) {
1759            this.setSelectedRow(selectionData.isSelected, [item]);
1760          }
1761        });
1762      }
1763    }
1764  }
1765
1766  setCurrentHover(data: any) {
1767    if (this.isRecycleList) {
1768      this.setMouseIn(false, this.currentTreeDivList);
1769      this.setMouseIn(false, this.currentRecycleList);
1770      if (data.isHover != undefined) {
1771        this.currentTreeDivList.forEach((hoverItem) => {
1772          if ((hoverItem as any).data == data) {
1773            this.setMouseIn(data.isHover, [hoverItem]);
1774          }
1775        });
1776        this.currentRecycleList.forEach((hoverItem) => {
1777          if ((hoverItem as any).data == data) {
1778            this.setMouseIn(data.isHover, [hoverItem]);
1779          }
1780        });
1781      }
1782    } else {
1783      this.setMouseIn(false, this.normalDs);
1784      if (data.isHover != undefined) {
1785        this.normalDs.forEach((item) => {
1786          if ((item as any).data == data) {
1787            this.setMouseIn(data.isHover, [item]);
1788          }
1789        });
1790      }
1791    }
1792  }
1793
1794  dispatchRowClickEventIcon(rowData: any, elements: any[]) {
1795    this.dispatchEvent(
1796      new CustomEvent('icon-click', {
1797        detail: {
1798          ...rowData.data,
1799          data: rowData.data,
1800          callBack: (isSelected: boolean) => {
1801            //是否爲单选
1802            if (isSelected) {
1803              this.clearAllSelection(rowData.data);
1804            }
1805            this.setSelectedRow(rowData.data.isSelected, elements);
1806          },
1807        },
1808        composed: true,
1809      })
1810    );
1811  }
1812
1813  dispatchRowClickEvent(rowObject: any, elements: any[]) {
1814    this.dispatchEvent(
1815      new CustomEvent('row-click', {
1816        detail: {
1817          ...rowObject.data,
1818          data: rowObject.data,
1819          callBack: (isSelected: boolean) => {
1820            //是否爲单选
1821            if (isSelected) {
1822              this.clearAllSelection(rowObject.data);
1823            }
1824            this.setSelectedRow(rowObject.data.isSelected, elements);
1825          },
1826        },
1827        composed: true,
1828      })
1829    );
1830  }
1831
1832  dispatchRowHoverEvent(rowObject: any, elements: any[]) {
1833    this.dispatchEvent(
1834      new CustomEvent('row-hover', {
1835        detail: {
1836          data: rowObject.data,
1837          callBack: () => {
1838            this.clearAllHover(rowObject.data);
1839            this.setMouseIn(rowObject.data.isHover, elements);
1840          },
1841        },
1842        composed: true,
1843      })
1844    );
1845  }
1846
1847  formatName(key: string, name: any) {
1848    let content = name;
1849    if (this.itemTextHandleMap.has(key)) {
1850      content = this.itemTextHandleMap.get(key)?.(name) || '';
1851    }
1852    if (content !== undefined && content !== null) {
1853      return content.toString().replace(/</g, '&lt;').replace(/>/g, '&gt;');
1854    }
1855    return '';
1856  }
1857
1858  setHighLight(isSearch: boolean, element: any) {
1859    if (isSearch) {
1860      element.setAttribute('high-light', '');
1861    } else {
1862      element.removeAttribute('high-light');
1863    }
1864  }
1865
1866  createTextColor(rowData: any, divElement: any) {
1867    let nodeText = document.createElement('text');
1868    nodeText.classList.add('functionName');
1869    nodeText.textContent = rowData.data.name;
1870    divElement.append(nodeText);
1871    if (rowData.data.scriptName !== 'unknown') {
1872      let scriptText = document.createElement('text');
1873      scriptText.classList.add('scriptName');
1874      scriptText.textContent = rowData.data.scriptName;
1875      divElement.append(scriptText);
1876      scriptText.style.color = '#a1a1a1';
1877    }
1878    divElement.title = rowData.data.symbolName;
1879  }
1880}
1881