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