• 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 { BaseElement, element } from '../../base-ui/BaseElement';
17import { LitMainMenuGroup } from '../../base-ui/menu/LitMainMenuGroup';
18import { LitMainMenu, MenuGroup, MenuItem } from '../../base-ui/menu/LitMainMenu';
19import { LitMainMenuItem } from '../../base-ui/menu/LitMainMenuItem';
20import { SpStatisticsHttpUtil } from '../../statistics/util/SpStatisticsHttpUtil';
21import { EventDefinition, eventDefinitions } from '../enums/helpDocEnums';
22
23@element('sp-help')
24export class SpHelp extends BaseElement {
25  private appContent: HTMLElement | undefined | null;
26  private helpFile: HTMLElement | undefined | null;
27  private navbarContainer: HTMLElement | undefined | null;
28  private backToTop: HTMLElement | undefined | null;
29
30  get dark(): boolean {
31    return this.hasAttribute('dark');
32  }
33
34  set dark(dark: boolean) {
35    if (dark) {
36      this.setAttribute('dark', `${dark}`);
37    } else {
38      this.removeAttribute('dark');
39    }
40    this.helpFile!.innerHTML =
41      '<iframe id="myIframe" type="text/html" src=' +
42      `doc/quickstart_device_record.html?${dark} width="100%" height="100%"></iframe>`;
43    this.navbarInit('quickstart_device_record');
44  }
45
46  initElements(): void {
47    let parentElement = this.parentNode as HTMLElement;
48    parentElement.style.overflow = 'hidden';
49    this.appContent = this.shadowRoot?.querySelector('#app-content') as HTMLElement;
50    this.helpFile = this.shadowRoot?.querySelector('#help-file') as HTMLElement;
51    this.navbarContainer = this.shadowRoot?.querySelector('#navbar-container') as HTMLElement;
52    this.backToTop = this.shadowRoot?.querySelector('.back') as HTMLElement;
53    let mainMenu = this.shadowRoot?.querySelector('#main-menu') as LitMainMenu;
54    let header = mainMenu.shadowRoot?.querySelector('.header') as HTMLDivElement;
55    let color = mainMenu.shadowRoot?.querySelector('.customColor') as HTMLDivElement;
56    let analysis = mainMenu.shadowRoot?.querySelector('.ai_analysis') as HTMLDivElement;
57    let version = mainMenu.shadowRoot?.querySelector('.version') as HTMLDivElement;
58    let extend_connect = mainMenu.shadowRoot?.querySelector('.extend_connect') as HTMLDivElement;
59    color.style.display = 'none';
60    analysis.style.display = 'none';
61    extend_connect.style.display = 'none';
62    header.style.display = 'none';
63    version.style.display = 'none';
64    this.setupMainMenu(mainMenu, this);
65    mainMenu.style.width = '330px';
66    let body = mainMenu.shadowRoot?.querySelector('.menu-body') as HTMLDivElement;
67    let groups = body.querySelectorAll<LitMainMenuGroup>('lit-main-menu-group');
68    groups.forEach((value) => {
69      let items = value.querySelectorAll<LitMainMenuItem>('lit-main-menu-item');
70      items.forEach((item) => {
71        item.style.width = '330px';
72      });
73      if (value.title === 'TraceStreamer') {
74        let items = value.querySelectorAll<LitMainMenuItem>('lit-main-menu-item');
75        items.forEach((i) => {
76          if (i.title !== 'TraceStreamer数据库说明') {
77            i.style.display = 'none';
78          }
79        });
80      }
81      if (value.title === 'SmartPerf') {
82        value.style.display = 'none';
83      }
84    });
85    let urlParams = new URL(window.location.href).searchParams;
86    if (urlParams && urlParams.get('action') && urlParams.get('action')!.length > 4) {
87      this.itemHelpClick(urlParams, this);
88    }
89  }
90
91  private itemHelpClick(urlParams: URLSearchParams, that: this): void {
92    if (urlParams.get('action')!.length > 4) {
93      let helpDocIndex = urlParams.get('action')!.substring(5);
94      let helpDocDetail = this.getEventDefinitionByIndex(Number(helpDocIndex));
95      that.helpFile!.innerHTML = `<iframe id="myIframe" type="text/html" src='doc/${helpDocDetail!.name}.html?${that.dark
96        }' width="100%" height="100%"></iframe>`;
97
98      this.navbarInit(helpDocDetail!.name);
99    }
100  }
101
102  private getEventDefinitionByIndex(index: number): EventDefinition | null {
103    for (let key in eventDefinitions) {
104      if (eventDefinitions[key].index === index) {
105        return eventDefinitions[key];
106      }
107    }
108    return null;
109  }
110
111  private setupMainMenu(mainMenu: LitMainMenu, that: this): void {
112    mainMenu.menus = [
113      {
114        collapsed: false,
115        title: 'QuickStart',
116        second: false,
117        icon: 'caret-down',
118        describe: '',
119        children: [
120          this.setupCaptureAndImportMenu(that),
121          this.setupMemoryMenu(that),
122          this.setupNativeMenu(that),
123          this.setupTsMenu(that),
124          this.setupAnalysisTemplateMenu(that),
125          this.setupFileMenu(that),
126          this.setupOtherMenu(that),
127        ],
128      },
129      {
130        collapsed: false,
131        title: 'TraceStreamer',
132        second: false,
133        icon: 'caret-down',
134        describe: '',
135        children: [
136          this.setupDatabaseMenu(that),
137          this.setupCompileMenu(that),
138          this.setupAnalysisMenu(that),
139          this.setupEventListMenu(that),
140          this.setupToolDescriptionMenu(that),
141          this.setupBinderMenu(that),
142          this.setupWakeUpMenu(that),
143        ],
144      },
145      {
146        collapsed: false,
147        title: 'SmartPerf',
148        second: false,
149        icon: 'caret-down',
150        describe: '',
151        children: [this.setupSmartPerfMenu(that)],
152      },
153    ];
154  }
155
156  private setupCaptureAndImportMenu(that: this): MenuGroup {
157    return {
158      collapsed: false,
159      title: '抓取和导入',
160      describe: '',
161      second: true,
162      icon: 'caret-down',
163      children: [
164        {
165          title: '设备端抓取trace说明',
166          icon: '',
167          clickHandler: function (item: MenuItem): void {
168            that.handleMemoryMenuItemClick(that, 'record', 'quickstart_device_record', '1');
169          },
170        },
171        {
172          title: 'web端抓取trace说明',
173          icon: '',
174          clickHandler: function (item: MenuItem): void {
175            that.handleMemoryMenuItemClick(that, 'online_record', 'quickstart_web_record', '2');
176          },
177        },
178        {
179          title: 'web端加载trace说明',
180          icon: '',
181          clickHandler: function (item: MenuItem): void {
182            that.handleMemoryMenuItemClick(that, 'load', 'quickstart_systemtrace', '3');
183          },
184        },
185      ],
186    };
187  }
188
189  private setupOtherMenu(that: this): MenuGroup {
190    return {
191      collapsed: false,
192      title: '其他',
193      describe: '',
194      icon: 'caret-down',
195      second: true,
196      children: this.setupOtherMenuItems(that),
197    };
198  }
199  private setupOtherMenuItems(that: this): MenuItem[] {
200    return [
201      this.createSubMenuItem('Sql分析和Metrics说明', 'sql', 'quickstart_sql_metrics', that, '17'),
202      this.createSubMenuItem('HiSystemEvent抓取和展示说明', 'hisys', 'quickstart_hisystemevent', that, '18'),
203      this.createSubMenuItem('sdk抓取和展示说明', 'sdk_record', 'quickstart_sdk', that, '19'),
204      this.createSubMenuItem('调用栈可视化和不同库函数调用占比说明', 'import_so', 'quickstart_Import_so', that, '20'),
205      this.createSubMenuItem('Hilog抓取和展示说明', 'hilog', 'quickstart_hilog', that, '21'),
206      this.createSubMenuItem('Ability Monitor抓取和展示说明', 'ability', 'quickstart_ability_monitor', that, '22'),
207      this.createSubMenuItem('Trace解析能力增强', 'trace_parsing', 'quickstart_parsing_ability', that, '23'),
208      this.createSubMenuItem('应用操作技巧', 'operation_skills', 'quickstart_Application_operation_skills', that, '24'),
209      this.createSubMenuItem('快捷键说明', 'keywords_shortcuts', 'quickstart_keywords_shortcuts', that, '25'),
210      this.createSubMenuItem('Xpower抓取和展示说明', 'xpower', 'quickstart_xpower', that, '26'),
211      this.createSubMenuItem('扩展程序安装指导', 'extensions', 'quickstart_extensions', that, '27'),
212      this.createSubMenuItem('FFRT抓取和展示说明', 'ffrt', 'quickstart_ffrt', that, '28'),
213      this.createSubMenuItem('约束与限制', 'limit', 'quickstart_limit', that, '29'),
214    ];
215  }
216
217  private createSubMenuItem(title: string, event: string, docName: string, that: this, index: string): MenuItem {
218    return {
219      title: title,
220      icon: '',
221      clickHandler: (item: MenuItem): void => {
222        that.handleMemoryMenuItemClick(that, event, docName, index);
223      },
224    };
225  }
226
227  private setupMemoryMenu(that: this): MenuGroup {
228    return {
229      collapsed: false,
230      title: '内存',
231      describe: '',
232      icon: 'caret-down',
233      second: true,
234      children: [
235        {
236          title: 'Js Memory抓取和展示说明',
237          icon: '',
238          clickHandler: function (item: MenuItem): void {
239            that.handleMemoryMenuItemClick(that, 'js_memory', 'quickstart_Js_memory', '4');
240          },
241        },
242        {
243          title: 'Native Memory抓取和展示说明',
244          icon: '',
245          clickHandler: function (item: MenuItem): void {
246            that.handleMemoryMenuItemClick(that, 'native', 'quickstart_native_memory', '5');
247          },
248        },
249        {
250          title: '页内存抓取和展示说明',
251          icon: '',
252          clickHandler: function (item: MenuItem): void {
253            that.handleMemoryMenuItemClick(that, 'virtual_memory', 'quickstart_page_fault', '6');
254          },
255        },
256        {
257          title: '系统内存抓取和展示说明',
258          icon: '',
259          clickHandler: function (item: MenuItem): void {
260            that.handleMemoryMenuItemClick(that, 'memory_template', 'quickstart_memory_template', '7');
261          },
262        },
263      ],
264    };
265  }
266
267  private handleMemoryMenuItemClick(that: this, event: string, docName: string, index?: string): void {
268    SpStatisticsHttpUtil.addOrdinaryVisitAction({
269      event: event,
270      action: 'help_doc',
271    });
272    that.helpFile!.innerHTML = `<iframe id="myIframe" type="text/html" src='doc/${docName}.html?${that.dark}' width="100%" height="100%"></iframe>`;
273    this.navbarInit(docName);
274    this.changeItemURL(index!);
275  }
276
277  private navbarInit(docName: string): void {
278    fetch(`doc/${docName}.html`)
279      .then(response => response.text())
280      .then(htmlString => {
281        const parser = new DOMParser();
282        const doc = parser.parseFromString(htmlString, 'text/html');
283
284        const hTags = Array.from(doc.body.querySelectorAll('h1, h2, h3, h4, h5, h6')).map((header) => ({
285          id: header.id,
286          text: header.textContent!.trim()
287        }));
288        this.navbarContainer!.innerHTML = `<ul id="nav-links">${hTags.map(hTag => {
289          let backData: string = '';
290          if (hTag.id) {
291            backData = `<li class="tooltip"><a id="${hTag.id}" data-full-text="${hTag.text}">${hTag.text}</a><span class="tooltiptext" id="tooltip-${hTag.id}">${hTag.text}</span>
292          </li>`;
293          }
294          return backData;
295        }).join('')
296          }</ul>`;
297
298        let navLinks = this.navbarContainer!.querySelectorAll('#nav-links a');
299        navLinks.forEach((navLink) => {
300          navLink.addEventListener('click', (e) => {
301            let lis = this.navbarContainer!.querySelectorAll('#nav-links li');
302            lis.forEach(li => li.classList.remove('active'));
303            navLink.closest('li')!.classList.add('active');
304            let targetId = navLink.id;
305            e.preventDefault();
306            this.helpFile!.innerHTML = `<iframe id="myIframe" type="text/html" src='doc/${docName}.html?dark=${this.dark}&targetId=${targetId}' width="100%" height="100%"></iframe>`;
307          });
308        });
309
310        this.backToTop!.querySelector('#back-to-top')!.addEventListener('click', (e) => {
311          e.preventDefault();
312          navLinks.forEach((navLink) => {
313            navLink.closest('li')?.classList.remove('active');
314          });
315          this.helpFile!.innerHTML = `<iframe id="myIframe" type="text/html" src='doc/${docName}.html?dark=${this.dark}' width="100%" height="100%"></iframe>`;
316        });
317
318      })
319      .catch(error => {
320        console.error('Error fetching and modifying HTML:', error);
321      });
322  }
323
324  private changeItemURL(index: string): void {
325    let url = new URL(window.location.href);
326    let actionParam = url.searchParams.get('action');
327    let newActionValue = `help_${index}`;
328    if (actionParam) {
329      url.searchParams.set('action', newActionValue);
330      let newURL = url.href;
331      history.pushState({}, '', newURL);
332    } else {
333      history.pushState({}, '', window.location.origin + window.location.pathname);
334    }
335  }
336
337  private setupNativeMenu(that: this): MenuGroup {
338    return {
339      collapsed: false,
340      title: 'Native栈',
341      describe: '',
342      second: true,
343      icon: 'caret-down',
344      children: [
345        {
346          title: 'HiPerf的抓取和展示说明',
347          icon: '',
348          clickHandler: function (item: MenuItem): void {
349            that.handleMemoryMenuItemClick(that, 'perf', 'quickstart_hiperf', '8');
350          },
351        },
352      ],
353    };
354  }
355
356  private setupTsMenu(that: this): MenuGroup {
357    return {
358      collapsed: false,
359      title: 'TS栈',
360      describe: '',
361      second: true,
362      icon: 'caret-down',
363      children: [
364        {
365          title: 'Cpuprofiler抓取和展示说明',
366          icon: '',
367          clickHandler: function (item: MenuItem): void {
368            that.handleMemoryMenuItemClick(that, 'arkts', 'quickstart_arkts', '9');
369          },
370        },
371      ],
372    };
373  }
374
375  private setupAnalysisTemplateMenu(that: this): MenuGroup {
376    return {
377      collapsed: false,
378      title: '分析模板',
379      describe: '',
380      second: true,
381      icon: 'caret-down',
382      children: [
383        {
384          title: 'Frame timeline抓取和展示说明',
385          icon: '',
386          clickHandler: function (item: MenuItem): void {
387            that.handleMemoryMenuItemClick(that, 'frame_record', 'quickstart_Frametimeline', '10');
388          },
389        },
390        {
391          title: 'Animation的抓取和展示说明',
392          icon: '',
393          clickHandler: function (item: MenuItem): void {
394            that.handleMemoryMenuItemClick(that, 'animation', 'quickstart_animation', '11');
395          },
396        },
397        {
398          title: 'TaskPool抓取和展示说明',
399          icon: '',
400          clickHandler: function (item: MenuItem): void {
401            that.handleMemoryMenuItemClick(that, 'taskpool', 'quickstart_taskpool', '12');
402          },
403        },
404        {
405          title: 'App startup的抓取和展示说明',
406          icon: '',
407          clickHandler: function (item: MenuItem): void {
408            that.handleMemoryMenuItemClick(that, 'app_startup', 'quickstart_app_startup', '13');
409          },
410        },
411        {
412          title: 'Scheduling analysis抓取和展示说明',
413          icon: '',
414          clickHandler: function (item: MenuItem): void {
415            that.handleMemoryMenuItemClick(that, 'scheduling_record', 'quickstart_schedulinganalysis', '14');
416          },
417        },
418      ],
419    };
420  }
421
422  private setupFileMenu(that: this): MenuGroup {
423    return {
424      collapsed: false,
425      title: '文件',
426      describe: '',
427      second: true,
428      icon: 'caret-down',
429      children: [
430        {
431          title: 'FileSystem抓取和展示说明',
432          icon: '',
433          clickHandler: function (item: MenuItem): void {
434            that.handleMemoryMenuItemClick(that, 'file_system', 'quickstart_filesystem', '15');
435          },
436        },
437        {
438          title: 'Bio抓取和展示说明',
439          icon: '',
440          clickHandler: function (item: MenuItem): void {
441            that.handleMemoryMenuItemClick(that, 'bio', 'quickstart_bio', '16');
442          },
443        },
444      ],
445    };
446  }
447
448  private setupDatabaseMenu(that: this): MenuItem {
449    return {
450      title: 'TraceStreamer数据库说明',
451      icon: '',
452      clickHandler: function (item: MenuItem): void {
453        that.handleMemoryMenuItemClick(that, 'trace_streamer_explain', 'des_tables', '30');
454      },
455    };
456  }
457
458  private setupCompileMenu(that: this): MenuItem {
459    return {
460      title: '编译Trace_streamer',
461      icon: '',
462      clickHandler: function (item: MenuItem): void {
463        that.handleMemoryMenuItemClick(that, 'trace_streamer_compile', 'compile_trace_streamer');
464      },
465    };
466  }
467
468  private setupAnalysisMenu(that: this): MenuItem {
469    return {
470      title: 'TraceStreamer 解析数据状态表',
471      icon: '',
472      clickHandler: function (item: MenuItem): void {
473        that.handleMemoryMenuItemClick(that, 'trace_streamer_des', 'des_stat');
474      },
475    };
476  }
477
478  private setupSmartPerfMenu(that: this): MenuItem {
479    return {
480      title: 'SmartPerf 编译指导',
481      icon: '',
482      clickHandler: function (item: MenuItem): void {
483        that.handleMemoryMenuItemClick(that, 'smartperf_guide', 'quickstart_smartperflinux_compile_guide');
484      },
485    };
486  }
487
488  private setupEventListMenu(that: this): MenuItem {
489    return {
490      title: 'TraceStreamer支持解析事件列表',
491      icon: '',
492      clickHandler: function (item: MenuItem): void {
493        that.handleMemoryMenuItemClick(that, 'support_event', 'des_support_event');
494      },
495    };
496  }
497
498  private setupToolDescriptionMenu(that: this): MenuItem {
499    return {
500      title: 'trace_streamer工具说明',
501      icon: '',
502      clickHandler: function (item: MenuItem): void {
503        that.handleMemoryMenuItemClick(that, 'quickstart_trace_streamer', 'quickstart_trace_streamer');
504      },
505    };
506  }
507
508  private setupBinderMenu(that: this): MenuItem {
509    return {
510      title: 'binder事件上下文如何关联',
511      icon: '',
512      clickHandler: function (item: MenuItem): void {
513        that.handleMemoryMenuItemClick(that, 'binder', 'des_binder');
514      },
515    };
516  }
517
518  private setupWakeUpMenu(that: this): MenuItem {
519    return {
520      title: 'wakeup唤醒说明',
521      icon: '',
522      clickHandler: function (item: MenuItem): void {
523        that.handleMemoryMenuItemClick(that, 'wakeup', 'des_wakup');
524      },
525    };
526  }
527
528  initHtml(): string {
529    return `
530        <style>
531        .sp-help-vessel {
532            min-height: 100%;
533            display: grid;
534            grid-template-columns: 1fr;
535            grid-template-rows:1fr;
536            background-color: var(--dark-background5,#F6F6F6);
537        }
538        :host{
539            width: 100%;
540            display: block;
541            height: 100%;
542            background-color: var(--dark-background5,#F6F6F6);
543        }
544        .body{
545            width: 99%;
546            margin-left: 15px;
547            display: grid;
548            grid-template-columns: min-content  1fr;
549            border-radius: 16px 16px 16px 16px;
550        }
551
552        .content{
553          border-style: none none none solid;
554          border-width: 1px;
555          border-color: rgba(166,164,164,0.2);
556          border-radius: 0px 16px 16px 0px;
557          padding-left:15px;
558          display: flex;
559          overflow-y: hidden;
560          box-sizing: border-box;
561        }
562        #navbar-container {
563          padding: 85px 10px 10px 10px;
564        }
565        #navbar-container ul {
566          list-style-type: none;
567          width:100%;
568          margin: 0;
569          padding: 0;
570          border-left: 5px solid #ecb829;
571        }
572        #navbar-container ul li {
573          position: relative;
574          width:100%;
575          height:30px;
576          line-height:30px;
577          text-align: left;
578          padding: 0 10px;
579          box-sizing: border-box;
580          border: none;
581          margin: 0;
582        }
583        #navbar-container ul li a {
584          width:100%;
585          height:100%;
586          color: black;
587          font-family: Helvetica;
588          font-size: 14px;
589          text-decoration: none;
590          display: block;
591          padding: 0;
592          border: none;
593          white-space: nowrap;
594          overflow: hidden;
595          text-overflow: ellipsis;
596        }
597        #navbar-container ul li:hover,
598        #navbar-container ul li:focus {
599          color: #ecb829;
600          cursor: pointer;
601        }
602        #navbar-container ul li:hover a,
603        #navbar-container ul li:focus a {
604          color: #ecb829;
605        }
606        #navbar-container ul li .tooltiptext {
607          position: absolute;
608          bottom: 0;
609          left: 50%;
610          transform: translateX(-50%);
611          visibility: hidden;
612          width: 100%;
613          background-color: #ecb829;
614          color: #fff;
615          font-family: Helvetica;
616          font-size: 14px;
617          text-align: center;
618          border-radius: 6px;
619          padding: 5px 5px;
620          margin-left:5px;
621          position: absolute;
622          z-index: 1;
623          opacity: 0;
624          transition: opacity 0.3s;
625          margin-bottom: 40px;
626          &::after {
627              content: '';
628              position: absolute;
629              bottom: -10px;
630              left: 50%;
631              margin-left: -10px;
632              width: 0;
633              height: 0;
634              border-style: solid;
635              border-width: 10px 10px 0 10px;
636              border-color: #ecb829 transparent transparent transparent;
637            }
638         }
639         #navbar-container ul li.tooltip:hover .tooltiptext {
640          visibility: visible;
641          opacity: 1;
642         }
643         #navbar-container ul li.active, #navbar-container ul li.active a {
644          color: #ecb829;
645         }
646        iframe {
647          border-width: 0px;
648        }
649        </style>
650        <div class="sp-help-vessel">
651         <div class="body">
652            <lit-main-menu id="main-menu" class="menugroup" data=''></lit-main-menu>
653            <div id="app-content" class="content">
654               <div id="help-file" style="width:80%;overflow-y: hidden;"></div>
655                      <nav id="navbar-container" style="width:19%;"></nav>
656                      <div class="back" style="flex:1;padding:70px 10px;">
657                          <lit-icon id="back-to-top" name="vertical-align-top" style="font-weight: bold;cursor: pointer;" size="20">
658                          </lit-icon>
659                      </div>
660               </div>
661            </div>
662         </div>
663        </div>
664        `;
665  }
666}
667