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