• 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 '../BaseElement';
17import { replacePlaceholders } from '../utils/Template';
18import { SpSystemTrace } from '../../trace/component/SpSystemTrace';
19import { SpChartList } from '../../trace/component/trace/SpChartList';
20import { dpr } from '../../trace/component/trace/base/Extension';
21let css = `
22<style>
23    :host{
24        outline: none;
25        display:inline-block;
26        position: relative;
27        overflow: visible;
28    }
29
30    .title{
31        padding: 6px 15px;
32        font-weight: bold;
33        font-size: 0.9rem;
34        border-bottom: 1px solid #f0f0f0;
35    }
36    .content{
37        padding: 10px;
38    }
39   .trigger-click {
40        position: absolute;
41        visibility: hidden;
42        z-index: -100;
43        width: 100%;
44        height: 100%;
45    }
46    /*通用*/
47    .popover{
48        width: {1};
49        min-width: 160px;
50        display: flex;
51        flex-direction: column;
52        visibility: hidden;
53        opacity: 0;
54        transition: all 0.3s;
55        z-index: 1;
56        position: absolute;
57        border-radius: 2px;
58        background-color: var(--dark-background3,#fff);
59        box-shadow: 0 0 20px #00000044;
60    }
61    .popover:after{
62        content: '';
63        display: flex;
64        position: absolute;
65        width: 12px;
66        height: 12px;
67        background: linear-gradient(45deg, var(--dark-background3,#FFFFFF),
68        var(--dark-background3,#FFFFFF) 50%, transparent 50%, transparent 100%);
69    }
70    :host(:not([placement])) .popover,
71    :host([placement='top']) .popover{
72        top: 0;
73        left: 50%;
74        right: 0;
75        transform: translate(-50%,calc(-100% - 12px)) scale(0.5);
76        transform-origin: bottom;
77    }
78    :host(:not([placement])) .popover:after,
79    :host([placement='top']) .popover:after{
80        border-top: 6px solid #fff;
81        left: 0;
82        top: calc(100%);
83        transform: translate(-50%,0%);
84        left: 50%;
85    }
86    :host(:not([placement])[trigger='hover']:hover)  .popover,
87    :host(:not([placement]):not([trigger]):hover)  .popover,
88    :host([placement='top'][trigger='hover']:hover)  .popover,
89    :host([placement='top']:not([trigger]):hover)  .popover {
90        visibility: visible;
91        opacity: 1;
92        transform: translate(-50%,calc(-100% - 12px)) scale(1);
93    }
94    :host(:not([placement])[trigger='click']) input[type=checkbox]:checked ~ .popover,
95    :host([placement='top'][trigger='click']) input[type=checkbox]:checked ~ .popover {
96        visibility: visible;
97        opacity: 1;
98        transform: translate(-50%,calc(-100% - 12px)) scale(1);
99    }
100    :host([placement='topLeft']) .popover{
101        top: 0;
102        left: 50%;
103        right: 0;
104        transform: translate(0,calc(-100% - 12px)) scale(0.5);
105        transform-origin: left bottom;
106    }
107    :host([placement='topLeft']) .popover:after{
108        top: 99%;
109        transform: rotateX(180deg);
110    }
111    :host([placement='topLeft']:not([trigger]):hover)  .popover,
112    :host([placement='topLeft'][trigger='hover']:hover)  .popover {
113        visibility: visible;
114        opacity: 1;
115        transform: translate(0%,calc(-100% - 12px)) scale(1);
116    }
117    :host([placement='topLeft'][trigger='click']) input[type=checkbox]:checked ~ .popover {
118        visibility: visible;
119        opacity: 1;
120        transform: translate(0%,calc(-100% - 12px)) scale(1);
121    }
122    :host([placement='topRight']) .popover{
123        top: 0;
124        right: 0;
125        transform: translate(0,calc(-100% - 12px)) scale(0.5);
126        transform-origin: right bottom;
127    }
128    :host([placement='topRight']) .popover:after{
129        border-top: 6px solid #fff;
130        top: calc(100%);
131        transform: translate(0%,0%);
132        right: 20px;
133    }
134    :host([placement='topRight']:not([trigger]):hover)  .popover,
135    :host([placement='topRight'][trigger='hover']:hover)  .popover {
136        visibility: visible;
137        opacity: 1;
138        transform: translate(0%,calc(-100% - 12px)) scale(1);
139    }
140    :host([placement='topRight'][trigger='click']) input[type=checkbox]:checked ~ .popover {
141        visibility: visible;
142        opacity: 1;
143        transform: translate(0%,calc(-100% - 12px)) scale(1);
144    }
145    :host([placement='leftTop']) .popover{
146        top: 0;
147        right: 100%;
148        transform: translate(-12px,0) scale(0.5);
149        transform-origin: right top;
150    }
151    :host([placement='leftTop']) .popover:after{
152        border-left: 6px solid #fff;
153        top: 10px;
154        right: -12px;
155        transform: translate(0px,0%);
156    }
157    :host([placement='leftTop']:not([trigger]):hover)  .popover,
158    :host([placement='leftTop'][trigger='hover']:hover)  .popover {
159        visibility: visible;
160        opacity: 1;
161        right: 100%;
162        transform: translate(-12px,0) scale(1);
163    }
164    :host([placement='leftTop'][trigger='click']) input[type=checkbox]:checked ~ .popover {
165        visibility: visible;
166        opacity: 1;
167        transform: translate(-12px,0) scale(1);
168    }
169    :host([placement='left']) .popover{
170        right: 100%;
171        top: 50%;
172        transform: translate(-12px,-50%) scale(0.5);
173        transform-origin: right center;
174    }
175    :host([placement='left']) .popover:after{
176        border-left: 6px solid #fff;
177        top: 50%;
178        right: -12px;
179        transform: translate(0px,-50%);
180    }
181    :host([placement='left']:not([trigger]):hover)  .popover,
182    :host([placement='left'][trigger='hover']:hover)  .popover {
183        visibility: visible;
184        opacity: 1;
185        right: 100%;
186        transform: translate(-12px,-50%) scale(1);
187    }
188    :host([placement='left'][trigger='click']) input[type=checkbox]:checked ~ .popover {
189        visibility: visible;
190        opacity: 1;
191        transform: translate(-12px,-50%) scale(1);
192    }
193    :host([placement='leftBottom']) .popover{
194        right: 100%;
195        bottom: 0;
196        transform: translate(-12px,0%) scale(0.5);
197        transform-origin: right bottom;
198    }
199    :host([placement='leftBottom']) .popover:after{
200        border-left: 6px solid #fff;
201        bottom: 10px;
202        right: -12px;
203        transform: translate(0px,-50%);
204    }
205    :host([placement='leftBottom']:not([trigger]):hover)  .popover,
206    :host([placement='leftBottom'][trigger='hover']:hover)  .popover {
207        visibility: visible;
208        opacity: 1;
209        right: 100%;
210        transform: translate(-12px,0%) scale(1);
211    }
212    :host([placement='leftBottom'][trigger='click']) input[type=checkbox]:checked ~ .popover {
213        visibility: visible;
214        opacity: 1;
215        transform: translate(-12px,0%) scale(1);
216    }
217    :host([placement='rightTop']) .popover{
218        top: 0;
219        left: 100%;
220        transform: translate(12px,0) scale(0.5);
221        transform-origin: left top;
222    }
223    :host([placement='rightTop']) .popover:after{
224        border-right: 6px solid #fff;
225        top: 10px;
226        left: -12px;
227        transform: translate(0px,0%);
228    }
229    :host([placement='rightTop']:not([trigger]):hover)  .popover,
230    :host([placement='rightTop'][trigger='hover']:hover)  .popover {
231        visibility: visible;
232        opacity: 1;
233        left: 100%;
234        transform: translate(12px,0) scale(1);
235    }
236    :host([placement='rightTop'][trigger='click']) input[type=checkbox]:checked ~ .popover {
237        visibility: visible;
238        opacity: 1;
239        transform: translate(12px,0) scale(1);
240    }
241    :host([placement='right']) .popover{
242        top: 50%;
243        left: 100%;
244        transform: translate(12px,-50%) scale(0.5);
245        transform-origin: left center;
246    }
247    :host([placement='right']) .popover:after{
248        border-right: 6px solid #fff;
249        top: 50%;
250        left: -12px;
251        transform: translate(0px,-50%);
252    }
253    :host([placement='right']:not([trigger]):hover)  .popover,
254    :host([placement='right'][trigger='hover']:hover)  .popover {
255        visibility: visible;
256        opacity: 1;
257        left: 100%;
258        transform: translate(12px,-50%) scale(1);
259    }
260    :host([placement='right'][trigger='click']) input[type=checkbox]:checked ~ .popover {
261        visibility: visible;
262        opacity: 1;
263        transform: translate(12px,-50%) scale(1);
264    }
265    :host([placement='rightBottom']) .popover{
266        bottom: 0;
267        left: 100%;
268        transform: translate(12px,0%) scale(0.5);
269        transform-origin: left bottom;
270    }
271    :host([placement='rightBottom']) .popover:after{
272        border-right: 6px solid #fff;
273        left: -12px;
274        bottom: 10px;
275        transform: translate(0px,0);
276    }
277    :host([placement='rightBottom']:not([trigger]):hover)  .popover,
278    :host([placement='rightBottom'][trigger='hover']:hover)  .popover {
279        visibility: visible;
280        opacity: 1;
281        bottom: 0;
282        transform: translate(12px,0%) scale(1);
283    }
284    :host([placement='rightBottom'][trigger='click']) input[type=checkbox]:checked ~ .popover {
285        visibility: visible;
286        opacity: 1;
287        transform: translate(12px,0%) scale(1);
288    }
289
290    :host([placement='bottomLeft']) .popover{
291        bottom: 0;
292        /*left: 0;*/
293        left: 8px;
294        right: 0;
295        transform: translate(0,calc(100% + 12px)) scale(0.5);
296        transform-origin: top left;
297    }
298    :host([placement='bottomLeft']) .popover:after{
299        bottom: calc(100%);
300        transform: translate(0%,0%);
301        left: 0;
302    }
303    :host([placement='bottomLeft']:not([trigger]):hover)  .popover,
304    :host([placement='bottomLeft'][trigger='hover']:hover)  .popover {
305        visibility: visible;
306        opacity: 1;
307        transform: translate(0%,calc(100% + 12px)) scale(1);
308    }
309    :host([placement='bottomLeft'][trigger='click']) input[type=checkbox]:checked ~ .popover {
310        visibility: visible;
311        opacity: 1;
312        transform: translate(0%,calc(100% + 12px)) scale(1);
313    }
314    :host([placement='bottom']) .popover{
315        bottom: 0;
316        left: 50%;
317        right: 0;
318        transform: translate(-50%,calc(100% + 12px)) scale(0.5);
319        transform-origin: top center;
320    }
321    :host([placement='bottom']) .popover:after{
322        border-bottom: 6px solid #fff;
323        bottom: calc(100%);
324        transform: translate(-50%,0%);
325        left: 50%;
326    }
327    :host([placement='bottom']:not([trigger]):hover)  .popover,
328    :host([placement='bottom'][trigger='hover']:hover)  .popover {
329        visibility: visible;
330        opacity: 1;
331        transform: translate(-50%,calc(100% + 12px)) scale(1);
332    }
333    :host([placement='bottom'][trigger='click']) input[type=checkbox]:checked ~ .popover {
334        visibility: visible;
335        opacity: 1;
336        transform: translate(-50%,calc(100% + 12px)) scale(1);
337    }
338    /*bottomRight*/
339    :host([placement='bottomRight']) .popover{
340        bottom: 0;
341        right: 0;
342        transform: translate(0%,calc(100% + 12px)) scale(0.5);
343        transform-origin: top right;
344    }
345    :host([placement='bottomRight']) .popover:after{
346        border-bottom: 6px solid #fff;
347        bottom: calc(100%);
348        transform: translate(-50%,0%);
349        right: 10px;
350    }
351    :host([placement='bottomRight']:not([trigger]):hover)  .popover,
352    :host([placement='bottomRight'][trigger='hover']:hover)  .popover {
353        visibility: visible;
354        opacity: 1;
355        transform: translate(0,calc(100% + 12px)) scale(1);
356    }
357    :host([placement='bottomRight'][trigger='click']) input[type=checkbox]:checked ~ .popover {
358        visibility: visible;
359        opacity: 1;
360        transform: translate(0%,calc(100% + 12px)) scale(1);
361    }
362    :host(:not([title])) .title{
363        display: none;
364    }
365    </style>
366`;
367const initHtmlStyle = (wid: string): string => {
368  return replacePlaceholders(css, wid);
369};
370
371@element('lit-popover')
372export class LitPopover extends BaseElement {
373  static isChangeHeight: boolean = false;
374  static finalHeight: number = 0;
375  static get observedAttributes(): string[] {
376    return ['title', 'trigger', 'width', 'placement', 'visible'];
377  }
378
379  get visible(): string {
380    return this.getAttribute('visible') || 'false';
381  }
382
383  set visible(value) {
384    if (value) {
385      this.setAttribute('visible', 'true');
386    } else {
387      this.setAttribute('visible', 'false');
388    }
389  }
390
391  set placement(value) {
392    this.setAttribute('placement', value || 'bottomLeft');
393  }
394
395  get placement(): string | null {
396    return this.getAttribute('placement');
397  }
398
399  get trigger(): string {
400    return this.getAttribute('trigger') || 'hover';
401  }
402
403  set trigger(value) {
404    this.setAttribute('trigger', value);
405  }
406
407  get title(): string {
408    return this.getAttribute('title') || '';
409  }
410
411  set title(value: string) {
412    this.setAttribute('title', value);
413  }
414
415  get width(): string {
416    return this.getAttribute('width') || 'max-content';
417  }
418
419  set width(value) {
420    this.setAttribute('width', value);
421  }
422
423  get haveRadio(): string | null {
424    return this.getAttribute('haveRadio');
425  }
426
427  get haveCheckbox(): string | null {
428    return this.getAttribute('haveCheckbox');
429  }
430
431  initElements(): void {}
432
433  initHtml(): string {
434    return `
435        ${initHtmlStyle(this.width)}
436        <input class="trigger-click" type="checkbox">
437        <div class="popover" title="">
438            <div class="title">${this.title}</div>
439            <div class="content"><slot name="content" ></slot></div>
440        </div>
441        <slot></slot>
442        `;
443  }
444
445  connectedCallback(): void {
446    let popover: unknown = this.shadowRoot!.querySelector('.popover');
447    let checkbox: unknown = this.shadowRoot!.querySelector('.trigger-click');
448    let sp = document.querySelector("body > sp-application")?.shadowRoot?.querySelector("#sp-system-trace") as SpSystemTrace;
449    let favoriteList = sp.shadowRoot?.querySelector("#favorite-chart-list") as SpChartList;
450    this.setAttribute('tabindex', '1'); // @ts-ignore
451    popover.onclick = (e: unknown): void => {
452      // @ts-ignore
453      e.stopPropagation();
454    }; // @ts-ignore
455    popover.addEventListener('mousemove', (e: unknown) => {
456      // @ts-ignore
457      e.stopPropagation();
458    });
459    this.onclick = (e: unknown): void => {
460      // @ts-ignore
461      e.stopPropagation(); // @ts-ignore
462      if (e.relatedTarget?.hasAttribute('not-close')) {
463        this.focus();
464      } // @ts-ignore
465      checkbox.checked = !checkbox.checked; // @ts-ignore
466      if (!this.haveCheckbox) {
467        // @ts-ignore
468        this.visible = checkbox.checked;
469      }
470      if (sp.collectRows && sp.collectRows.length) {
471        let isHiperf = sp.collectRows.some((row) => {
472          return row.rowId === 'HiPerf-callchart' && row.rowParentId === 'HiPerf';
473        });
474        let rowHeight = sp.collectRows.reduce((pre, row) => {
475          let height = row._frame?.height;
476          return pre + height!;
477        }, 0);
478        let titleHeight = sp.groupTitle1!.clientHeight || sp.groupTitle2!.clientHeight;
479        if (sp.collectEl1!.innerHTML.trim() !== '' && sp.collectEl2!.innerHTML.trim() !== '') {
480          titleHeight = titleHeight * 2;
481        }
482        let favoriteListHeight = favoriteList!.clientHeight * dpr();
483        let finalHeight = rowHeight + titleHeight > favoriteListHeight ? favoriteListHeight : rowHeight + titleHeight;
484        let isResetHeight = parseFloat(favoriteList.style.height.replace('px', '')) >= 300 && finalHeight >= 300;
485        favoriteList.style.height = this.visible === 'true' && isHiperf && !isResetHeight ? '300px' : `${finalHeight}px`;
486        LitPopover.isChangeHeight = this.visible === 'true' && isHiperf && !isResetHeight ? true : false;
487        LitPopover.finalHeight = finalHeight;
488      }
489    }; // @ts-ignore
490    popover.onmouseleave = (): void => {
491      this.focus();
492      if (this.haveCheckbox) {
493        // @ts-ignore
494        this.visible = false;
495      }
496    };
497    this.onblur = (ev: unknown): void => {
498      // @ts-ignore
499      if (ev.relatedTarget && this.haveRadio) {
500        // @ts-ignore
501        if (ev.relatedTarget.hasAttribute('not-close')) {
502          // @ts-ignore
503        } else if (ev.relatedTarget.type === 'radio') {
504          this.focus();
505        } else {
506          // @ts-ignore
507          this.visible = false;
508        }
509      // @ts-ignore
510      } else if (this.haveCheckbox) {
511      } else {
512        // @ts-ignore
513        this.visible = false;
514      }
515    };
516  }
517
518  disconnectedCallback(): void {}
519
520  adoptedCallback(): void {}
521
522  attributeChangedCallback(name: unknown, oldValue: unknown, newValue: unknown): void {
523    if (name === 'visible') {
524      if (newValue === 'false') {
525        // @ts-ignore
526        this.shadowRoot!.querySelector('.trigger-click')!.checked = false;
527      } else {
528        // @ts-ignore
529        this.shadowRoot!.querySelector('.trigger-click')!.checked = true;
530      }
531    }
532  }
533}
534