Changes for page Service Navigator
Last modified by Veronika Kocher on Thursday, 03 Sep 2026 14:15
From version 22.16
edited by Veronika Kocher
on Thursday, 03 Sep 2026 13:04
on Thursday, 03 Sep 2026 13:04
Change comment:
There is no comment for this version
To version 22.15
edited by Veronika Kocher
on Thursday, 03 Sep 2026 10:09
on Thursday, 03 Sep 2026 10:09
Change comment:
There is no comment for this version
Summary
-
Page properties (1 modified, 0 added, 0 removed)
Details
- Page properties
-
- Content
-
... ... @@ -285,13 +285,12 @@ 285 285 </div> 286 286 {{/html}} 287 287 288 -{{html clean="false"}} 289 -<!-- SN_SERVICE_NAVIGATOR_MASTER_STYLE_START --> 288 +\n\n 289 +\n\n{{html clean="false"}} 290 +<!-- SN_HORIZONTAL_BOX_HARMONIZER_START --> 290 290 291 -<style data-sn-service-navigator-master="1"> 292 -/* ========================================================= 293 - MASTER TYPOGRAPHY 294 - ========================================================= */ 292 +<style data-sn-horizontal-box-harmonizer="7"> 293 +/* ---------- Typography: never justify headings ---------- */ 295 295 #xwikicontent h1, 296 296 #xwikicontent h2, 297 297 #xwikicontent h3, ... ... @@ -313,73 +313,88 @@ 313 313 word-spacing:normal!important; 314 314 } 315 315 316 -/* ========================================================= 317 - COMING SOON / IN VORBEREITUNG 318 - ========================================================= */ 319 -.sn-coming-soon-badge{ 320 - display:inline-block; 321 - vertical-align:middle; 322 - margin-left:10px; 323 - padding:4px 8px; 324 - border-radius:14px; 325 - border:1px solid #efd9cc; 326 - background:#fff4ee; 327 - color:#8a4d36; 328 - font-size:11px; 329 - font-weight:700; 330 - letter-spacing:.055em; 331 - line-height:1.2; 332 - white-space:nowrap; 333 -} 334 - 335 -/* ========================================================= 336 - NATIVE / DETAIL CALLOUT GEOMETRY 337 - Preserve existing backgrounds. 338 - ========================================================= */ 339 -#xwikicontent .arsn-info, 340 -#xwikicontent .dmp-info, 341 -#xwikicontent .ido-info, 342 -#xwikicontent .pp-info, 343 -#xwikicontent .infomessage{ 315 +/* ---------- Native XWiki semantic callouts ---------- */ 316 +#xwikicontent .box.infomessage, 317 +#xwikicontent .infomessage, 318 +#xwikicontent .box.warningmessage, 319 +#xwikicontent .warningmessage, 320 +#xwikicontent .box.successmessage, 321 +#xwikicontent .successmessage, 322 +#xwikicontent .box.errormessage, 323 +#xwikicontent .errormessage, 324 +#xwikicontent [data-sn-callout-harmonized="1"]{ 344 344 box-sizing:border-box!important; 345 - border-left:4px solid #21b6d7!important; 346 - border-radius:8px; 326 + border-radius:8px!important; 327 + border-top:1px solid rgba(0,0,0,.08)!important; 328 + border-right:1px solid rgba(0,0,0,.08)!important; 329 + border-bottom:1px solid rgba(0,0,0,.08)!important; 330 + border-left:4px solid var(--sn-callout-accent,#21b6d7)!important; 331 + padding:14px 16px!important; 347 347 text-align:left!important; 333 + text-justify:auto!important; 348 348 word-spacing:normal!important; 335 + box-shadow:none!important; 349 349 } 350 350 351 -#xwikicontent .arsn-warn, 352 -#xwikicontent .dmp-warn, 353 -#xwikicontent .ido-warn, 354 -#xwikicontent .pp-warn, 355 -#xwikicontent .warn, 356 -#xwikicontent .warning, 357 -#xwikicontent .warningmessage, 338 +#xwikicontent .box.infomessage, 339 +#xwikicontent .infomessage{ 340 + --sn-callout-accent:#21b6d7; 341 + background:#eaf7fb!important; 342 +} 343 + 344 +#xwikicontent .box.warningmessage, 345 +#xwikicontent .warningmessage{ 346 + --sn-callout-accent:#f0aa00; 347 + background:#fff8e7!important; 348 +} 349 + 350 +#xwikicontent .box.successmessage, 351 +#xwikicontent .successmessage{ 352 + --sn-callout-accent:#38b76a; 353 + background:#edf9f1!important; 354 +} 355 + 356 +#xwikicontent .box.errormessage, 358 358 #xwikicontent .errormessage{ 359 - box-sizing:border-box!important; 360 - border-left:4px solid #e94b13!important; 361 - border-radius:8px; 362 - text-align:left!important; 363 - word-spacing:normal!important; 358 + --sn-callout-accent:#e94b13; 359 + background:#fff1ec!important; 364 364 } 365 365 366 -[data-sn-master-equal-height], 367 -[data-sn-master-first-row]{ 362 +#xwikicontent [data-sn-callout-harmonized="1"] > :first-child, 363 +#xwikicontent .infomessage > :first-child, 364 +#xwikicontent .warningmessage > :first-child, 365 +#xwikicontent .successmessage > :first-child, 366 +#xwikicontent .errormessage > :first-child{ 367 + margin-top:0!important; 368 +} 369 + 370 +#xwikicontent [data-sn-callout-harmonized="1"] > :last-child, 371 +#xwikicontent .infomessage > :last-child, 372 +#xwikicontent .warningmessage > :last-child, 373 +#xwikicontent .successmessage > :last-child, 374 +#xwikicontent .errormessage > :last-child{ 375 + margin-bottom:0!important; 376 +} 377 + 378 +#xwikicontent [data-sn-equal-height-managed], 379 +#xwikicontent [data-sn-first-section-aligned], 380 +#xwikicontent [data-sn-first-content-aligned]{ 368 368 box-sizing:border-box; 369 369 } 370 370 </style> 371 371 372 -<script data-sn- service-navigator-master="1">385 +<script data-sn-horizontal-box-harmonizer="7"> 373 373 (function(){ 374 374 "use strict"; 375 375 376 - var PAGE_KIND="overview"; 377 - var PLACEHOLDER=false; 378 - var PLACEHOLDER_LABEL="COMING SOON"; 379 - 380 380 var MOBILE_MAX=767; 381 381 var ROW_TOLERANCE=6; 391 + var MIN_W=150; 392 + var MIN_H=36; 393 + var MAX_PARENT_CHILDREN=18; 394 + var SEARCH_DEPTH=5; 382 382 var RESIZE_DEBOUNCE=220; 396 + var MIN_WIDTH_CHANGE=2; 383 383 384 384 var root= 385 385 document.getElementById("xwikicontent")|| ... ... @@ -389,114 +389,142 @@ 389 389 390 390 if(!root)return; 391 391 392 - var managedHeight=new Set(); 393 - var managedMargin=new Set(); 394 - var originalHeight=new WeakMap(); 395 - var originalMargin=new WeakMap(); 406 + var heightManaged=new Set(); 407 + var sectionManaged=new Set(); 408 + var contentManaged=new Set(); 396 396 410 + var originalMinHeight=new WeakMap(); 411 + var originalMarginTop=new WeakMap(); 412 + 397 397 var resizeTimer=0; 398 - var running=false; 414 + var lastWidth=-1; 415 + var hasApplied=false; 416 + var applying=false; 399 399 400 - var THEMES=[ 401 - { 402 - name:"BLUE", 403 - accent:"#21b6d7", 404 - bg:"#eaf7fb", 405 - text:"#315d68", 406 - labels:[ 407 - "HIER STARTEN", 408 - "ENTSCHEIDEN", 409 - "ÜBERPRÜFEN & ANPASSEN", 410 - "START HERE", 411 - "DECIDE", 412 - "REVIEW & ADAPT" 413 - ] 414 - }, 415 - { 416 - name:"RED", 417 - accent:"#e94b13", 418 - bg:"#fff1ec", 419 - text:"#8a4d36", 420 - labels:[ 421 - "PLANEN & ORGANISIEREN", 422 - "ORGANISIEREN & DOKUMENTIEREN", 423 - "PUBLIZIEREN & PRÄSENTIEREN", 424 - "PLAN & ORGANISE", 425 - "PLAN & ORGANIZE", 426 - "ORGANISE & DOCUMENT", 427 - "ORGANIZE & DOCUMENT", 428 - "PUBLISH & PRESENT" 429 - ] 430 - }, 431 - { 432 - name:"YELLOW", 433 - accent:"#f0aa00", 434 - bg:"#fff8e7", 435 - text:"#785b17", 436 - labels:[ 437 - "SCHÜTZEN & KLÄREN", 438 - "STANDARDISIEREN & IDENTIFIZIEREN", 439 - "ÖFFNEN, NACHNUTZEN & AUFFINDBAR MACHEN", 440 - "PROTECT & CLARIFY", 441 - "STANDARDISE & IDENTIFY", 442 - "STANDARDIZE & IDENTIFY", 443 - "OPEN, REUSE & MAKE FINDABLE" 444 - ] 445 - }, 446 - { 447 - name:"GREEN", 448 - accent:"#38b76a", 449 - bg:"#edf9f1", 450 - text:"#3f7451", 451 - labels:[ 452 - "INFRASTRUKTUR EINRICHTEN", 453 - "INFRASTRUKTUR & ZUSAMMENARBEIT EINRICHTEN", 454 - "SPEICHERN & ZUGRIFF STEUERN", 455 - "REPOSITORIUM, ERHALTEN & ÜBERGEBEN", 456 - "SET UP INFRASTRUCTURE", 457 - "SET UP INFRASTRUCTURE & COLLABORATION", 458 - "STORE & CONTROL ACCESS", 459 - "REPOSITORY, PRESERVE & HAND OVER" 460 - ] 418 + function num(v){ 419 + var n=parseFloat(v); 420 + return Number.isFinite(n)?n:0; 421 + } 422 + 423 + function visible(el,minW,minH){ 424 + if(!el||el.nodeType!==1)return false; 425 + 426 + var s=getComputedStyle(el); 427 + 428 + if( 429 + s.display==="none"|| 430 + s.visibility==="hidden"|| 431 + Number(s.opacity)===0 432 + ){ 433 + return false; 461 461 } 462 - ]; 463 463 464 - function num(value){ 465 - var n=parseFloat(value); 466 - return Number.isFinite(n)?n:0; 436 + var r=el.getBoundingClientRect(); 437 + 438 + return ( 439 + r.width>=(minW||1)&& 440 + r.height>=(minH||1) 441 + ); 467 467 } 468 468 469 - function norm (value){470 - return String( value||"")444 + function normalizeText(text){ 445 + return String(text||"") 471 471 .replace(/\s+/g," ") 472 472 .trim() 473 473 .toUpperCase(); 474 474 } 475 475 476 - function visible(el){ 477 - if(!el||el.nodeType!==1)return false; 451 + function excluded(el){ 452 + return ( 453 + !el.matches|| 454 + el.matches( 455 + "button,input,select,textarea,option,label,img,svg,canvas,table,thead,tbody,tfoot,tr,td,th,summary,script,style,noscript,template,.btn,.chip,[role=button]" 456 + ) 457 + ); 458 + } 478 478 479 - var style=getComputedStyle(el); 480 - var rect=el.getBoundingClientRect(); 460 + /* ---------- Custom coloured callouts ---------- */ 481 481 462 + function nativeCallout(el){ 463 + var c= 464 + typeof el.className==="string" 465 + ? el.className.toLowerCase() 466 + : ""; 467 + 482 482 return ( 483 - style.display!=="none"&& 484 - style.visibility!=="hidden"&& 485 - rect.width>20&& 486 - rect.height>4 469 + /(^|\s)(infomessage|warningmessage|successmessage|errormessage)(\s|$)/.test(c) 487 487 ); 488 488 } 489 489 490 - function saveStyle(el,map,property){ 473 + function customCallout(el){ 474 + if(!visible(el,220,42)||excluded(el))return false; 475 + 476 + var r=el.getBoundingClientRect(); 477 + 478 + if(r.height>520)return false; 479 + 480 + var s=getComputedStyle(el); 481 + 482 + var bg= 483 + s.backgroundColor&& 484 + s.backgroundColor!=="rgba(0, 0, 0, 0)"&& 485 + s.backgroundColor!=="transparent"&& 486 + s.backgroundColor!=="rgb(255, 255, 255)"; 487 + 488 + var left= 489 + num(s.borderLeftWidth); 490 + 491 + return ( 492 + bg&& 493 + left>=2 494 + ); 495 + } 496 + 497 + function harmoniseCustomCallouts(){ 498 + Array.from( 499 + root.querySelectorAll( 500 + "div,aside,section" 501 + ) 502 + ).forEach(function(el){ 503 + if(nativeCallout(el))return; 504 + if(!customCallout(el))return; 505 + 506 + var s=getComputedStyle(el); 507 + 508 + el.setAttribute( 509 + "data-sn-callout-harmonized", 510 + "1" 511 + ); 512 + 513 + if( 514 + s.borderLeftColor 515 + ){ 516 + el.style.setProperty( 517 + "--sn-callout-accent", 518 + s.borderLeftColor 519 + ); 520 + } 521 + }); 522 + } 523 + 524 + /* ---------- Restore only values V7 itself changed ---------- */ 525 + 526 + function saveOriginal(el,map,property){ 491 491 if(map.has(el))return; 492 492 493 493 map.set(el,{ 494 - value:el.style.getPropertyValue(property), 495 - priority:el.style.getPropertyPriority(property) 530 + value: 531 + el.style.getPropertyValue( 532 + property 533 + ), 534 + priority: 535 + el.style.getPropertyPriority( 536 + property 537 + ) 496 496 }); 497 497 } 498 498 499 - function restore Style(el,map,property){541 + function restoreOriginal(el,map,property){ 500 500 var original=map.get(el); 501 501 502 502 if(original&&original.value){ ... ... @@ -506,845 +506,770 @@ 506 506 original.priority||"" 507 507 ); 508 508 }else{ 509 - el.style.removeProperty(property); 551 + el.style.removeProperty( 552 + property 553 + ); 510 510 } 511 511 } 512 512 513 513 function resetRuntime(){ 514 - managedHeight.forEach(function(el){515 - restore Style(558 + heightManaged.forEach(function(el){ 559 + restoreOriginal( 516 516 el, 517 - originalHeight, 561 + originalMinHeight, 518 518 "min-height" 519 519 ); 564 + 520 520 el.removeAttribute( 521 - "data-sn- master-equal-height"566 + "data-sn-equal-height-managed" 522 522 ); 523 523 }); 524 524 525 - managedMargin.forEach(function(el){526 - restore Style(570 + sectionManaged.forEach(function(el){ 571 + restoreOriginal( 527 527 el, 528 - originalMargin, 573 + originalMarginTop, 529 529 "margin-top" 530 530 ); 576 + 531 531 el.removeAttribute( 532 - "data-sn- master-first-row"578 + "data-sn-first-section-aligned" 533 533 ); 534 534 }); 535 535 536 - managedHeight.clear(); 537 - managedMargin.clear(); 538 - } 582 + contentManaged.forEach(function(el){ 583 + restoreOriginal( 584 + el, 585 + originalMarginTop, 586 + "margin-top" 587 + ); 539 539 540 - function themeFor(text){ 541 - var value=norm(text); 589 + el.removeAttribute( 590 + "data-sn-first-content-aligned" 591 + ); 592 + }); 542 542 543 - for(var i=0;i<THEMES.length;i++){ 544 - for(var j=0;j<THEMES[i].labels.length;j++){ 545 - var label=THEMES[i].labels[j]; 546 - 547 - if( 548 - value===label|| 549 - value.indexOf(label+" ")===0|| 550 - value.indexOf(label+" -")===0|| 551 - value.indexOf(label+" ·")===0 552 - ){ 553 - return THEMES[i]; 554 - } 555 - } 556 - } 557 - 558 - return null; 594 + heightManaged.clear(); 595 + sectionManaged.clear(); 596 + contentManaged.clear(); 559 559 } 560 560 561 - /* ======================================================= 562 - PLACEHOLDER BADGE 563 - ======================================================= */ 599 + /* ---------- Card detection ---------- */ 564 564 565 - function applyPlaceholderBadge(){ 566 - if(!PLACEHOLDER)return; 601 + function namedLikeBox(el){ 602 + var c= 603 + typeof el.className==="string" 604 + ? el.className 605 + : ""; 567 567 607 + return /(^|[\s_-])(box|card|tile|panel|role|check|service|source|call|area|detail|resource|topic|warn|info)([\s_-]|$)/i.test(c); 608 + } 609 + 610 + function boxLike(el){ 568 568 if( 569 - document.querySelector( 570 - ".sn-coming-soon-badge" 571 - ) 612 + !visible(el,MIN_W,MIN_H)|| 613 + excluded(el) 572 572 ){ 573 - return; 615 + return false; 574 574 } 575 575 576 - var title= 577 - document.querySelector( 578 - "#document-title" 579 - )|| 580 - document.querySelector( 581 - "h1" 582 - ); 618 + var s=getComputedStyle(el); 619 + var r=el.getBoundingClientRect(); 583 583 584 - if(!title)return; 621 + var border= 622 + num(s.borderTopWidth)+ 623 + num(s.borderRightWidth)+ 624 + num(s.borderBottomWidth)+ 625 + num(s.borderLeftWidth); 585 585 586 - var badge= 587 - document.createElement( 588 - "span" 589 - ); 590 - 591 - badge.className= 592 - "sn-coming-soon-badge"; 593 - 594 - badge.textContent= 595 - PLACEHOLDER_LABEL; 596 - 597 - badge.setAttribute( 598 - "aria-label", 599 - PLACEHOLDER_LABEL 627 + var radius=Math.max( 628 + num(s.borderTopLeftRadius), 629 + num(s.borderTopRightRadius), 630 + num(s.borderBottomLeftRadius), 631 + num(s.borderBottomRightRadius) 600 600 ); 601 601 602 - title.appendChild(603 - ba dge604 - ) ;605 - }634 + var bg= 635 + s.backgroundColor&& 636 + s.backgroundColor!=="rgba(0, 0, 0, 0)"&& 637 + s.backgroundColor!=="transparent"; 606 606 607 - /*=======================================================608 - DETAILPAGE OWN-ACCENT PROPAGATION609 - == ===================================================== */639 + var shadow= 640 + s.boxShadow&& 641 + s.boxShadow!=="none"; 610 610 611 - function parseRGB(value){ 612 - var match=String(value||"").match( 613 - /rgba?\(\s*([\d.]+)\s*,\s*([\d.]+)\s*,\s*([\d.]+)/i 643 + return ( 644 + namedLikeBox(el)|| 645 + border>=1|| 646 + (bg&&radius>=3)|| 647 + (shadow&&r.width>=180) 614 614 ); 615 - 616 - if(!match)return null; 617 - 618 - return [ 619 - Number(match[1]), 620 - Number(match[2]), 621 - Number(match[3]) 622 - ]; 623 623 } 624 624 625 - function distance(a,b){ 626 - return Math.sqrt( 627 - Math.pow(a[0]-b[0],2)+ 628 - Math.pow(a[1]-b[1],2)+ 629 - Math.pow(a[2]-b[2],2) 630 - ); 631 - } 651 + function pickTarget(child){ 652 + if(!visible(child,MIN_W,MIN_H))return null; 632 632 633 - function paletteMatch(cssColor){ 634 - var rgb=parseRGB(cssColor); 654 + if(boxLike(child))return child; 635 635 636 - if(!rgb)return null; 656 + var cr=child.getBoundingClientRect(); 657 + var q=[]; 637 637 638 - var palette=[ 639 - {hex:"#21b6d7",rgb:[33,182,215]}, 640 - {hex:"#e94b13",rgb:[233,75,19]}, 641 - {hex:"#f0aa00",rgb:[240,170,0]}, 642 - {hex:"#38b76a",rgb:[56,183,106]} 643 - ]; 659 + Array.from(child.children||[]).forEach(function(el){ 660 + q.push({el:el,depth:1}); 661 + }); 644 644 645 645 var best=null; 646 - var best Distance=Infinity;664 + var bestScore=-Infinity; 647 647 648 - palette.forEach(function(item){ 649 - var d=distance(rgb,item.rgb); 666 + while(q.length){ 667 + var item=q.shift(); 668 + var el=item.el; 650 650 651 - if(d<bestDistance){ 652 - best=item; 653 - bestDistance=d; 654 - } 655 - }); 670 + if(!visible(el,MIN_W,MIN_H))continue; 656 656 657 - return bestDistance<=30 658 - ?best 659 - :null; 660 - } 672 + var r=el.getBoundingClientRect(); 661 661 662 - function propagateDetailAccents(){ 663 - if(PAGE_KIND!=="detail")return; 664 - 665 - Array.from( 666 - root.querySelectorAll( 667 - ".arsn-call,.dmp-call,.ido-call,.pp-call,"+ 668 - ".arsn-source,.dmp-source,.ido-source,.pp-source" 669 - ) 670 - ).forEach(function(el){ 671 - if(!visible(el))return; 672 - 673 - var style=getComputedStyle(el); 674 - 675 675 if( 676 - num(style.borderTopWidth)>=2 675 + r.width>=cr.width*.68&& 676 + boxLike(el) 677 677 ){ 678 - var match= 679 - paletteMatch( 680 - style.borderTopColor 678 + var widthFit= 679 + 1-Math.min( 680 + 1, 681 + Math.abs(cr.width-r.width)/ 682 + Math.max(1,cr.width) 681 681 ); 682 682 683 - if(match){ 684 - el.style.setProperty( 685 - "border-left", 686 - "4px solid "+match.hex, 687 - "important" 685 + var topFit= 686 + 1-Math.min( 687 + 1, 688 + Math.abs(cr.top-r.top)/100 688 688 ); 690 + 691 + var score= 692 + widthFit*6+ 693 + topFit*3+ 694 + Math.min(r.height,900)/450+ 695 + Math.min(r.width*r.height,900000)/900000; 696 + 697 + if(score>bestScore){ 698 + best=el; 699 + bestScore=score; 689 689 } 690 690 } 691 - }); 692 692 693 - // Warning families: explicit safety override. 694 - Array.from( 695 - root.querySelectorAll( 696 - ".arsn-warn,.dmp-warn,.ido-warn,.pp-warn,"+ 697 - ".warn,.warning,.warningmessage,.errormessage" 698 - ) 699 - ).forEach(function(el){ 700 - if(!visible(el))return; 703 + if(item.depth<SEARCH_DEPTH){ 704 + Array.from(el.children||[]).forEach(function(next){ 705 + q.push({ 706 + el:next, 707 + depth:item.depth+1 708 + }); 709 + }); 710 + } 711 + } 701 701 702 - el.style.setProperty( 703 - "border-left", 704 - "4px solid #e94b13", 705 - "important" 706 - ); 707 - }); 713 + return best; 714 + } 708 708 709 - // Info families: explicit orientation override. 710 - Array.from( 711 - root.querySelectorAll( 712 - ".arsn-info,.dmp-info,.ido-info,.pp-info,.infomessage" 713 - ) 714 - ).forEach(function(el){ 715 - if(!visible(el))return; 716 + function groupRows(entries){ 717 + var groups=[]; 716 716 717 - el.style.setProperty( 718 - "border-left", 719 - "4px solid #21b6d7", 720 - "important" 721 - ); 722 - }); 723 - } 719 + entries 720 + .slice() 721 + .sort(function(a,b){ 722 + return ( 723 + a.rect.top-b.rect.top|| 724 + a.rect.left-b.rect.left 725 + ); 726 + }) 727 + .forEach(function(entry){ 728 + var group=null; 724 724 725 - /* ======================================================= 726 - OVERVIEW SEMANTIC THEME PALETTE 727 - ======================================================= */ 730 + for(var i=0;i<groups.length;i++){ 731 + if( 732 + Math.abs( 733 + groups[i].top- 734 + entry.rect.top 735 + )<=ROW_TOLERANCE 736 + ){ 737 + group=groups[i]; 738 + break; 739 + } 740 + } 728 728 729 - function smallestThemeHeaders(){ 730 - return Array.from( 731 - root.querySelectorAll( 732 - "div,span,p,strong,h3,h4,h5,h6" 733 - ) 734 - ).filter(function(el){ 735 - if(!visible(el))return false; 736 - if(!themeFor(el.textContent))return false; 742 + if(!group){ 743 + group={ 744 + top:entry.rect.top, 745 + entries:[] 746 + }; 747 + groups.push(group); 748 + } 737 737 738 - return !Array.from( 739 - el.children||[] 740 - ).some(function(child){ 741 - return !!themeFor( 742 - child.textContent 743 - ); 750 + group.entries.push(entry); 744 744 }); 745 - }); 752 + 753 + return groups; 746 746 } 747 747 748 - function findOverviewCard(header){ 749 - var node=header.parentElement; 750 - var candidates=[]; 756 + function validRow(group){ 757 + if(group.entries.length<2)return false; 751 751 752 - while(node&&node!==root){ 753 - var rect=node.getBoundingClientRect(); 754 - var style=getComputedStyle(node); 759 + var lefts= 760 + group.entries 761 + .map(function(e){return e.rect.left;}) 762 + .sort(function(a,b){return a-b;}); 755 755 756 - var border= 757 - num(style.borderTopWidth)+ 758 - num(style.borderRightWidth)+ 759 - num(style.borderBottomWidth)+ 760 - num(style.borderLeftWidth); 764 + if( 765 + lefts[lefts.length-1]- 766 + lefts[0]< 767 + 80 768 + ){ 769 + return false; 770 + } 761 761 762 - if( 763 - rect.width>=220&& 764 - rect.width<=800&& 765 - rect.height>=120&& 766 - border>=1 767 - ){ 768 - candidates.push(node); 769 - } 772 + var widths= 773 + group.entries 774 + .map(function(e){return e.rect.width;}) 775 + .filter(function(w){return w>0;}); 770 770 771 - node=node.parentElement; 772 - } 777 + if(widths.length<2)return false; 773 773 774 - if(!candidates.length)return null; 779 + var minW= 780 + Math.min.apply(Math,widths); 775 775 776 - candidates.sort(function(a,b){ 777 - return ( 778 - b.getBoundingClientRect().height- 779 - a.getBoundingClientRect().height 782 + var maxW= 783 + Math.max.apply(Math,widths); 784 + 785 + return ( 786 + maxW/ 787 + Math.max(1,minW)<= 788 + 1.9 789 + ); 790 + } 791 + 792 + /* ---------- Known ARSN first section bars ---------- */ 793 + 794 + function knownBar(el){ 795 + var text= 796 + normalizeText( 797 + el.textContent 780 780 ); 781 - }); 782 782 783 - return candidates[0]; 800 + return ( 801 + text==="HIER STARTEN"|| 802 + text==="ORGANISIEREN & DOKUMENTIEREN"|| 803 + text==="ENTSCHEIDEN"|| 804 + text==="START HERE"|| 805 + text==="GET STARTED"|| 806 + text==="ORGANISE & DOCUMENT"|| 807 + text==="ORGANIZE & DOCUMENT"|| 808 + text==="DECIDE" 809 + ); 784 784 } 785 785 786 - function rowCandidates(link,card){ 787 - var result=[]; 812 + function findKnownBar(card){ 788 788 var cardRect= 789 789 card.getBoundingClientRect(); 790 790 791 - var node=link; 816 + var rows= 817 + Array.from( 818 + card.querySelectorAll( 819 + "div,p,span,strong,h3,h4,h5,h6" 820 + ) 821 + ) 822 + .filter(function(el){ 823 + if(!visible(el,20,6))return false; 824 + if(!knownBar(el))return false; 792 792 793 - while(node&&node!==card){ 794 - if(visible(node)){ 795 - var rect= 796 - node.getBoundingClientRect(); 826 + var r=el.getBoundingClientRect(); 797 797 798 - if( 799 - rect.height<=105&& 800 - rect.width>= 801 - cardRect.width*.50&& 802 - rect.width<= 803 - cardRect.width*1.03 804 - ){ 805 - result.push(node); 806 - } 807 - } 828 + var rel= 829 + r.top- 830 + cardRect.top; 808 808 809 - node=node.parentElement; 810 - } 811 - 812 - return result; 813 - } 814 - 815 - function chooseOuterRow( 816 - candidates, 817 - link 818 - ){ 819 - if(!candidates.length){ 820 - return link; 821 - } 822 - 823 - var bordered= 824 - candidates.filter(function(el){ 825 825 return ( 826 - num( 827 - getComputedStyle(el) 828 - .borderLeftWidth 829 - )>=1 833 + rel>=35&& 834 + rel<= 835 + cardRect.height*.75 830 830 ); 837 + }) 838 + .sort(function(a,b){ 839 + return ( 840 + a.getBoundingClientRect().top- 841 + b.getBoundingClientRect().top 842 + ); 831 831 }); 832 832 833 - var pool= 834 - bordered.length 835 - ?bordered 836 - :candidates; 845 + return rows[0]||null; 846 + } 837 837 838 - pool.sort(function(a,b){ 839 - var ar= 840 - a.getBoundingClientRect(); 848 + function alignKnownBars(cards){ 849 + var rows= 850 + cards.map(function(card){ 851 + var bar= 852 + findKnownBar(card); 841 841 842 - var br= 843 - b.getBoundingClientRect(); 854 + if(!bar)return null; 844 844 845 - return ( 846 - ar.left-br.left|| 847 - br.width-ar.width 848 - ); 849 - }); 856 + var cr= 857 + card.getBoundingClientRect(); 850 850 851 - r eturnpool[0]||link;852 - }859 + var br= 860 + bar.getBoundingClientRect(); 853 853 854 - function applyOverviewPalette(){ 855 - if(PAGE_KIND!=="overview"){ 856 - return []; 862 + return { 863 + bar:bar, 864 + relativeTop: 865 + br.top- 866 + cr.top 867 + }; 868 + }); 869 + 870 + if( 871 + rows.some(function(row){ 872 + return !row; 873 + }) 874 + ){ 875 + return false; 857 857 } 858 858 859 - var headers= 860 - smallestThemeHeaders() 861 - .map(function(el){ 862 - return { 863 - el:el, 864 - theme: 865 - themeFor( 866 - el.textContent 867 - ), 868 - card: 869 - findOverviewCard( 870 - el 871 - ) 872 - }; 878 + var target= 879 + Math.max.apply( 880 + Math, 881 + rows.map(function(row){ 882 + return row.relativeTop; 873 873 }) 874 - .filter(function(row){ 875 - return !!row.card; 876 - }); 884 + ); 877 877 878 - var unique=[]; 879 - var seenHeaders=new Set(); 886 + rows.forEach(function(row){ 887 + var delta= 888 + target- 889 + row.relativeTop; 880 880 881 - headers.forEach(function(row){ 882 - var key= 883 - row.theme.name+ 884 - "|"+ 885 - Math.round( 886 - row.card 887 - .getBoundingClientRect() 888 - .left 889 - )+ 890 - "|"+ 891 - Math.round( 892 - row.el 893 - .getBoundingClientRect() 894 - .top 895 - ); 891 + if(delta<=1)return; 896 896 897 - if(!seenHeaders.has(key)){898 - seenHeaders.add(key);899 - unique.push(row);900 - }901 - });893 + saveOriginal( 894 + row.bar, 895 + originalMarginTop, 896 + "margin-top" 897 + ); 902 902 903 - unique.forEach(function(row){ 904 - var headerRect= 905 - row.el 906 - .getBoundingClientRect(); 899 + var current= 900 + num( 901 + getComputedStyle( 902 + row.bar 903 + ).marginTop 904 + ); 907 907 908 - row.el.style.setProperty( 909 - "background", 910 - row.theme.bg, 911 - "important" 906 + row.bar.style.setProperty( 907 + "margin-top", 908 + ( 909 + current+ 910 + delta 911 + )+"px" 912 912 ); 913 913 914 - row.el.style.setProperty( 915 - "color", 916 - row.theme.text, 917 - "important" 914 + row.bar.setAttribute( 915 + "data-sn-first-section-aligned", 916 + "7" 918 918 ); 919 919 920 - row.el.style.setProperty( 921 - "text-align", 922 - "left", 923 - "important" 919 + sectionManaged.add( 920 + row.bar 924 924 ); 922 + }); 925 925 926 - row.el.style.setProperty( 927 - "word-spacing", 928 - "normal", 929 - "important" 930 - ); 924 + return true; 925 + } 931 931 932 - var later= 933 - unique 934 - .filter(function(other){ 935 - return ( 936 - other.card===row.card&& 937 - other.el 938 - .getBoundingClientRect() 939 - .top> 940 - headerRect.top+2 941 - ); 942 - }) 943 - .sort(function(a,b){ 944 - return ( 945 - a.el 946 - .getBoundingClientRect() 947 - .top- 948 - b.el 949 - .getBoundingClientRect() 950 - .top 951 - ); 952 - }); 927 + /* ---------- Generic first content after heading ---------- */ 953 953 954 - var stopTop= 955 - later.length 956 - ?later[0].el 957 - .getBoundingClientRect() 958 - .top 959 - :Infinity; 929 + function heading(card){ 930 + var cr= 931 + card.getBoundingClientRect(); 960 960 933 + var rows= 961 961 Array.from( 962 - row.card.querySelectorAll("a") 963 - ).forEach(function(link){ 964 - if(!visible(link))return; 935 + card.querySelectorAll( 936 + "h1,h2,h3,h4,h5,h6,.box-title,[role=heading]" 937 + ) 938 + ) 939 + .filter(function(el){ 940 + if(!visible(el,20,8))return false; 965 965 966 - var rect= 967 - link.getBoundingClientRect(); 942 + var r=el.getBoundingClientRect(); 968 968 969 - if( 970 - rect.top<= 971 - headerRect.bottom-2|| 972 - rect.top>= 973 - stopTop-2 974 - ){ 975 - return; 976 - } 944 + var rel= 945 + r.top- 946 + cr.top; 977 977 978 - var candidates= 979 - rowCandidates( 980 - link, 981 - row.card 982 - ); 983 - 984 - var target= 985 - chooseOuterRow( 986 - candidates, 987 - link 988 - ); 989 - 990 - candidates.forEach(function(el){ 991 - el.style.setProperty( 992 - "border-left", 993 - "0 solid transparent", 994 - "important" 995 - ); 996 - }); 997 - 998 - target.style.setProperty( 999 - "border-left", 1000 - "3px solid "+ 1001 - row.theme.accent, 1002 - "important" 948 + return ( 949 + rel>=0&& 950 + rel<= 951 + Math.min( 952 + 160, 953 + cr.height*.45 954 + ) 1003 1003 ); 1004 - 1005 - target.style.setProperty(1006 - "box-sizing",1007 - "border-box",1008 - "important"956 + }) 957 + .sort(function(a,b){ 958 + return ( 959 + a.getBoundingClientRect().top- 960 + b.getBoundingClientRect().top 1009 1009 ); 1010 1010 }); 1011 - }); 1012 1012 1013 - return unique;964 + return rows[0]||null; 1014 1014 } 1015 1015 1016 - /* ======================================================= 1017 - OVERVIEW CARD HEIGHT + FIRST THEMATIC ROW 1018 - ======================================================= */ 967 + function firstContent(card,h){ 968 + if(!h)return null; 1019 1019 1020 - function alignOverviewCards(headers){ 1021 - if( 1022 - PAGE_KIND!=="overview"|| 1023 - window.innerWidth<=MOBILE_MAX 1024 - ){ 1025 - return; 1026 - } 970 + var cr= 971 + card.getBoundingClientRect(); 1027 1027 1028 - var cards=[];1029 - varseen=new Set();973 + var hr= 974 + h.getBoundingClientRect(); 1030 1030 1031 - headers.forEach(function(row){ 1032 - if(!seen.has(row.card)){ 1033 - seen.add(row.card); 1034 - cards.push(row.card); 1035 - } 1036 - }); 976 + var rows= 977 + Array.from( 978 + card.querySelectorAll( 979 + "p,div,ul,ol,dl,blockquote" 980 + ) 981 + ) 982 + .filter(function(el){ 983 + if( 984 + el===h|| 985 + h.contains(el)|| 986 + el.contains(h) 987 + ){ 988 + return false; 989 + } 1037 1037 1038 - if(cards.length<2){ 1039 - return; 1040 - } 991 + if(!visible(el,30,8))return false; 1041 1041 1042 - // Group cards by actual top position. 1043 - var groups=[]; 993 + var text= 994 + String(el.textContent||"") 995 + .replace(/\s+/g," ") 996 + .trim(); 1044 1044 1045 - cards.forEach(function(card){ 1046 - var top= 1047 - card.getBoundingClientRect().top; 998 + if(text.length<3)return false; 1048 1048 1049 - var group=null;1000 + var r=el.getBoundingClientRect(); 1050 1050 1051 - for(var i=0;i<groups.length;i++){ 1052 1052 if( 1053 - Math.abs( 1054 - groups[i].top-top 1055 - )<=ROW_TOLERANCE 1003 + r.top< 1004 + hr.bottom-1 1056 1056 ){ 1057 - group=groups[i]; 1058 - break; 1006 + return false; 1059 1059 } 1060 - } 1061 1061 1062 - if(!group){ 1063 - group={ 1064 - top:top, 1065 - cards:[] 1066 - }; 1067 - groups.push(group); 1068 - } 1009 + if( 1010 + r.top-cr.top> 1011 + Math.min( 1012 + 280, 1013 + cr.height*.65 1014 + ) 1015 + ){ 1016 + return false; 1017 + } 1069 1069 1070 - group.cards.push(card); 1071 - }); 1019 + if( 1020 + r.height> 1021 + cr.height*.58 1022 + ){ 1023 + return false; 1024 + } 1072 1072 1073 - groups.forEach(function(group){ 1074 - if(group.cards.length<2){ 1075 - return; 1076 - } 1026 + return true; 1027 + }) 1028 + .sort(function(a,b){ 1029 + var ar= 1030 + a.getBoundingClientRect(); 1077 1077 1078 - var firstHeaders= 1079 - group.cards.map(function(card){ 1080 - var candidates= 1081 - headers 1082 - .filter(function(row){ 1083 - return row.card===card; 1084 - }) 1085 - .sort(function(a,b){ 1086 - return ( 1087 - a.el 1088 - .getBoundingClientRect() 1089 - .top- 1090 - b.el 1091 - .getBoundingClientRect() 1092 - .top 1093 - ); 1094 - }); 1032 + var br= 1033 + b.getBoundingClientRect(); 1095 1095 1096 - return candidates.length 1097 - ?candidates[0] 1098 - :null; 1099 - }); 1035 + return ( 1036 + ar.top-br.top|| 1037 + ar.height-br.height 1038 + ); 1039 + }); 1100 1100 1101 - if( 1102 - !firstHeaders.some(function(row){ 1103 - return !row; 1104 - }) 1105 - ){ 1106 - var targetTop= 1107 - Math.max.apply( 1108 - Math, 1109 - firstHeaders.map(function(row){ 1110 - return ( 1111 - row.el 1112 - .getBoundingClientRect() 1113 - .top- 1114 - row.card 1115 - .getBoundingClientRect() 1116 - .top 1117 - ); 1118 - }) 1119 - ); 1041 + return rows[0]||null; 1042 + } 1120 1120 1121 - firstHeaders.forEach(function(row){ 1122 - var relativeTop= 1123 - row.el 1124 - .getBoundingClientRect() 1125 - .top- 1126 - row.card 1127 - .getBoundingClientRect() 1128 - .top; 1044 + function alignGeneric(cards){ 1045 + var rows= 1046 + cards.map(function(card){ 1047 + var h= 1048 + heading(card); 1129 1129 1130 - var delta= 1131 - targetTop-relativeTop; 1050 + var c= 1051 + firstContent( 1052 + card, 1053 + h 1054 + ); 1132 1132 1133 - if(delta>1){ 1134 - saveStyle( 1135 - row.el, 1136 - originalMargin, 1137 - "margin-top" 1138 - ); 1056 + if(!h||!c)return null; 1139 1139 1140 - var current= 1141 - num( 1142 - getComputedStyle( 1143 - row.el 1144 - ).marginTop 1145 - ); 1058 + var cr= 1059 + card.getBoundingClientRect(); 1146 1146 1147 - row.el.style.setProperty( 1148 - "margin-top", 1149 - ( 1150 - current+delta 1151 - )+"px" 1152 - ); 1061 + var rr= 1062 + c.getBoundingClientRect(); 1153 1153 1154 - row.el.setAttribute( 1155 - "data-sn-master-first-row", 1156 - "1" 1157 - ); 1064 + return { 1065 + content:c, 1066 + relativeTop: 1067 + rr.top-cr.top 1068 + }; 1069 + }); 1158 1158 1159 - managedMargin.add( 1160 - row.el 1161 - ); 1162 - } 1163 - }); 1164 - } 1071 + if( 1072 + rows.some(function(row){ 1073 + return !row; 1074 + }) 1075 + ){ 1076 + return false; 1077 + } 1165 1165 1166 - var maxHeight=0; 1079 + var target= 1080 + Math.max.apply( 1081 + Math, 1082 + rows.map(function(row){ 1083 + return row.relativeTop; 1084 + }) 1085 + ); 1167 1167 1168 - group.cards.forEach(function(card){ 1169 - maxHeight= 1170 - Math.max( 1171 - maxHeight, 1172 - card 1173 - .getBoundingClientRect() 1174 - .height 1175 - ); 1176 - }); 1087 + rows.forEach(function(row){ 1088 + var delta= 1089 + target- 1090 + row.relativeTop; 1177 1177 1178 - maxHeight= 1179 - Math.ceil(maxHeight); 1092 + if(delta<=1)return; 1180 1180 1181 - group.cards.forEach(function(card){ 1182 - saveStyle( 1183 - card, 1184 - originalHeight, 1185 - "min-height" 1186 - ); 1094 + saveOriginal( 1095 + row.content, 1096 + originalMarginTop, 1097 + "margin-top" 1098 + ); 1187 1187 1188 - card.style.setProperty( 1189 - "min-height", 1190 - maxHeight+"px" 1100 + var current= 1101 + num( 1102 + getComputedStyle( 1103 + row.content 1104 + ).marginTop 1191 1191 ); 1192 1192 1193 - card.setAttribute( 1194 - "data-sn-master-equal-height", 1195 - "1" 1196 - ); 1107 + row.content.style.setProperty( 1108 + "margin-top", 1109 + ( 1110 + current+ 1111 + delta 1112 + )+"px" 1113 + ); 1197 1197 1198 - managedHeight.add( 1199 - card 1200 - ); 1201 - }); 1115 + row.content.setAttribute( 1116 + "data-sn-first-content-aligned", 1117 + "7" 1118 + ); 1119 + 1120 + contentManaged.add( 1121 + row.content 1122 + ); 1202 1202 }); 1124 + 1125 + return true; 1203 1203 } 1204 1204 1205 - /* ======================================================= 1206 - DETAIL GRID EQUAL HEIGHT, DESKTOP ONLY 1207 - ======================================================= */ 1128 + function applyRow(group){ 1129 + if(!validRow(group))return false; 1208 1208 1209 - function equaliseDetailGrids(){ 1131 + var cards=[]; 1132 + var seen=new Set(); 1133 + 1134 + group.entries.forEach(function(entry){ 1135 + if(!seen.has(entry.target)){ 1136 + seen.add(entry.target); 1137 + cards.push(entry.target); 1138 + } 1139 + }); 1140 + 1141 + if(cards.length<2)return false; 1142 + 1210 1210 if( 1211 - PAGE_KIND!=="detail"|| 1212 - window.innerWidth<=MOBILE_MAX 1144 + !alignKnownBars(cards) 1213 1213 ){ 1214 - return;1146 + alignGeneric(cards); 1215 1215 } 1216 1216 1217 - var selectors=[ 1218 - ".arsn-grid", 1219 - ".arsn-grid-2", 1220 - ".arsn-grid-3", 1221 - ".dmp-grid", 1222 - ".ido-grid", 1223 - ".pp-grid" 1224 - ]; 1149 + var maxHeight=0; 1225 1225 1226 - selectors.forEach(function(selector){ 1227 - Array.from( 1228 - root.querySelectorAll(selector) 1229 - ).forEach(function(grid){ 1230 - var children= 1231 - Array.from( 1232 - grid.children||[] 1233 - ).filter(visible); 1151 + cards.forEach(function(card){ 1152 + maxHeight= 1153 + Math.max( 1154 + maxHeight, 1155 + card.getBoundingClientRect().height 1156 + ); 1157 + }); 1234 1234 1235 - if(children.length<2){ 1236 - return; 1237 - } 1159 + maxHeight= 1160 + Math.ceil( 1161 + maxHeight 1162 + ); 1238 1238 1239 - vargroups=[];1164 + if(maxHeight<MIN_H)return false; 1240 1240 1241 - children.forEach(function(child){ 1242 - var top= 1243 - child 1244 - .getBoundingClientRect() 1245 - .top; 1166 + cards.forEach(function(card){ 1167 + saveOriginal( 1168 + card, 1169 + originalMinHeight, 1170 + "min-height" 1171 + ); 1246 1246 1247 - var group=null; 1173 + card.style.setProperty( 1174 + "min-height", 1175 + maxHeight+"px" 1176 + ); 1248 1248 1249 - for(var i=0;i<groups.length;i++){ 1250 - if( 1251 - Math.abs( 1252 - groups[i].top-top 1253 - )<=ROW_TOLERANCE 1254 - ){ 1255 - group=groups[i]; 1256 - break; 1257 - } 1258 - } 1178 + card.setAttribute( 1179 + "data-sn-equal-height-managed", 1180 + "7" 1181 + ); 1259 1259 1260 - if(!group){ 1261 - group={ 1262 - top:top, 1263 - items:[] 1264 - }; 1265 - groups.push(group); 1266 - } 1183 + heightManaged.add(card); 1184 + }); 1267 1267 1268 - group.items.push(child);1269 - });1186 + return true; 1187 + } 1270 1270 1271 - groups.forEach(function(group){ 1272 - if(group.items.length<2){ 1273 - return; 1274 - } 1189 + function calculate(force){ 1190 + if(applying)return; 1275 1275 1276 - var maxHeight=0; 1192 + var width= 1193 + Math.round( 1194 + window.innerWidth 1195 + ); 1277 1277 1278 - group.items.forEach(function(item){ 1279 - maxHeight= 1280 - Math.max( 1281 - maxHeight, 1282 - item 1283 - .getBoundingClientRect() 1284 - .height 1285 - ); 1286 - }); 1197 + var meaningful= 1198 + lastWidth<0|| 1199 + Math.abs( 1200 + width- 1201 + lastWidth 1202 + )>= 1203 + MIN_WIDTH_CHANGE; 1287 1287 1288 - maxHeight= 1289 - Math.ceil(maxHeight); 1205 + if( 1206 + hasApplied&& 1207 + !force&& 1208 + !meaningful 1209 + ){ 1210 + return; 1211 + } 1290 1290 1291 - group.items.forEach(function(item){ 1292 - saveStyle( 1293 - item, 1294 - originalHeight, 1295 - "min-height" 1296 - ); 1213 + applying=true; 1297 1297 1298 - item.style.setProperty( 1299 - "min-height", 1300 - maxHeight+"px" 1301 - ); 1215 + try{ 1216 + harmoniseCustomCallouts(); 1302 1302 1303 - item.setAttribute(1304 - "data-sn-master-equal-height",1305 - "1"1306 - );1218 + if(width<=MOBILE_MAX){ 1219 + if(hasApplied){ 1220 + resetRuntime(); 1221 + } 1307 1307 1308 - managedHeight.add(item); 1309 - }); 1223 + hasApplied=false; 1224 + lastWidth=width; 1225 + return; 1226 + } 1227 + 1228 + if(hasApplied){ 1229 + resetRuntime(); 1230 + } 1231 + 1232 + var parents= 1233 + Array.from( 1234 + root.querySelectorAll("*") 1235 + ) 1236 + .filter(function(parent){ 1237 + return ( 1238 + visible( 1239 + parent, 1240 + MIN_W, 1241 + MIN_H 1242 + )&& 1243 + parent.children&& 1244 + parent.children.length>=2&& 1245 + parent.children.length<= 1246 + MAX_PARENT_CHILDREN 1247 + ); 1310 1310 }); 1311 - }); 1312 - }); 1313 - } 1314 1314 1315 - /* ======================================================= 1316 - RUN / RESPONSIVE SCHEDULING 1317 - ======================================================= */ 1250 + var touched= 1251 + new Set(); 1318 1318 1319 - function run(){1320 - if(running)return;1253 + parents.forEach(function(parent){ 1254 + var entries=[]; 1321 1321 1322 - running=true; 1256 + Array.from( 1257 + parent.children 1258 + ).forEach(function(child){ 1259 + if( 1260 + !visible( 1261 + child, 1262 + MIN_W, 1263 + MIN_H 1264 + ) 1265 + ){ 1266 + return; 1267 + } 1323 1323 1324 - try{ 1325 - resetRuntime(); 1326 - applyPlaceholderBadge(); 1327 - propagateDetailAccents(); 1269 + var target= 1270 + pickTarget(child); 1328 1328 1329 - var headers= 1330 - applyOverviewPalette(); 1272 + if(!target)return; 1331 1331 1332 - if( 1333 - window.innerWidth> 1334 - MOBILE_MAX 1335 - ){ 1336 - alignOverviewCards( 1337 - headers 1338 - ); 1274 + entries.push({ 1275 + target:target, 1276 + rect: 1277 + target.getBoundingClientRect() 1278 + }); 1279 + }); 1339 1339 1340 - equaliseDetailGrids(); 1341 - } 1281 + groupRows( 1282 + entries 1283 + ).forEach(function(group){ 1284 + if(!validRow(group))return; 1285 + 1286 + var targets= 1287 + group.entries.map(function(entry){ 1288 + return entry.target; 1289 + }); 1290 + 1291 + if( 1292 + !targets.some(function(el){ 1293 + return !touched.has(el); 1294 + }) 1295 + ){ 1296 + return; 1297 + } 1298 + 1299 + if(applyRow(group)){ 1300 + targets.forEach(function(el){ 1301 + touched.add(el); 1302 + }); 1303 + } 1304 + }); 1305 + }); 1306 + 1307 + lastWidth=width; 1308 + hasApplied=true; 1342 1342 }finally{ 1343 - running=false;1310 + applying=false; 1344 1344 } 1345 1345 } 1346 1346 1347 - function onResize(){1314 + function resize(){ 1348 1348 if(resizeTimer){ 1349 1349 clearTimeout( 1350 1350 resizeTimer ... ... @@ -1355,40 +1355,19 @@ 1355 1355 setTimeout( 1356 1356 function(){ 1357 1357 resizeTimer=0; 1358 - run();1325 + calculate(false); 1359 1359 }, 1360 1360 RESIZE_DEBOUNCE 1361 1361 ); 1362 1362 } 1363 1363 1364 - async function waitForReady(){ 1365 - if( 1366 - document.readyState!=="complete" 1367 - ){ 1368 - await new Promise(function(resolve){ 1369 - window.addEventListener( 1370 - "load", 1371 - resolve, 1372 - {once:true} 1373 - ); 1374 - }); 1375 - } 1376 - 1377 - if( 1378 - document.fonts&& 1379 - document.fonts.ready 1380 - ){ 1381 - try{ 1382 - await document.fonts.ready; 1383 - }catch(error){} 1384 - } 1385 - 1331 + function waitImages(){ 1386 1386 var images= 1387 1387 Array.from( 1388 1388 root.querySelectorAll("img") 1389 1389 ); 1390 1390 1391 - await Promise.all(1337 + return Promise.all( 1392 1392 images.map(function(img){ 1393 1393 if(img.complete){ 1394 1394 return Promise.resolve(); ... ... @@ -1413,20 +1413,46 @@ 1413 1413 }); 1414 1414 }) 1415 1415 ); 1362 + } 1416 1416 1417 - run(); 1364 + async function initial(){ 1365 + if( 1366 + document.readyState!== 1367 + "complete" 1368 + ){ 1369 + await new Promise(function(resolve){ 1370 + addEventListener( 1371 + "load", 1372 + resolve, 1373 + {once:true} 1374 + ); 1375 + }); 1376 + } 1377 + 1378 + if( 1379 + document.fonts&& 1380 + document.fonts.ready 1381 + ){ 1382 + try{ 1383 + await document.fonts.ready; 1384 + }catch(error){} 1385 + } 1386 + 1387 + await waitImages(); 1388 + 1389 + // Exactly one initial layout calculation. 1390 + calculate(true); 1418 1418 } 1419 1419 1420 - window.addEventListener(1393 + addEventListener( 1421 1421 "resize", 1422 - onResize,1395 + resize, 1423 1423 {passive:true} 1424 1424 ); 1425 1425 1426 - waitForReady();1399 + initial(); 1427 1427 })(); 1428 1428 </script> 1429 1429 1430 -<!-- SN_SERVICE_NAVIGATOR_MASTER_STYLE_END --> 1431 -{{/html}} 1432 - 1403 +<!-- SN_HORIZONTAL_BOX_HARMONIZER_END --> 1404 +{{/html}}\n