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 { element } from '../BaseElement.js'; 17import { LitTabpane } from './lit-tabpane.js'; 18import { SpStatisticsHttpUtil } from '../../statistics/util/SpStatisticsHttpUtil.js'; 19 20@element('lit-tabs') 21export class LitTabs extends HTMLElement { 22 private tabPos: any; 23 private nav: HTMLDivElement | undefined | null; 24 private line: HTMLDivElement | undefined | null; 25 private slots: HTMLSlotElement | undefined | null; 26 27 constructor() { 28 super(); 29 const shadowRoot = this.attachShadow({ mode: 'open' }); 30 shadowRoot.innerHTML = ` 31 <style> 32 :host{ 33 display: block; 34 text-align: unset; 35 color: var(--dark-color1,#252525); 36 background-color: var(--dark-background,#FFFFFF); 37 box-shadow: #00000033 0 0 10px ; 38 } 39 ::slotted(lit-tabpane){ 40 box-sizing:border-box; 41 width:100%; 42 height:100%; 43 flex-shrink:0; 44 overflow: auto; 45 } 46 .nav-item{ 47 display: inline-flex; 48 justify-content: center; 49 align-items: center; 50 /*padding: 6px 0px 6px 12px;*/ 51 padding-left: 12px; 52 font-size: .9rem; 53 font-weight: normal; 54 cursor: pointer; 55 transition: all 0.3s; 56 flex-shrink: 0; 57 } 58 .nav-item lit-icon{ 59 margin-right: 2px; 60 font-size: inherit; 61 } 62 63 .nav-item[data-disabled]{ 64 pointer-events: all; 65 cursor: not-allowed; 66 color: #bfbfbf; 67 } 68 .nav-item[data-hidden]{ 69 pointer-events: all; 70 cursor: not-allowed; 71 color: #bfbfbf; 72 display: none; 73 } 74 75 .tab-content{ 76 display: block; 77 background-color: #fff; 78 flex:1; 79 } 80 81 /* 82 * top top-left top-center top-right 83 */ 84 :host(:not([position])) .nav-root, 85 :host([position^='top']) .nav-root{ 86 display: flex; 87 position: relative; 88 height: 38px; 89 z-index: auto; 90 /*justify-content: center;*/ 91 /*align-items: center;*/ 92 } 93 :host(:not([mode]):not([position])) .tab-line,/*移动的线条*/ 94 :host([mode='flat'][position^='top']) .tab-line{ 95 position:absolute; 96 } 97 98 :host(:not([position])) .tab-nav-container, 99 :host([position^='top']) .tab-nav-container{ 100 display: flex; 101 /*position: relative;*/ 102 /*flex-direction: column;*/ 103 /*overflow-y: hidden;*/ 104 /*overflow-x: auto;*/ 105 /*overflow: -moz-scrollbars-none; */ 106 /*-ms-overflow-style: none;*/ 107 /*transition: all 0.3s;*/ 108 109 position: absolute; 110 overflow: auto; 111 height: 850px; 112 transform: rotateZ(-90deg) rotateY(180deg); 113 transform-origin: left top; 114 overflow-x: hidden; 115 width: 38px; 116 117 cursor: row-resize; 118 user-select: none; 119 } 120 :host([position='top']) .tab-nav, 121 :host([position='top-left']) .tab-nav{ 122 display: flex; 123 position: relative; 124 justify-content: flex-start; 125 cursor: row-resize; 126 user-select: none; 127 margin-top: 6px; 128 margin-left: 5px; 129 130 transform: translateY(-38px) rotateZ(90deg) rotateX(180deg) translateY(38px); 131 transform-origin: left bottom; 132 flex-wrap: nowrap; 133 height: 38px; 134 } 135 :host([position='top-center']) .tab-nav{ 136 display: flex; 137 justify-content: center; 138 } 139 :host([position='top-right']) .tab-nav{ 140 display: flex; 141 justify-content: flex-end; 142 } 143 144 :host([position^='top'][mode='card']) .nav-item{ 145 border-top: 1px solid var(--dark-border1,#f0f0f0); 146 border-left: 1px solid var(--dark-border1,#f0f0f0); 147 border-right: 1px solid var(--dark-border1,#f0f0f0); 148 bottom: 0px; 149 margin-right: 2px; 150 position: relative; 151 height: 100%; 152 } 153 :host([position^='top']) .tab-nav-bg-line{ 154 position: absolute;bottom: 0;height: 1px; 155 width: 100% 156 } 157 :host([position^='top'][mode='card']) .nav-item:not([data-selected]){ 158 border-top-left-radius: 5px; 159 border-top-right-radius: 5px; 160 background-color: var(--dark-border1,#D8D8D8); 161 color: var(--dark-color1,#212121); 162 } 163 :host([position^='top'][mode='card']) .nav-item[data-selected]{ 164 background-color: var(--dark-background,#ffffff); 165 bottom: 0px; 166 color: var(--dark-color1,#212121); 167 border-top: 1px solid var(--dark-border1,#bababa); 168 border-top-left-radius: 5px; 169 border-top-right-radius: 5px; 170 border-left: 1px solid var(--dark-border1,#bababa); 171 border-right: 1px solid var(--dark-border1,#bababa); 172 } 173 /* 174 bottom bottom-left bottom-center bottom-right 175 */ 176 :host([position^='bottom']) .tab{ 177 display: flex; 178 flex-direction: column-reverse; 179 } 180 :host([mode='flat'][position^='bottom']) .tab-line{ 181 position:absolute; 182 top: -3px; 183 background-color: #42b983; 184 height: 2px; 185 transform: translateY(-100%); 186 transition: all 0.3s; 187 } 188 :host([position^='bottom']) .tab-nav-container{ 189 display: flex; 190 position: relative; 191 flex-direction: column; 192 overflow-x: auto; 193 overflow-y: visible; 194 overflow: -moz-scrollbars-none; 195 -ms-overflow-style: none; 196 transition: all 0.3s; 197 flex: 1; 198 border-top: #f0f0f0 1px solid; 199 } 200 :host([position^='bottom']) .nav-root{ 201 display: flex; 202 justify-content: center; 203 align-items: center; 204 } 205 :host([position='bottom']) .tab-nav, 206 :host([position='bottom-left']) .tab-nav{ 207 display: flex; 208 position: relative; 209 justify-content: flex-start; 210 } 211 :host([position='bottom-center']) .tab-nav{ 212 display: flex; 213 justify-content: center; 214 } 215 :host([position='bottom-right']) .tab-nav{ 216 display: flex; 217 justify-content: flex-end; 218 } 219 :host([position^='bottom'][mode='card']) .nav-item{ 220 border-top: 1px solid #ffffff; 221 border-left: 1px solid #f0f0f0; 222 border-right: 1px solid #f0f0f0; 223 border-bottom: 1px solid #f0f0f0; 224 top: -1px; 225 margin-right: 2px; 226 position: relative; 227 } 228 :host([position^='bottom']) .tab-nav-bg-line{ 229 position: absolute;top: 0;height: 1px;background-color: #f0f0f0;width: 100% 230 } 231 :host([position^='bottom'][mode='card']) .nav-item:not([data-selected]){ 232 background-color: #f5f5f5; 233 border-top: 1px solid #f0f0f0; 234 } 235 :host([position^='bottom'][mode='card']) .nav-item[data-selected]{ 236 background-color: #ffffff; 237 border-top: 1px solid #fff; 238 top: -1px; 239 } 240 /* 241 left left-top left-center left-bottom 242 */ 243 :host([position^='left']) .tab{ 244 display: flex; 245 flex-direction: row; 246 } 247 :host([mode='flat'][position^='left']) .tab-line{ 248 position:absolute; 249 right: 1px; 250 background-color: #42b983; 251 width: 3px; 252 transform: translateX(100%); 253 transition: all 0.3s; 254 } 255 :host([position^='left']) .tab-nav-container{ 256 display: flex; 257 position: relative; 258 flex-direction: row; 259 overflow-x: auto; 260 overflow-y: visible; 261 overflow: -moz-scrollbars-none; 262 -ms-overflow-style: none; 263 transition: all 0.3s; 264 flex: 1; 265 border-right: #f0f0f0 1px solid; 266 } 267 :host([position^='left']) .nav-root{ 268 display: flex; 269 flex-direction: column; 270 justify-content: center; 271 align-items: center; 272 } 273 :host([position='left']) .tab-nav, 274 :host([position='left-top']) .tab-nav{ 275 display: flex; 276 position: relative; 277 flex-direction: column; 278 justify-content: flex-start; 279 } 280 :host([position='left-center']) .tab-nav{ 281 display: flex; 282 position: relative; 283 flex-direction: column; 284 justify-content: center; 285 } 286 :host([position='left-bottom']) .tab-nav{ 287 display: flex; 288 position: relative; 289 flex-direction: column; 290 justify-content: flex-end; 291 } 292 :host([position^='left'][mode='card']) .nav-item{ 293 border-top: 1px solid #f0f0f0; 294 border-left: 1px solid #f0f0f0; 295 border-right: 1px solid #ffffff; 296 border-bottom: 1px solid #f0f0f0; 297 right: -1px; 298 margin-bottom: 2px; 299 position: relative; 300 } 301 :host([position^='left']) .tab-nav-bg-line{ 302 position: absolute;right: 0;width: 1px;background-color: #f0f0f0;width: 100% 303 } 304 :host([position^='left'][mode='card']) .nav-item:not([data-selected]){ 305 background-color: #f5f5f5; 306 border-right: 1px solid #f0f0f0; 307 } 308 :host([position^='left'][mode='card']) .nav-item[data-selected]{ 309 background-color: #ffffff; 310 border-bottom: 1px solid #fff; 311 right: -1px; 312 } 313 /* 314 right right-top right-center right-bottom 315 */ 316 :host([position^='right']) .tab{ 317 display: flex; 318 flex-direction: row-reverse; 319 } 320 :host([mode='flat'][position^='right']) .tab-line{ 321 position:absolute; 322 left: 1px; 323 background-color: #42b983; 324 width: 3px; 325 transform: translateX(-100%); 326 transition: all 0.3s; 327 } 328 :host([position^='right']) .tab-nav-container{ 329 display: flex; 330 position: relative; 331 flex-direction: row-reverse; 332 overflow-x: auto; 333 overflow-y: visible; 334 overflow: -moz-scrollbars-none; 335 -ms-overflow-style: none; 336 transition: all 0.3s; 337 flex: 1; 338 border-left: #f0f0f0 1px solid; 339 } 340 :host([position^='right']) .nav-root{ 341 display: flex; 342 flex-direction: column; 343 justify-content: center; 344 align-items: center; 345 } 346 :host([position='right']) .tab-nav, 347 :host([position='right-top']) .tab-nav{ 348 display: flex; 349 position: relative; 350 flex-direction: column; 351 justify-content: flex-start; 352 } 353 :host([position='right-center']) .tab-nav{ 354 display: flex; 355 position: relative; 356 flex-direction: column; 357 justify-content: center; 358 } 359 :host([position='right-bottom']) .tab-nav{ 360 display: flex; 361 position: relative; 362 flex-direction: column; 363 justify-content: flex-end; 364 } 365 :host([position^='right'][mode='card']) .nav-item{ 366 border-top: 1px solid #f0f0f0; 367 border-left: 1px solid #ffffff; 368 border-right: 1px solid #f0f0f0; 369 border-bottom: 1px solid #f0f0f0; 370 left: -1px; 371 margin-top: 2px; 372 position: relative; 373 } 374 :host([position^='right']) .tab-nav-bg-line{ 375 position: absolute;left: 0;width: 1px;background-color: #f0f0f0;width: 100% 376 } 377 :host([position^='right'][mode='card']) .nav-item:not([data-selected]){ 378 background-color: #f5f5f5; 379 border-left: 1px solid #f0f0f0; 380 } 381 :host([position^='right'][mode='card']) .nav-item[data-selected]{ 382 background-color: #ffffff; 383 left: -1px; 384 } 385 386 387 .tab-nav-container::-webkit-scrollbar { 388 display: none; 389 } 390 391 .close-icon:hover{ 392 color: #000; 393 } 394 .nav-item[data-closeable] .close-icon{ 395 display: block; 396 padding: 2px 5px; 397 color: var(--dark-icon,#606060) 398 } 399 .nav-item[data-closeable] .no-close-icon{ 400 display: none; 401 } 402 .nav-item:not([data-closeable]) .no-close-icon{ 403 display: block; 404 } 405 .nav-item:not([data-closeable]) .close-icon{ 406 display: none; 407 } 408 409 </style> 410 <style id="filter"></style> 411 <div class="tab" > 412 <div class="nav-root" style="background-color: var(--dark-background4,#f2f2f2);"> 413 <slot name="left" style="flex:1"></slot> 414 <div class="tab-nav-container" > 415 <div class="tab-nav-bg-line"></div> 416 <div class="tab-nav" id="nav" ></div> 417 <div class="tab-line" id="tab-line"></div> 418 </div> 419 <div id="tab-filling" style="flex: 1"></div> 420 <slot name="right" style="flex:1"></slot> 421 </div> 422 <div class="tab-content"> 423 <slot id="slot">NEED CONTENT</slot> 424 </div> 425 </div> 426 `; 427 } 428 429 static get observedAttributes() { 430 return ['activekey', 'mode', 'position']; 431 } 432 433 get position() { 434 return this.getAttribute('position') || 'top'; 435 } 436 437 set position(value) { 438 this.setAttribute('position', value); 439 } 440 441 get mode() { 442 return this.getAttribute('mode') || 'flat'; 443 } 444 445 set mode(value) { 446 this.setAttribute('mode', value); 447 } 448 449 get activekey() { 450 return this.getAttribute('activekey') || ''; 451 } 452 453 set activekey(value: string) { 454 this.setAttribute('activekey', value); 455 } 456 457 set onTabClick(fn: any) { 458 this.addEventListener('onTabClick', fn); 459 } 460 461 updateLabel(key: string, value: string) { 462 if (this.nav) { 463 let item = this.nav.querySelector(`.nav-item[data-key='${key}']`); 464 if (item) { 465 item.querySelector<HTMLSpanElement>('span')!.innerHTML = value; 466 this.initTabPos(); 467 } 468 } 469 } 470 471 updateDisabled(key: string, value: string) { 472 if (this.nav) { 473 let item = this.nav.querySelector(`.nav-item[data-key='${key}']`); 474 if (item) { 475 if (value) { 476 item.setAttribute('data-disabled', ''); 477 } else { 478 item.removeAttribute('data-disabled'); 479 } 480 this.initTabPos(); 481 } 482 } 483 } 484 485 updateCloseable(key: string, value: string) { 486 if (this.nav) { 487 let item = this.nav.querySelector(`.nav-item[data-key='${key}']`); 488 if (item) { 489 if (value) { 490 item.setAttribute('data-closeable', ''); 491 } else { 492 item.removeAttribute('data-closeable'); 493 } 494 this.initTabPos(); 495 } 496 } 497 } 498 499 updateHidden(key: string, value: string) { 500 if (this.nav) { 501 let item = this.nav.querySelector(`.nav-item[data-key='${key}']`); 502 if (item) { 503 if (value === 'true') { 504 item.setAttribute('data-hidden', ''); 505 } else { 506 item.removeAttribute('data-hidden'); 507 } 508 this.initTabPos(); 509 } 510 } 511 } 512 513 initTabPos() { 514 const items = this.nav!.querySelectorAll<HTMLDivElement>('.nav-item'); 515 Array.from(items).forEach((a, index) => { 516 // @ts-ignore 517 this.tabPos[a.dataset.key] = { 518 index: index, 519 width: a.offsetWidth, 520 height: a.offsetHeight, 521 left: a.offsetLeft, 522 top: a.offsetTop, 523 label: a.textContent, 524 }; 525 }); 526 if (this.activekey) { 527 if (this.position.startsWith('left')) { 528 this.line?.setAttribute( 529 'style', 530 `height:${this.tabPos[this.activekey].height}px;transform:translate(100%,${ 531 this.tabPos[this.activekey].top 532 }px)` 533 ); 534 } else if (this.position.startsWith('top')) { 535 if (this.tabPos[this.activekey]) { 536 this.line?.setAttribute( 537 'style', 538 `width:${this.tabPos[this.activekey].width}px;transform:translate(${ 539 this.tabPos[this.activekey].left 540 }px,100%)` 541 ); 542 } 543 } else if (this.position.startsWith('right')) { 544 this.line?.setAttribute( 545 'style', 546 `height:${this.tabPos[this.activekey].height}px;transform:translate(-100%,${ 547 this.tabPos[this.activekey].top 548 }px)` 549 ); 550 } else if (this.position.startsWith('bottom')) { 551 this.line?.setAttribute( 552 'style', 553 `width:${this.tabPos[this.activekey].width}px;transform:translate(${this.tabPos[this.activekey].left}px,100%)` 554 ); 555 } 556 } 557 } 558 559 connectedCallback() { 560 let that = this; 561 this.tabPos = {}; 562 this.nav = this.shadowRoot?.querySelector('#nav'); 563 this.line = this.shadowRoot?.querySelector('#tab-line'); 564 this.slots = this.shadowRoot?.querySelector('#slot'); 565 this.slots?.addEventListener('slotchange', () => { 566 const elements: Element[] | undefined = this.slots?.assignedElements(); 567 let panes = this.querySelectorAll<LitTabpane>('lit-tabpane'); 568 if (this.activekey) { 569 panes.forEach((a) => { 570 if (a.key === this.activekey) { 571 a.style.display = 'block'; 572 } else { 573 a.style.display = 'none'; 574 } 575 }); 576 } else { 577 panes.forEach((a, index) => { 578 if (index === 0) { 579 a.style.display = 'block'; 580 this.activekey = a.key || ''; 581 } else { 582 a.style.display = 'none'; 583 } 584 }); 585 } 586 let navHtml = ''; 587 elements 588 ?.map((it) => it as LitTabpane) 589 .forEach((a) => { 590 if (a.disabled) { 591 navHtml += `<div class="nav-item" data-key="${a.key}" data-disabled ${a.closeable ? 'data-closeable' : ''}> 592 ${a.icon ? `<lit-icon name='${a.icon}'></lit-icon>` : ``} 593 <span>${a.tab}</span> 594 <lit-icon class="close-icon" name='close' size="16"></lit-icon><div class="no-close-icon" style="margin-right: 12px"></div> 595 </div>`; 596 } else if (a.hidden) { 597 navHtml += `<div class="nav-item" data-key="${a.key}" data-hidden ${a.closeable ? 'data-closeable' : ''}> 598 ${a.icon ? `<lit-icon name='${a.icon}'></lit-icon>` : ``} 599 <span>${a.tab}</span> 600 <lit-icon class="close-icon" name='close' size="16"></lit-icon><div class="no-close-icon" style="margin-right: 12px"></div> 601 </div>`; 602 } else { 603 if (a.key === this.activekey) { 604 navHtml += `<div class="nav-item" data-key="${a.key}" data-selected ${ 605 a.closeable ? 'data-closeable' : '' 606 }> 607 ${a.icon ? `<lit-icon name='${a.icon}'></lit-icon>` : ``} 608 <span>${a.tab}</span> 609 <lit-icon class="close-icon" name='close' size="16"></lit-icon><div class="no-close-icon" style="margin-right: 12px"></div> 610 </div>`; 611 } else { 612 navHtml += `<div class="nav-item" data-key="${a.key}" ${a.closeable ? 'data-closeable' : ''}> 613 ${a.icon ? `<lit-icon name='${a.icon}'></lit-icon>` : ``} 614 <span>${a.tab}</span> 615 <lit-icon class="close-icon" name='close' size="16"></lit-icon><div class="no-close-icon" style="margin-right: 12px"></div> 616 </div>`; 617 } 618 } 619 }); 620 this.nav!.innerHTML = navHtml; 621 this.initTabPos(); 622 this.nav!.querySelectorAll<HTMLElement>('.close-icon').forEach((a) => { 623 a.onclick = (e) => { 624 e.stopPropagation(); 625 const closeKey = (e.target! as HTMLElement).parentElement!.dataset.key; 626 this.dispatchEvent( 627 new CustomEvent('close-handler', { 628 detail: { key: closeKey }, 629 composed: true, 630 }) 631 ); 632 }; 633 }); 634 }); 635 this.nav!.onclick = (e) => { 636 if ((e.target! as HTMLElement).closest('div')!.hasAttribute('data-disabled')) return; 637 let key = (e.target! as HTMLElement).closest('div')!.dataset.key; 638 if (key) { 639 this.activeByKey(key); 640 } 641 let label = (e.target! as HTMLElement).closest('div')!.querySelector('span')!.textContent; 642 this.dispatchEvent( 643 new CustomEvent('onTabClick', { 644 detail: { key: key, tab: label }, 645 }) 646 ); 647 }; 648 649 new ResizeObserver((entries) => { 650 let filling = this.shadowRoot!.querySelector<HTMLDivElement>('#tab-filling'); 651 652 this.shadowRoot!.querySelector<HTMLDivElement>('.tab-nav-container')!.style.height = filling!.offsetWidth + 'px'; 653 }).observe(this.shadowRoot!.querySelector('#tab-filling')!); 654 } 655 656 activeByKey(key: string, isValid: boolean = true) { 657 if (key === null || key === undefined) return; //如果没有key 不做相应 658 this.nav!.querySelectorAll('.nav-item').forEach((a) => { 659 if (a.querySelector('span')?.innerText === 'Comparison') { 660 a.setAttribute('id', 'nav-comparison'); 661 } 662 if (a.getAttribute('data-key') === key) { 663 a.setAttribute('data-selected', 'true'); 664 if (isValid) { 665 let span = a.querySelector('span') as HTMLSpanElement; 666 let title = span.innerText; 667 let rowType = document 668 .querySelector<HTMLElement>('sp-application')! 669 .shadowRoot?.querySelector<HTMLElement>('sp-system-trace')! 670 .getAttribute('clickRow'); 671 if (title === 'Counters' || title === 'Thread States') { 672 title += `(${rowType})`; 673 } 674 if (title === 'Analysis') { 675 let rowId = document 676 .querySelector<HTMLElement>('sp-application')! 677 .shadowRoot?.querySelector<HTMLElement>('sp-system-trace')! 678 .getAttribute('rowId'); 679 if (rowId!.indexOf('DiskIOLatency') > -1) { 680 title += '(disk-io)'; 681 } else if (rowId!.indexOf('VirtualMemory') > -1) { 682 title += '(virtual-memory-cell)'; 683 } else { 684 title += `(${rowType})`; 685 } 686 } 687 if (title === 'Slices' || title === 'Current Selection') { 688 let rowName = document 689 .querySelector<HTMLElement>('sp-application')! 690 .shadowRoot?.querySelector<HTMLElement>('sp-system-trace')! 691 .getAttribute('rowName'); 692 if (rowName && rowName!.indexOf('deliverInputEvent') > -1) { 693 title += '(deliverInputEvent)'; 694 } else { 695 let rowType = document 696 .querySelector<HTMLElement>('sp-application')! 697 .shadowRoot?.querySelector<HTMLElement>('sp-system-trace')! 698 .getAttribute('clickRow'); 699 title += `(${rowType})`; 700 } 701 } 702 SpStatisticsHttpUtil.addOrdinaryVisitAction({ 703 event: title, 704 action: 'trace_tab', 705 }); 706 } 707 } else { 708 a.removeAttribute('data-selected'); 709 } 710 }); 711 let tbp = this.querySelector(`lit-tabpane[key='${key}']`); 712 let panes = this.querySelectorAll<LitTabpane>('lit-tabpane'); 713 panes.forEach((a) => { 714 if (a.key === key) { 715 a.style.display = 'block'; 716 this.activekey = a.key; 717 this.initTabPos(); 718 } else { 719 a.style.display = 'none'; 720 } 721 }); 722 } 723 724 activePane(key: string) { 725 if (key === null || key === undefined) return false; 726 let tbp = this.querySelector(`lit-tabpane[key='${key}']`); 727 if (tbp) { 728 this.activeByKey(key); 729 return true; 730 } else { 731 return false; 732 } 733 } 734 735 disconnectedCallback() {} 736 737 adoptedCallback() {} 738 739 attributeChangedCallback(name: string, oldValue: string, newValue: string) { 740 if (name === 'activekey' && this.nav && oldValue !== newValue && newValue != '') { 741 this.activeByKey(newValue, false); 742 } 743 } 744} 745