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