1/* 2 * Copyright (C) 2024 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 */ 15import {TabPaneApSummaryHtml} from './TabPaneApSummary.html.js'; 16 17export class TabPaneApSummary extends HTMLElement { 18 static jsonData = null; 19 constructor() { 20 super(); 21 this.apDataSource = []; 22 this.apData = []; 23 this.apTreeNodes = []; 24 this.expandedNodeList = new Set(); 25 this.selectTreeDepth = 0; 26 fetch('/ap/config.json') 27 .then(response => response.json()) 28 .then(data => { 29 TabPaneApSummary.jsonData = data; 30 this.expansionClickEvent = () => { 31 let apItem; 32 this.expandedNodeList.clear(); 33 if (((apItem = this.expansionUpIcon) === null || apItem === void 0 ? void 0 : apItem.name) === 'down') { 34 this.selectTreeDepth = 0; 35 this.expansionUpIcon.name = 'up'; 36 this.expansionDownIcon.name = 'down'; 37 } else { 38 this.selectTreeDepth = TabPaneApSummary.jsonData.summaryTreeLevel.length; 39 this.expansionUpIcon.name = 'down'; 40 this.expansionDownIcon.name = 'up'; 41 } 42 this.refreshSelectDepth(this.apTreeNodes); 43 this.refreshRowNodeTable(true); 44 }; 45 this.attachShadow({mode: 'open'}).innerHTML = this.initHtml(); 46 this.initElements(); 47 }); 48 } 49 50 set data(apDatas) { 51 this.apDataSource = []; 52 this.expandedNodeList.clear(); 53 this.expansionUpIcon.name = 'up'; 54 this.expansionDownIcon.name = 'down'; 55 this.apSummaryTable.innerHTML = ''; 56 this.apDataSource = apDatas; 57 this.apData = this.apDataSource; 58 if (this.apData.length !== 0) { 59 this.refreshRowNodeTable(); 60 } 61 } 62 63 filterData(filter) { 64 const keysOfApBean = TabPaneApSummary.jsonData.filterKeys; 65 if (filter === '') { 66 this.apData = this.apDataSource; 67 } else { 68 this.apData = this.apDataSource.filter((item) => { 69 return keysOfApBean.some(field => { 70 const value = item[field]; 71 return value !== undefined && value !== null && value.toString().toLowerCase().includes(filter); 72 }); 73 }); 74 } 75 this.expandedNodeList.clear(); 76 this.expansionUpIcon.name = 'up'; 77 this.expansionDownIcon.name = 'down'; 78 this.apSummaryTable.innerHTML = ''; 79 this.refreshRowNodeTable(); 80 } 81 82 initElements() { 83 this.apSummaryTable = this.shadowRoot?.querySelector('#tab-summary'); 84 this.expansionDiv = this.shadowRoot?.querySelector('.expansion-div'); 85 this.expansionUpIcon = this.shadowRoot?.querySelector('.expansion-up-icon'); 86 this.expansionDownIcon = this.shadowRoot?.querySelector('.expansion-down-icon'); 87 let summaryTreeLevel = TabPaneApSummary.jsonData.summaryTreeLevel; 88 this.shadowRoot?.querySelectorAll('.head-label').forEach((summaryTreeHead) => { 89 summaryTreeHead.addEventListener('click', () => { 90 this.selectTreeDepth = summaryTreeLevel.indexOf(summaryTreeHead.textContent); 91 this.expandedNodeList.clear(); 92 this.refreshSelectDepth(this.apTreeNodes); 93 this.refreshRowNodeTable(true); 94 }); 95 }); 96 this.apSummaryTable.onscroll = () => { 97 let apTreeTableEl = this.shadowRoot?.querySelector('.ap-tree-table'); 98 if (apTreeTableEl) { 99 apTreeTableEl.scrollTop = (this.apSummaryTable?.scrollTop) || 0; 100 } 101 }; 102 } 103 104 expansionAll() { 105 this.selectTreeDepth = TabPaneApSummary.jsonData.summaryTreeLevel.length - 1; 106 this.expandedNodeList.clear(); 107 this.refreshSelectDepth(this.apTreeNodes); 108 this.refreshRowNodeTable(true); 109 } 110 111 initHtml() { 112 return TabPaneApSummaryHtml; 113 } 114 115 connectedCallback() { 116 new ResizeObserver(() => { 117 this.parentElement.style.overflow = 'hidden'; 118 this.refreshRowNodeTable(); 119 }).observe(this.parentElement); 120 this.expansionDiv?.addEventListener('click', this.expansionClickEvent); 121 } 122 123 disconnectedCallback() { 124 this.expansionDiv?.removeEventListener('click', this.expansionClickEvent); 125 } 126 127 refreshSelectDepth(apTreeNodes) { 128 apTreeNodes.forEach((item) => { 129 if (item.depth < this.selectTreeDepth) { 130 this.expandedNodeList.add(item.id); 131 if (item.children.length > 0) { 132 this.refreshSelectDepth(item.children); 133 } 134 } 135 }); 136 } 137 138 createTr(rowNode, className, proper) { 139 let elementTr = document.createElement('tr'); 140 let elementTd = document.createElement('td'); 141 elementTr.title = rowNode[proper]; 142 elementTd.textContent = rowNode[proper]; 143 elementTd.className = className; 144 elementTr.appendChild(elementTd); 145 return elementTr; 146 } 147 148 createRowNodeTableEL(rowNodeList, tableTreeEl, tableRightDivs) { 149 let unitPadding = 20; 150 let leftPadding = 5; 151 rowNodeList.forEach((rowNode) => { 152 let tableTreeRowEl = document.createElement('tr'); 153 tableTreeRowEl.className = 'tree-row-tr'; 154 tableTreeRowEl.title = `${rowNode.apName}`; 155 let leftSpacingEl = document.createElement('td'); 156 leftSpacingEl.style.paddingLeft = `${rowNode.depth * unitPadding + leftPadding}px`; 157 tableTreeRowEl.appendChild(leftSpacingEl); 158 this.addToggleIconEl(rowNode, tableTreeRowEl); 159 let rowNodeTextEL = document.createElement('td'); 160 rowNodeTextEL.textContent = `${rowNode.apName}`; 161 rowNodeTextEL.className = 'row-name-td'; 162 tableTreeRowEl.appendChild(rowNodeTextEL); 163 tableTreeEl.appendChild(tableTreeRowEl); 164 let apTrs = TabPaneApSummary.jsonData.apTableTr; 165 for (let index = 0; index < apTrs.length; index++) { 166 let item = apTrs[index]; 167 Object.keys(item).forEach((key) => { 168 tableRightDivs[index].appendChild(this.createTr(rowNode, key, item[key])); 169 }); 170 } 171 if (rowNode.children && this.expandedNodeList.has(rowNode.id)) { 172 this.createRowNodeTableEL(rowNode.children, tableTreeEl, tableRightDivs); 173 } 174 }); 175 } 176 177 addToggleIconEl(rowNode, tableRowEl) { 178 let toggleIconEl = document.createElement('td'); 179 let expandIcon = document.createElement('lit-icon'); 180 expandIcon.classList.add('tree-icon'); 181 if (rowNode.children && rowNode.children.length > 0) { 182 toggleIconEl.appendChild(expandIcon); 183 expandIcon.name = this.expandedNodeList.has(rowNode.id) ? 'minus-square' : 'plus-square'; 184 toggleIconEl.classList.add('expand-icon'); 185 toggleIconEl.addEventListener('click', () => { 186 let scrollTop = this.apSummaryTable?.scrollTop ?? 0; 187 this.changeNode(rowNode.id); 188 this.apSummaryTable.scrollTop = scrollTop; 189 let apTreeTableEl = this.shadowRoot?.querySelector('.ap-tree-table'); 190 if (apTreeTableEl) { 191 apTreeTableEl.scrollTop = scrollTop; 192 } 193 }); 194 } 195 tableRowEl.appendChild(toggleIconEl); 196 } 197 198 changeNode(currentNode) { 199 if (this.expandedNodeList.has(currentNode)) { 200 this.expandedNodeList.delete(currentNode); 201 } else { 202 this.expandedNodeList.add(currentNode); 203 } 204 this.refreshRowNodeTable(); 205 } 206 207 refreshRowNodeTable(useCacheRefresh = false) { 208 if (this.apSummaryTable === undefined) { 209 return; 210 } 211 this.apSummaryTable.innerHTML = ''; 212 if (this.apSummaryTable && this.parentElement) { 213 this.apSummaryTable.style.height = `${this.parentElement.clientHeight - 30}px`; 214 } 215 if (!useCacheRefresh) { 216 this.apTreeNodes = this.buildTreeTblNodes(this.apData); 217 } 218 let tableFragmentEl = document.createDocumentFragment(); 219 let tableTreeEl = document.createElement('div'); 220 tableTreeEl.className = 'ap-tree-table'; 221 let apTrs = TabPaneApSummary.jsonData.apTableTr; 222 let tableRightDivs = []; 223 for (let index = 0; index < apTrs.length; index++) { 224 tableRightDivs.push(document.createElement('div')); 225 } 226 if (this.parentElement) { 227 tableTreeEl.style.height = `${this.parentElement.clientHeight - 40}px`; 228 } 229 this.createRowNodeTableEL(this.apTreeNodes, tableTreeEl, tableRightDivs); 230 let emptyTr = document.createElement('tr'); 231 emptyTr.className = 'tree-row-tr'; 232 tableTreeEl === null || tableTreeEl === void 0 ? void 0 : tableTreeEl.appendChild(emptyTr); 233 tableFragmentEl.appendChild(tableTreeEl); 234 for (let index = 0; index < tableRightDivs.length; index++) { 235 let emptyItemTr = document.createElement('tr'); 236 emptyItemTr.className = 'tree-row-tr'; 237 tableRightDivs[index].appendChild(emptyItemTr); 238 tableFragmentEl.appendChild(tableRightDivs[index]); 239 } 240 this.apSummaryTable.appendChild(tableFragmentEl); 241 } 242 243 buildTreeTblNodes(apTreeNodes) { 244 let id = 0; 245 let root = { 246 id: id, 247 depth: 0, 248 children: [], 249 apName: 'All', 250 type: '', 251 isRoot: '', 252 apKind: '', 253 apAbcId: '', 254 apId: '' 255 }; 256 apTreeNodes.forEach((item) => { 257 id++; 258 let moduleNode = root.children.find((node) => node.apName === item.moduleName); 259 let result = this.buildItem(moduleNode, id, item, root); 260 id = result.id; 261 let offsetNode = result.offsetNode; 262 if (offsetNode.depth === 2) { 263 let typeNode; 264 id++; 265 typeNode = { 266 id: id, depth: 3, children: [], apName: item.type, type: '', 267 isRoot: `${item.isRoot}`, 268 apKind: item.apKind === '-' ? '-' : TabPaneApSummary.KindMap[item.apKind === undefined ? 269 'UnknowId' : item.apKind], 270 apAbcId: `${item.apAbcId}`, 271 apId: `${item.apId}` 272 }; 273 offsetNode.children.push(typeNode); 274 } 275 }); 276 return root.children.sort((leftData, rightData) => { 277 return leftData.apName.localeCompare(rightData.apName); 278 }); 279 } 280 281 buildItem(moduleNode, id, item, root) { 282 if (!moduleNode) { 283 id++; 284 moduleNode = { 285 id: id, depth: 0, 286 children: [], 287 apName: item.moduleName, 288 type: '', 289 isRoot: '-', 290 apKind: '-', 291 apAbcId: '-', 292 apId: '-' 293 }; 294 root.children.push(moduleNode); 295 } 296 let funcNode = moduleNode.children.find((node) => node.apName === item.funcName); 297 if (!funcNode) { 298 id++; 299 funcNode = { 300 id: id, depth: 1, 301 children: [], 302 apName: item.funcName, 303 type: '', 304 isRoot: '-', 305 apKind: '-', 306 apAbcId: '-', 307 apId: '-' 308 }; 309 moduleNode.children.push(funcNode); 310 } 311 if (item.offset === '-') { 312 return {id: id, offsetNode: funcNode}; 313 } 314 let offsetNode = funcNode.children.find((node) => node.apName === item.offset); 315 if (!offsetNode) { 316 id++; 317 offsetNode = { 318 id: id, depth: 2, 319 children: [], 320 apName: item.offset, 321 type: '', 322 isRoot: '-', 323 apKind: '-', 324 apAbcId: '-', 325 apId: '-' 326 }; 327 funcNode.children.push(offsetNode); 328 } 329 return {id, offsetNode}; 330 } 331 332 static MakeApObj(moduleName, functionName, item) { 333 if (item === undefined) { 334 item = new TypeItem(); 335 } 336 let abcId = this.abcFilePoolMap.get(String(item.abcId)); 337 if (abcId === undefined) { 338 abcId = '-'; 339 } 340 let transformedItem = { 341 moduleName: moduleName, 342 funcName: functionName, 343 offset: (item === null || item === void 0 ? void 0 : item.typeOffset) === undefined ? '-' : item.typeOffset, 344 type: (item === null || item === void 0 ? void 0 : item.typeName) === undefined ? '-' : item.typeName, 345 apKind: (item === null || item === void 0 ? void 0 : item.kind) === undefined ? '-' : item.kind, 346 apAbcId: (item === null || item === void 0 ? void 0 : item.abcId) === undefined ? '-' : abcId, 347 apId: (item === null || item === void 0 ? void 0 : item.id) === undefined ? '-' : item.id, 348 isRoot: (item === null || item === void 0 ? void 0 : item.isRoot) === undefined ? '-' : item.isRoot 349 }; 350 return transformedItem; 351 } 352 353 static TransformJson(value) { 354 let apRes = JSON.parse(value); 355 let apData = JSON.parse(apRes.data); 356 let jsonData = apData.recordDetail; 357 let abcFilePool = apData.abcFilePool; 358 this.abcFilePoolMap = new Map(abcFilePool.map(item => { 359 let parts = item.abcFile.split(/\/|\\/); 360 let fileName = parts.length > 1 ? parts[parts.length - 1] : item.abcFile; 361 return [item.abcId, fileName]; 362 })); 363 let result = []; 364 for (let moduleItem of jsonData) { 365 for (let functionItem of moduleItem.function) { 366 if (functionItem.type.length === 0) { 367 result.push(TabPaneApSummary.MakeApObj(moduleItem.moduleName, functionItem.functionName)); 368 } 369 for (let typeItem of functionItem.type) { 370 if (Array.isArray(typeItem)) { 371 for (let typesItem of typeItem) { 372 if (Array.isArray(typesItem)) { 373 for (let item of typesItem) { 374 result.push(TabPaneApSummary.MakeApObj(moduleItem.moduleName, functionItem.functionName, item)); 375 } 376 } else { 377 result.push(TabPaneApSummary.MakeApObj(moduleItem.moduleName, functionItem.functionName, typesItem)); 378 } 379 } 380 } else { 381 result.push(TabPaneApSummary.MakeApObj(moduleItem.moduleName, functionItem.functionName, typeItem)); 382 } 383 } 384 } 385 } 386 return result; 387 } 388} 389 390TabPaneApSummary.KindMap = { 391 '0': 'ClassId', 392 '1': 'LiteralId', 393 '2': 'BuiltinsId', 394 '3': 'LegacyKind', 395 '4': 'MethodId', 396 '5': 'BuiltinFunctionId', 397 '6': 'RecordClassId', 398 '7': 'PrototypeId', 399 '8': 'ConstructorId', 400 '9': 'MegaStateKinds', 401 '10': 'TotalKinds', 402 '11': 'UnknowId', 403 '12': 'GlobalsId' 404}; 405TabPaneApSummary.abcFilePoolMap = new Map(); 406if (!customElements.get('tab-ap-summary')) { 407 customElements.define('tab-ap-summary', TabPaneApSummary); 408} 409export class TypeItem { 410 constructor() { 411 this.typeName = '-'; 412 this.typeOffset = '-'; 413 this.isRoot = '-'; 414 this.kind = '-'; 415 this.abcId = '-'; 416 this.id = '-'; 417 } 418} 419