Changes for page Prepare
Last modified by Veronika Kocher on Friday, 18 Sep 2026 16:47
From version 29.10
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 29.9
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
-
... ... @@ -485,13 +485,12 @@ 485 485 </div> 486 486 {{/html}} 487 487 488 -{{html clean="false"}} 489 -<!-- SN_SERVICE_NAVIGATOR_MASTER_STYLE_START --> 488 +\n\n 489 +\n\n{{html clean="false"}} 490 +<!-- SN_HORIZONTAL_BOX_HARMONIZER_START --> 490 490 491 -<style data-sn-service-navigator-master="1"> 492 -/* ========================================================= 493 - MASTER TYPOGRAPHY 494 - ========================================================= */ 492 +<style data-sn-horizontal-box-harmonizer="7"> 493 +/* ---------- Typography: never justify headings ---------- */ 495 495 #xwikicontent h1, 496 496 #xwikicontent h2, 497 497 #xwikicontent h3, ... ... @@ -513,73 +513,88 @@ 513 513 word-spacing:normal!important; 514 514 } 515 515 516 -/* ========================================================= 517 - COMING SOON / IN VORBEREITUNG 518 - ========================================================= */ 519 -.sn-coming-soon-badge{ 520 - display:inline-block; 521 - vertical-align:middle; 522 - margin-left:10px; 523 - padding:4px 8px; 524 - border-radius:14px; 525 - border:1px solid #efd9cc; 526 - background:#fff4ee; 527 - color:#8a4d36; 528 - font-size:11px; 529 - font-weight:700; 530 - letter-spacing:.055em; 531 - line-height:1.2; 532 - white-space:nowrap; 533 -} 534 - 535 -/* ========================================================= 536 - NATIVE / DETAIL CALLOUT GEOMETRY 537 - Preserve existing backgrounds. 538 - ========================================================= */ 539 -#xwikicontent .arsn-info, 540 -#xwikicontent .dmp-info, 541 -#xwikicontent .ido-info, 542 -#xwikicontent .pp-info, 543 -#xwikicontent .infomessage{ 515 +/* ---------- Native XWiki semantic callouts ---------- */ 516 +#xwikicontent .box.infomessage, 517 +#xwikicontent .infomessage, 518 +#xwikicontent .box.warningmessage, 519 +#xwikicontent .warningmessage, 520 +#xwikicontent .box.successmessage, 521 +#xwikicontent .successmessage, 522 +#xwikicontent .box.errormessage, 523 +#xwikicontent .errormessage, 524 +#xwikicontent [data-sn-callout-harmonized="1"]{ 544 544 box-sizing:border-box!important; 545 - border-left:4px solid #21b6d7!important; 546 - border-radius:8px; 526 + border-radius:8px!important; 527 + border-top:1px solid rgba(0,0,0,.08)!important; 528 + border-right:1px solid rgba(0,0,0,.08)!important; 529 + border-bottom:1px solid rgba(0,0,0,.08)!important; 530 + border-left:4px solid var(--sn-callout-accent,#21b6d7)!important; 531 + padding:14px 16px!important; 547 547 text-align:left!important; 533 + text-justify:auto!important; 548 548 word-spacing:normal!important; 535 + box-shadow:none!important; 549 549 } 550 550 551 -#xwikicontent .arsn-warn, 552 -#xwikicontent .dmp-warn, 553 -#xwikicontent .ido-warn, 554 -#xwikicontent .pp-warn, 555 -#xwikicontent .warn, 556 -#xwikicontent .warning, 557 -#xwikicontent .warningmessage, 538 +#xwikicontent .box.infomessage, 539 +#xwikicontent .infomessage{ 540 + --sn-callout-accent:#21b6d7; 541 + background:#eaf7fb!important; 542 +} 543 + 544 +#xwikicontent .box.warningmessage, 545 +#xwikicontent .warningmessage{ 546 + --sn-callout-accent:#f0aa00; 547 + background:#fff8e7!important; 548 +} 549 + 550 +#xwikicontent .box.successmessage, 551 +#xwikicontent .successmessage{ 552 + --sn-callout-accent:#38b76a; 553 + background:#edf9f1!important; 554 +} 555 + 556 +#xwikicontent .box.errormessage, 558 558 #xwikicontent .errormessage{ 559 - box-sizing:border-box!important; 560 - border-left:4px solid #e94b13!important; 561 - border-radius:8px; 562 - text-align:left!important; 563 - word-spacing:normal!important; 558 + --sn-callout-accent:#e94b13; 559 + background:#fff1ec!important; 564 564 } 565 565 566 -[data-sn-master-equal-height], 567 -[data-sn-master-first-row]{ 562 +#xwikicontent [data-sn-callout-harmonized="1"] > :first-child, 563 +#xwikicontent .infomessage > :first-child, 564 +#xwikicontent .warningmessage > :first-child, 565 +#xwikicontent .successmessage > :first-child, 566 +#xwikicontent .errormessage > :first-child{ 567 + margin-top:0!important; 568 +} 569 + 570 +#xwikicontent [data-sn-callout-harmonized="1"] > :last-child, 571 +#xwikicontent .infomessage > :last-child, 572 +#xwikicontent .warningmessage > :last-child, 573 +#xwikicontent .successmessage > :last-child, 574 +#xwikicontent .errormessage > :last-child{ 575 + margin-bottom:0!important; 576 +} 577 + 578 +#xwikicontent [data-sn-equal-height-managed], 579 +#xwikicontent [data-sn-first-section-aligned], 580 +#xwikicontent [data-sn-first-content-aligned]{ 568 568 box-sizing:border-box; 569 569 } 570 570 </style> 571 571 572 -<script data-sn- service-navigator-master="1">585 +<script data-sn-horizontal-box-harmonizer="7"> 573 573 (function(){ 574 574 "use strict"; 575 575 576 - var PAGE_KIND="overview"; 577 - var PLACEHOLDER=false; 578 - var PLACEHOLDER_LABEL="COMING SOON"; 579 - 580 580 var MOBILE_MAX=767; 581 581 var ROW_TOLERANCE=6; 591 + var MIN_W=150; 592 + var MIN_H=36; 593 + var MAX_PARENT_CHILDREN=18; 594 + var SEARCH_DEPTH=5; 582 582 var RESIZE_DEBOUNCE=220; 596 + var MIN_WIDTH_CHANGE=2; 583 583 584 584 var root= 585 585 document.getElementById("xwikicontent")|| ... ... @@ -589,114 +589,142 @@ 589 589 590 590 if(!root)return; 591 591 592 - var managedHeight=new Set(); 593 - var managedMargin=new Set(); 594 - var originalHeight=new WeakMap(); 595 - var originalMargin=new WeakMap(); 606 + var heightManaged=new Set(); 607 + var sectionManaged=new Set(); 608 + var contentManaged=new Set(); 596 596 610 + var originalMinHeight=new WeakMap(); 611 + var originalMarginTop=new WeakMap(); 612 + 597 597 var resizeTimer=0; 598 - var running=false; 614 + var lastWidth=-1; 615 + var hasApplied=false; 616 + var applying=false; 599 599 600 - var THEMES=[ 601 - { 602 - name:"BLUE", 603 - accent:"#21b6d7", 604 - bg:"#eaf7fb", 605 - text:"#315d68", 606 - labels:[ 607 - "HIER STARTEN", 608 - "ENTSCHEIDEN", 609 - "ÜBERPRÜFEN & ANPASSEN", 610 - "START HERE", 611 - "DECIDE", 612 - "REVIEW & ADAPT" 613 - ] 614 - }, 615 - { 616 - name:"RED", 617 - accent:"#e94b13", 618 - bg:"#fff1ec", 619 - text:"#8a4d36", 620 - labels:[ 621 - "PLANEN & ORGANISIEREN", 622 - "ORGANISIEREN & DOKUMENTIEREN", 623 - "PUBLIZIEREN & PRÄSENTIEREN", 624 - "PLAN & ORGANISE", 625 - "PLAN & ORGANIZE", 626 - "ORGANISE & DOCUMENT", 627 - "ORGANIZE & DOCUMENT", 628 - "PUBLISH & PRESENT" 629 - ] 630 - }, 631 - { 632 - name:"YELLOW", 633 - accent:"#f0aa00", 634 - bg:"#fff8e7", 635 - text:"#785b17", 636 - labels:[ 637 - "SCHÜTZEN & KLÄREN", 638 - "STANDARDISIEREN & IDENTIFIZIEREN", 639 - "ÖFFNEN, NACHNUTZEN & AUFFINDBAR MACHEN", 640 - "PROTECT & CLARIFY", 641 - "STANDARDISE & IDENTIFY", 642 - "STANDARDIZE & IDENTIFY", 643 - "OPEN, REUSE & MAKE FINDABLE" 644 - ] 645 - }, 646 - { 647 - name:"GREEN", 648 - accent:"#38b76a", 649 - bg:"#edf9f1", 650 - text:"#3f7451", 651 - labels:[ 652 - "INFRASTRUKTUR EINRICHTEN", 653 - "INFRASTRUKTUR & ZUSAMMENARBEIT EINRICHTEN", 654 - "SPEICHERN & ZUGRIFF STEUERN", 655 - "REPOSITORIUM, ERHALTEN & ÜBERGEBEN", 656 - "SET UP INFRASTRUCTURE", 657 - "SET UP INFRASTRUCTURE & COLLABORATION", 658 - "STORE & CONTROL ACCESS", 659 - "REPOSITORY, PRESERVE & HAND OVER" 660 - ] 618 + function num(v){ 619 + var n=parseFloat(v); 620 + return Number.isFinite(n)?n:0; 621 + } 622 + 623 + function visible(el,minW,minH){ 624 + if(!el||el.nodeType!==1)return false; 625 + 626 + var s=getComputedStyle(el); 627 + 628 + if( 629 + s.display==="none"|| 630 + s.visibility==="hidden"|| 631 + Number(s.opacity)===0 632 + ){ 633 + return false; 661 661 } 662 - ]; 663 663 664 - function num(value){ 665 - var n=parseFloat(value); 666 - return Number.isFinite(n)?n:0; 636 + var r=el.getBoundingClientRect(); 637 + 638 + return ( 639 + r.width>=(minW||1)&& 640 + r.height>=(minH||1) 641 + ); 667 667 } 668 668 669 - function norm (value){670 - return String( value||"")644 + function normalizeText(text){ 645 + return String(text||"") 671 671 .replace(/\s+/g," ") 672 672 .trim() 673 673 .toUpperCase(); 674 674 } 675 675 676 - function visible(el){ 677 - if(!el||el.nodeType!==1)return false; 651 + function excluded(el){ 652 + return ( 653 + !el.matches|| 654 + el.matches( 655 + "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]" 656 + ) 657 + ); 658 + } 678 678 679 - var style=getComputedStyle(el); 680 - var rect=el.getBoundingClientRect(); 660 + /* ---------- Custom coloured callouts ---------- */ 681 681 662 + function nativeCallout(el){ 663 + var c= 664 + typeof el.className==="string" 665 + ? el.className.toLowerCase() 666 + : ""; 667 + 682 682 return ( 683 - style.display!=="none"&& 684 - style.visibility!=="hidden"&& 685 - rect.width>20&& 686 - rect.height>4 669 + /(^|\s)(infomessage|warningmessage|successmessage|errormessage)(\s|$)/.test(c) 687 687 ); 688 688 } 689 689 690 - function saveStyle(el,map,property){ 673 + function customCallout(el){ 674 + if(!visible(el,220,42)||excluded(el))return false; 675 + 676 + var r=el.getBoundingClientRect(); 677 + 678 + if(r.height>520)return false; 679 + 680 + var s=getComputedStyle(el); 681 + 682 + var bg= 683 + s.backgroundColor&& 684 + s.backgroundColor!=="rgba(0, 0, 0, 0)"&& 685 + s.backgroundColor!=="transparent"&& 686 + s.backgroundColor!=="rgb(255, 255, 255)"; 687 + 688 + var left= 689 + num(s.borderLeftWidth); 690 + 691 + return ( 692 + bg&& 693 + left>=2 694 + ); 695 + } 696 + 697 + function harmoniseCustomCallouts(){ 698 + Array.from( 699 + root.querySelectorAll( 700 + "div,aside,section" 701 + ) 702 + ).forEach(function(el){ 703 + if(nativeCallout(el))return; 704 + if(!customCallout(el))return; 705 + 706 + var s=getComputedStyle(el); 707 + 708 + el.setAttribute( 709 + "data-sn-callout-harmonized", 710 + "1" 711 + ); 712 + 713 + if( 714 + s.borderLeftColor 715 + ){ 716 + el.style.setProperty( 717 + "--sn-callout-accent", 718 + s.borderLeftColor 719 + ); 720 + } 721 + }); 722 + } 723 + 724 + /* ---------- Restore only values V7 itself changed ---------- */ 725 + 726 + function saveOriginal(el,map,property){ 691 691 if(map.has(el))return; 692 692 693 693 map.set(el,{ 694 - value:el.style.getPropertyValue(property), 695 - priority:el.style.getPropertyPriority(property) 730 + value: 731 + el.style.getPropertyValue( 732 + property 733 + ), 734 + priority: 735 + el.style.getPropertyPriority( 736 + property 737 + ) 696 696 }); 697 697 } 698 698 699 - function restore Style(el,map,property){741 + function restoreOriginal(el,map,property){ 700 700 var original=map.get(el); 701 701 702 702 if(original&&original.value){ ... ... @@ -706,845 +706,770 @@ 706 706 original.priority||"" 707 707 ); 708 708 }else{ 709 - el.style.removeProperty(property); 751 + el.style.removeProperty( 752 + property 753 + ); 710 710 } 711 711 } 712 712 713 713 function resetRuntime(){ 714 - managedHeight.forEach(function(el){715 - restore Style(758 + heightManaged.forEach(function(el){ 759 + restoreOriginal( 716 716 el, 717 - originalHeight, 761 + originalMinHeight, 718 718 "min-height" 719 719 ); 764 + 720 720 el.removeAttribute( 721 - "data-sn- master-equal-height"766 + "data-sn-equal-height-managed" 722 722 ); 723 723 }); 724 724 725 - managedMargin.forEach(function(el){726 - restore Style(770 + sectionManaged.forEach(function(el){ 771 + restoreOriginal( 727 727 el, 728 - originalMargin, 773 + originalMarginTop, 729 729 "margin-top" 730 730 ); 776 + 731 731 el.removeAttribute( 732 - "data-sn- master-first-row"778 + "data-sn-first-section-aligned" 733 733 ); 734 734 }); 735 735 736 - managedHeight.clear(); 737 - managedMargin.clear(); 738 - } 782 + contentManaged.forEach(function(el){ 783 + restoreOriginal( 784 + el, 785 + originalMarginTop, 786 + "margin-top" 787 + ); 739 739 740 - function themeFor(text){ 741 - var value=norm(text); 789 + el.removeAttribute( 790 + "data-sn-first-content-aligned" 791 + ); 792 + }); 742 742 743 - for(var i=0;i<THEMES.length;i++){ 744 - for(var j=0;j<THEMES[i].labels.length;j++){ 745 - var label=THEMES[i].labels[j]; 746 - 747 - if( 748 - value===label|| 749 - value.indexOf(label+" ")===0|| 750 - value.indexOf(label+" -")===0|| 751 - value.indexOf(label+" ·")===0 752 - ){ 753 - return THEMES[i]; 754 - } 755 - } 756 - } 757 - 758 - return null; 794 + heightManaged.clear(); 795 + sectionManaged.clear(); 796 + contentManaged.clear(); 759 759 } 760 760 761 - /* ======================================================= 762 - PLACEHOLDER BADGE 763 - ======================================================= */ 799 + /* ---------- Card detection ---------- */ 764 764 765 - function applyPlaceholderBadge(){ 766 - if(!PLACEHOLDER)return; 801 + function namedLikeBox(el){ 802 + var c= 803 + typeof el.className==="string" 804 + ? el.className 805 + : ""; 767 767 807 + return /(^|[\s_-])(box|card|tile|panel|role|check|service|source|call|area|detail|resource|topic|warn|info)([\s_-]|$)/i.test(c); 808 + } 809 + 810 + function boxLike(el){ 768 768 if( 769 - document.querySelector( 770 - ".sn-coming-soon-badge" 771 - ) 812 + !visible(el,MIN_W,MIN_H)|| 813 + excluded(el) 772 772 ){ 773 - return; 815 + return false; 774 774 } 775 775 776 - var title= 777 - document.querySelector( 778 - "#document-title" 779 - )|| 780 - document.querySelector( 781 - "h1" 782 - ); 818 + var s=getComputedStyle(el); 819 + var r=el.getBoundingClientRect(); 783 783 784 - if(!title)return; 821 + var border= 822 + num(s.borderTopWidth)+ 823 + num(s.borderRightWidth)+ 824 + num(s.borderBottomWidth)+ 825 + num(s.borderLeftWidth); 785 785 786 - var badge= 787 - document.createElement( 788 - "span" 789 - ); 790 - 791 - badge.className= 792 - "sn-coming-soon-badge"; 793 - 794 - badge.textContent= 795 - PLACEHOLDER_LABEL; 796 - 797 - badge.setAttribute( 798 - "aria-label", 799 - PLACEHOLDER_LABEL 827 + var radius=Math.max( 828 + num(s.borderTopLeftRadius), 829 + num(s.borderTopRightRadius), 830 + num(s.borderBottomLeftRadius), 831 + num(s.borderBottomRightRadius) 800 800 ); 801 801 802 - title.appendChild(803 - ba dge804 - ) ;805 - }834 + var bg= 835 + s.backgroundColor&& 836 + s.backgroundColor!=="rgba(0, 0, 0, 0)"&& 837 + s.backgroundColor!=="transparent"; 806 806 807 - /*=======================================================808 - DETAILPAGE OWN-ACCENT PROPAGATION809 - == ===================================================== */839 + var shadow= 840 + s.boxShadow&& 841 + s.boxShadow!=="none"; 810 810 811 - function parseRGB(value){ 812 - var match=String(value||"").match( 813 - /rgba?\(\s*([\d.]+)\s*,\s*([\d.]+)\s*,\s*([\d.]+)/i 843 + return ( 844 + namedLikeBox(el)|| 845 + border>=1|| 846 + (bg&&radius>=3)|| 847 + (shadow&&r.width>=180) 814 814 ); 815 - 816 - if(!match)return null; 817 - 818 - return [ 819 - Number(match[1]), 820 - Number(match[2]), 821 - Number(match[3]) 822 - ]; 823 823 } 824 824 825 - function distance(a,b){ 826 - return Math.sqrt( 827 - Math.pow(a[0]-b[0],2)+ 828 - Math.pow(a[1]-b[1],2)+ 829 - Math.pow(a[2]-b[2],2) 830 - ); 831 - } 851 + function pickTarget(child){ 852 + if(!visible(child,MIN_W,MIN_H))return null; 832 832 833 - function paletteMatch(cssColor){ 834 - var rgb=parseRGB(cssColor); 854 + if(boxLike(child))return child; 835 835 836 - if(!rgb)return null; 856 + var cr=child.getBoundingClientRect(); 857 + var q=[]; 837 837 838 - var palette=[ 839 - {hex:"#21b6d7",rgb:[33,182,215]}, 840 - {hex:"#e94b13",rgb:[233,75,19]}, 841 - {hex:"#f0aa00",rgb:[240,170,0]}, 842 - {hex:"#38b76a",rgb:[56,183,106]} 843 - ]; 859 + Array.from(child.children||[]).forEach(function(el){ 860 + q.push({el:el,depth:1}); 861 + }); 844 844 845 845 var best=null; 846 - var best Distance=Infinity;864 + var bestScore=-Infinity; 847 847 848 - palette.forEach(function(item){ 849 - var d=distance(rgb,item.rgb); 866 + while(q.length){ 867 + var item=q.shift(); 868 + var el=item.el; 850 850 851 - if(d<bestDistance){ 852 - best=item; 853 - bestDistance=d; 854 - } 855 - }); 870 + if(!visible(el,MIN_W,MIN_H))continue; 856 856 857 - return bestDistance<=30 858 - ?best 859 - :null; 860 - } 872 + var r=el.getBoundingClientRect(); 861 861 862 - function propagateDetailAccents(){ 863 - if(PAGE_KIND!=="detail")return; 864 - 865 - Array.from( 866 - root.querySelectorAll( 867 - ".arsn-call,.dmp-call,.ido-call,.pp-call,"+ 868 - ".arsn-source,.dmp-source,.ido-source,.pp-source" 869 - ) 870 - ).forEach(function(el){ 871 - if(!visible(el))return; 872 - 873 - var style=getComputedStyle(el); 874 - 875 875 if( 876 - num(style.borderTopWidth)>=2 875 + r.width>=cr.width*.68&& 876 + boxLike(el) 877 877 ){ 878 - var match= 879 - paletteMatch( 880 - style.borderTopColor 878 + var widthFit= 879 + 1-Math.min( 880 + 1, 881 + Math.abs(cr.width-r.width)/ 882 + Math.max(1,cr.width) 881 881 ); 882 882 883 - if(match){ 884 - el.style.setProperty( 885 - "border-left", 886 - "4px solid "+match.hex, 887 - "important" 885 + var topFit= 886 + 1-Math.min( 887 + 1, 888 + Math.abs(cr.top-r.top)/100 888 888 ); 890 + 891 + var score= 892 + widthFit*6+ 893 + topFit*3+ 894 + Math.min(r.height,900)/450+ 895 + Math.min(r.width*r.height,900000)/900000; 896 + 897 + if(score>bestScore){ 898 + best=el; 899 + bestScore=score; 889 889 } 890 890 } 891 - }); 892 892 893 - // Warning families: explicit safety override. 894 - Array.from( 895 - root.querySelectorAll( 896 - ".arsn-warn,.dmp-warn,.ido-warn,.pp-warn,"+ 897 - ".warn,.warning,.warningmessage,.errormessage" 898 - ) 899 - ).forEach(function(el){ 900 - if(!visible(el))return; 903 + if(item.depth<SEARCH_DEPTH){ 904 + Array.from(el.children||[]).forEach(function(next){ 905 + q.push({ 906 + el:next, 907 + depth:item.depth+1 908 + }); 909 + }); 910 + } 911 + } 901 901 902 - el.style.setProperty( 903 - "border-left", 904 - "4px solid #e94b13", 905 - "important" 906 - ); 907 - }); 913 + return best; 914 + } 908 908 909 - // Info families: explicit orientation override. 910 - Array.from( 911 - root.querySelectorAll( 912 - ".arsn-info,.dmp-info,.ido-info,.pp-info,.infomessage" 913 - ) 914 - ).forEach(function(el){ 915 - if(!visible(el))return; 916 + function groupRows(entries){ 917 + var groups=[]; 916 916 917 - el.style.setProperty( 918 - "border-left", 919 - "4px solid #21b6d7", 920 - "important" 921 - ); 922 - }); 923 - } 919 + entries 920 + .slice() 921 + .sort(function(a,b){ 922 + return ( 923 + a.rect.top-b.rect.top|| 924 + a.rect.left-b.rect.left 925 + ); 926 + }) 927 + .forEach(function(entry){ 928 + var group=null; 924 924 925 - /* ======================================================= 926 - OVERVIEW SEMANTIC THEME PALETTE 927 - ======================================================= */ 930 + for(var i=0;i<groups.length;i++){ 931 + if( 932 + Math.abs( 933 + groups[i].top- 934 + entry.rect.top 935 + )<=ROW_TOLERANCE 936 + ){ 937 + group=groups[i]; 938 + break; 939 + } 940 + } 928 928 929 - function smallestThemeHeaders(){ 930 - return Array.from( 931 - root.querySelectorAll( 932 - "div,span,p,strong,h3,h4,h5,h6" 933 - ) 934 - ).filter(function(el){ 935 - if(!visible(el))return false; 936 - if(!themeFor(el.textContent))return false; 942 + if(!group){ 943 + group={ 944 + top:entry.rect.top, 945 + entries:[] 946 + }; 947 + groups.push(group); 948 + } 937 937 938 - return !Array.from( 939 - el.children||[] 940 - ).some(function(child){ 941 - return !!themeFor( 942 - child.textContent 943 - ); 950 + group.entries.push(entry); 944 944 }); 945 - }); 952 + 953 + return groups; 946 946 } 947 947 948 - function findOverviewCard(header){ 949 - var node=header.parentElement; 950 - var candidates=[]; 956 + function validRow(group){ 957 + if(group.entries.length<2)return false; 951 951 952 - while(node&&node!==root){ 953 - var rect=node.getBoundingClientRect(); 954 - var style=getComputedStyle(node); 959 + var lefts= 960 + group.entries 961 + .map(function(e){return e.rect.left;}) 962 + .sort(function(a,b){return a-b;}); 955 955 956 - var border= 957 - num(style.borderTopWidth)+ 958 - num(style.borderRightWidth)+ 959 - num(style.borderBottomWidth)+ 960 - num(style.borderLeftWidth); 964 + if( 965 + lefts[lefts.length-1]- 966 + lefts[0]< 967 + 80 968 + ){ 969 + return false; 970 + } 961 961 962 - if( 963 - rect.width>=220&& 964 - rect.width<=800&& 965 - rect.height>=120&& 966 - border>=1 967 - ){ 968 - candidates.push(node); 969 - } 972 + var widths= 973 + group.entries 974 + .map(function(e){return e.rect.width;}) 975 + .filter(function(w){return w>0;}); 970 970 971 - node=node.parentElement; 972 - } 977 + if(widths.length<2)return false; 973 973 974 - if(!candidates.length)return null; 979 + var minW= 980 + Math.min.apply(Math,widths); 975 975 976 - candidates.sort(function(a,b){ 977 - return ( 978 - b.getBoundingClientRect().height- 979 - a.getBoundingClientRect().height 982 + var maxW= 983 + Math.max.apply(Math,widths); 984 + 985 + return ( 986 + maxW/ 987 + Math.max(1,minW)<= 988 + 1.9 989 + ); 990 + } 991 + 992 + /* ---------- Known ARSN first section bars ---------- */ 993 + 994 + function knownBar(el){ 995 + var text= 996 + normalizeText( 997 + el.textContent 980 980 ); 981 - }); 982 982 983 - return candidates[0]; 1000 + return ( 1001 + text==="HIER STARTEN"|| 1002 + text==="ORGANISIEREN & DOKUMENTIEREN"|| 1003 + text==="ENTSCHEIDEN"|| 1004 + text==="START HERE"|| 1005 + text==="GET STARTED"|| 1006 + text==="ORGANISE & DOCUMENT"|| 1007 + text==="ORGANIZE & DOCUMENT"|| 1008 + text==="DECIDE" 1009 + ); 984 984 } 985 985 986 - function rowCandidates(link,card){ 987 - var result=[]; 1012 + function findKnownBar(card){ 988 988 var cardRect= 989 989 card.getBoundingClientRect(); 990 990 991 - var node=link; 1016 + var rows= 1017 + Array.from( 1018 + card.querySelectorAll( 1019 + "div,p,span,strong,h3,h4,h5,h6" 1020 + ) 1021 + ) 1022 + .filter(function(el){ 1023 + if(!visible(el,20,6))return false; 1024 + if(!knownBar(el))return false; 992 992 993 - while(node&&node!==card){ 994 - if(visible(node)){ 995 - var rect= 996 - node.getBoundingClientRect(); 1026 + var r=el.getBoundingClientRect(); 997 997 998 - if( 999 - rect.height<=105&& 1000 - rect.width>= 1001 - cardRect.width*.50&& 1002 - rect.width<= 1003 - cardRect.width*1.03 1004 - ){ 1005 - result.push(node); 1006 - } 1007 - } 1028 + var rel= 1029 + r.top- 1030 + cardRect.top; 1008 1008 1009 - node=node.parentElement; 1010 - } 1011 - 1012 - return result; 1013 - } 1014 - 1015 - function chooseOuterRow( 1016 - candidates, 1017 - link 1018 - ){ 1019 - if(!candidates.length){ 1020 - return link; 1021 - } 1022 - 1023 - var bordered= 1024 - candidates.filter(function(el){ 1025 1025 return ( 1026 - num( 1027 - getComputedStyle(el) 1028 - .borderLeftWidth 1029 - )>=1 1033 + rel>=35&& 1034 + rel<= 1035 + cardRect.height*.75 1030 1030 ); 1037 + }) 1038 + .sort(function(a,b){ 1039 + return ( 1040 + a.getBoundingClientRect().top- 1041 + b.getBoundingClientRect().top 1042 + ); 1031 1031 }); 1032 1032 1033 - var pool= 1034 - bordered.length 1035 - ?bordered 1036 - :candidates; 1045 + return rows[0]||null; 1046 + } 1037 1037 1038 - pool.sort(function(a,b){ 1039 - var ar= 1040 - a.getBoundingClientRect(); 1048 + function alignKnownBars(cards){ 1049 + var rows= 1050 + cards.map(function(card){ 1051 + var bar= 1052 + findKnownBar(card); 1041 1041 1042 - var br= 1043 - b.getBoundingClientRect(); 1054 + if(!bar)return null; 1044 1044 1045 - return ( 1046 - ar.left-br.left|| 1047 - br.width-ar.width 1048 - ); 1049 - }); 1056 + var cr= 1057 + card.getBoundingClientRect(); 1050 1050 1051 - r eturnpool[0]||link;1052 - }1059 + var br= 1060 + bar.getBoundingClientRect(); 1053 1053 1054 - function applyOverviewPalette(){ 1055 - if(PAGE_KIND!=="overview"){ 1056 - return []; 1062 + return { 1063 + bar:bar, 1064 + relativeTop: 1065 + br.top- 1066 + cr.top 1067 + }; 1068 + }); 1069 + 1070 + if( 1071 + rows.some(function(row){ 1072 + return !row; 1073 + }) 1074 + ){ 1075 + return false; 1057 1057 } 1058 1058 1059 - var headers= 1060 - smallestThemeHeaders() 1061 - .map(function(el){ 1062 - return { 1063 - el:el, 1064 - theme: 1065 - themeFor( 1066 - el.textContent 1067 - ), 1068 - card: 1069 - findOverviewCard( 1070 - el 1071 - ) 1072 - }; 1078 + var target= 1079 + Math.max.apply( 1080 + Math, 1081 + rows.map(function(row){ 1082 + return row.relativeTop; 1073 1073 }) 1074 - .filter(function(row){ 1075 - return !!row.card; 1076 - }); 1084 + ); 1077 1077 1078 - var unique=[]; 1079 - var seenHeaders=new Set(); 1086 + rows.forEach(function(row){ 1087 + var delta= 1088 + target- 1089 + row.relativeTop; 1080 1080 1081 - headers.forEach(function(row){ 1082 - var key= 1083 - row.theme.name+ 1084 - "|"+ 1085 - Math.round( 1086 - row.card 1087 - .getBoundingClientRect() 1088 - .left 1089 - )+ 1090 - "|"+ 1091 - Math.round( 1092 - row.el 1093 - .getBoundingClientRect() 1094 - .top 1095 - ); 1091 + if(delta<=1)return; 1096 1096 1097 - if(!seenHeaders.has(key)){1098 - seenHeaders.add(key);1099 - unique.push(row);1100 - }1101 - });1093 + saveOriginal( 1094 + row.bar, 1095 + originalMarginTop, 1096 + "margin-top" 1097 + ); 1102 1102 1103 - unique.forEach(function(row){ 1104 - var headerRect= 1105 - row.el 1106 - .getBoundingClientRect(); 1099 + var current= 1100 + num( 1101 + getComputedStyle( 1102 + row.bar 1103 + ).marginTop 1104 + ); 1107 1107 1108 - row.el.style.setProperty( 1109 - "background", 1110 - row.theme.bg, 1111 - "important" 1106 + row.bar.style.setProperty( 1107 + "margin-top", 1108 + ( 1109 + current+ 1110 + delta 1111 + )+"px" 1112 1112 ); 1113 1113 1114 - row.el.style.setProperty( 1115 - "color", 1116 - row.theme.text, 1117 - "important" 1114 + row.bar.setAttribute( 1115 + "data-sn-first-section-aligned", 1116 + "7" 1118 1118 ); 1119 1119 1120 - row.el.style.setProperty( 1121 - "text-align", 1122 - "left", 1123 - "important" 1119 + sectionManaged.add( 1120 + row.bar 1124 1124 ); 1122 + }); 1125 1125 1126 - row.el.style.setProperty( 1127 - "word-spacing", 1128 - "normal", 1129 - "important" 1130 - ); 1124 + return true; 1125 + } 1131 1131 1132 - var later= 1133 - unique 1134 - .filter(function(other){ 1135 - return ( 1136 - other.card===row.card&& 1137 - other.el 1138 - .getBoundingClientRect() 1139 - .top> 1140 - headerRect.top+2 1141 - ); 1142 - }) 1143 - .sort(function(a,b){ 1144 - return ( 1145 - a.el 1146 - .getBoundingClientRect() 1147 - .top- 1148 - b.el 1149 - .getBoundingClientRect() 1150 - .top 1151 - ); 1152 - }); 1127 + /* ---------- Generic first content after heading ---------- */ 1153 1153 1154 - var stopTop= 1155 - later.length 1156 - ?later[0].el 1157 - .getBoundingClientRect() 1158 - .top 1159 - :Infinity; 1129 + function heading(card){ 1130 + var cr= 1131 + card.getBoundingClientRect(); 1160 1160 1133 + var rows= 1161 1161 Array.from( 1162 - row.card.querySelectorAll("a") 1163 - ).forEach(function(link){ 1164 - if(!visible(link))return; 1135 + card.querySelectorAll( 1136 + "h1,h2,h3,h4,h5,h6,.box-title,[role=heading]" 1137 + ) 1138 + ) 1139 + .filter(function(el){ 1140 + if(!visible(el,20,8))return false; 1165 1165 1166 - var rect= 1167 - link.getBoundingClientRect(); 1142 + var r=el.getBoundingClientRect(); 1168 1168 1169 - if( 1170 - rect.top<= 1171 - headerRect.bottom-2|| 1172 - rect.top>= 1173 - stopTop-2 1174 - ){ 1175 - return; 1176 - } 1144 + var rel= 1145 + r.top- 1146 + cr.top; 1177 1177 1178 - var candidates= 1179 - rowCandidates( 1180 - link, 1181 - row.card 1182 - ); 1183 - 1184 - var target= 1185 - chooseOuterRow( 1186 - candidates, 1187 - link 1188 - ); 1189 - 1190 - candidates.forEach(function(el){ 1191 - el.style.setProperty( 1192 - "border-left", 1193 - "0 solid transparent", 1194 - "important" 1195 - ); 1196 - }); 1197 - 1198 - target.style.setProperty( 1199 - "border-left", 1200 - "3px solid "+ 1201 - row.theme.accent, 1202 - "important" 1148 + return ( 1149 + rel>=0&& 1150 + rel<= 1151 + Math.min( 1152 + 160, 1153 + cr.height*.45 1154 + ) 1203 1203 ); 1204 - 1205 - target.style.setProperty(1206 - "box-sizing",1207 - "border-box",1208 - "important"1156 + }) 1157 + .sort(function(a,b){ 1158 + return ( 1159 + a.getBoundingClientRect().top- 1160 + b.getBoundingClientRect().top 1209 1209 ); 1210 1210 }); 1211 - }); 1212 1212 1213 - return unique;1164 + return rows[0]||null; 1214 1214 } 1215 1215 1216 - /* ======================================================= 1217 - OVERVIEW CARD HEIGHT + FIRST THEMATIC ROW 1218 - ======================================================= */ 1167 + function firstContent(card,h){ 1168 + if(!h)return null; 1219 1219 1220 - function alignOverviewCards(headers){ 1221 - if( 1222 - PAGE_KIND!=="overview"|| 1223 - window.innerWidth<=MOBILE_MAX 1224 - ){ 1225 - return; 1226 - } 1170 + var cr= 1171 + card.getBoundingClientRect(); 1227 1227 1228 - var cards=[];1229 - varseen=new Set();1173 + var hr= 1174 + h.getBoundingClientRect(); 1230 1230 1231 - headers.forEach(function(row){ 1232 - if(!seen.has(row.card)){ 1233 - seen.add(row.card); 1234 - cards.push(row.card); 1235 - } 1236 - }); 1176 + var rows= 1177 + Array.from( 1178 + card.querySelectorAll( 1179 + "p,div,ul,ol,dl,blockquote" 1180 + ) 1181 + ) 1182 + .filter(function(el){ 1183 + if( 1184 + el===h|| 1185 + h.contains(el)|| 1186 + el.contains(h) 1187 + ){ 1188 + return false; 1189 + } 1237 1237 1238 - if(cards.length<2){ 1239 - return; 1240 - } 1191 + if(!visible(el,30,8))return false; 1241 1241 1242 - // Group cards by actual top position. 1243 - var groups=[]; 1193 + var text= 1194 + String(el.textContent||"") 1195 + .replace(/\s+/g," ") 1196 + .trim(); 1244 1244 1245 - cards.forEach(function(card){ 1246 - var top= 1247 - card.getBoundingClientRect().top; 1198 + if(text.length<3)return false; 1248 1248 1249 - var group=null;1200 + var r=el.getBoundingClientRect(); 1250 1250 1251 - for(var i=0;i<groups.length;i++){ 1252 1252 if( 1253 - Math.abs( 1254 - groups[i].top-top 1255 - )<=ROW_TOLERANCE 1203 + r.top< 1204 + hr.bottom-1 1256 1256 ){ 1257 - group=groups[i]; 1258 - break; 1206 + return false; 1259 1259 } 1260 - } 1261 1261 1262 - if(!group){ 1263 - group={ 1264 - top:top, 1265 - cards:[] 1266 - }; 1267 - groups.push(group); 1268 - } 1209 + if( 1210 + r.top-cr.top> 1211 + Math.min( 1212 + 280, 1213 + cr.height*.65 1214 + ) 1215 + ){ 1216 + return false; 1217 + } 1269 1269 1270 - group.cards.push(card); 1271 - }); 1219 + if( 1220 + r.height> 1221 + cr.height*.58 1222 + ){ 1223 + return false; 1224 + } 1272 1272 1273 - groups.forEach(function(group){ 1274 - if(group.cards.length<2){ 1275 - return; 1276 - } 1226 + return true; 1227 + }) 1228 + .sort(function(a,b){ 1229 + var ar= 1230 + a.getBoundingClientRect(); 1277 1277 1278 - var firstHeaders= 1279 - group.cards.map(function(card){ 1280 - var candidates= 1281 - headers 1282 - .filter(function(row){ 1283 - return row.card===card; 1284 - }) 1285 - .sort(function(a,b){ 1286 - return ( 1287 - a.el 1288 - .getBoundingClientRect() 1289 - .top- 1290 - b.el 1291 - .getBoundingClientRect() 1292 - .top 1293 - ); 1294 - }); 1232 + var br= 1233 + b.getBoundingClientRect(); 1295 1295 1296 - return candidates.length 1297 - ?candidates[0] 1298 - :null; 1299 - }); 1235 + return ( 1236 + ar.top-br.top|| 1237 + ar.height-br.height 1238 + ); 1239 + }); 1300 1300 1301 - if( 1302 - !firstHeaders.some(function(row){ 1303 - return !row; 1304 - }) 1305 - ){ 1306 - var targetTop= 1307 - Math.max.apply( 1308 - Math, 1309 - firstHeaders.map(function(row){ 1310 - return ( 1311 - row.el 1312 - .getBoundingClientRect() 1313 - .top- 1314 - row.card 1315 - .getBoundingClientRect() 1316 - .top 1317 - ); 1318 - }) 1319 - ); 1241 + return rows[0]||null; 1242 + } 1320 1320 1321 - firstHeaders.forEach(function(row){ 1322 - var relativeTop= 1323 - row.el 1324 - .getBoundingClientRect() 1325 - .top- 1326 - row.card 1327 - .getBoundingClientRect() 1328 - .top; 1244 + function alignGeneric(cards){ 1245 + var rows= 1246 + cards.map(function(card){ 1247 + var h= 1248 + heading(card); 1329 1329 1330 - var delta= 1331 - targetTop-relativeTop; 1250 + var c= 1251 + firstContent( 1252 + card, 1253 + h 1254 + ); 1332 1332 1333 - if(delta>1){ 1334 - saveStyle( 1335 - row.el, 1336 - originalMargin, 1337 - "margin-top" 1338 - ); 1256 + if(!h||!c)return null; 1339 1339 1340 - var current= 1341 - num( 1342 - getComputedStyle( 1343 - row.el 1344 - ).marginTop 1345 - ); 1258 + var cr= 1259 + card.getBoundingClientRect(); 1346 1346 1347 - row.el.style.setProperty( 1348 - "margin-top", 1349 - ( 1350 - current+delta 1351 - )+"px" 1352 - ); 1261 + var rr= 1262 + c.getBoundingClientRect(); 1353 1353 1354 - row.el.setAttribute( 1355 - "data-sn-master-first-row", 1356 - "1" 1357 - ); 1264 + return { 1265 + content:c, 1266 + relativeTop: 1267 + rr.top-cr.top 1268 + }; 1269 + }); 1358 1358 1359 - managedMargin.add( 1360 - row.el 1361 - ); 1362 - } 1363 - }); 1364 - } 1271 + if( 1272 + rows.some(function(row){ 1273 + return !row; 1274 + }) 1275 + ){ 1276 + return false; 1277 + } 1365 1365 1366 - var maxHeight=0; 1279 + var target= 1280 + Math.max.apply( 1281 + Math, 1282 + rows.map(function(row){ 1283 + return row.relativeTop; 1284 + }) 1285 + ); 1367 1367 1368 - group.cards.forEach(function(card){ 1369 - maxHeight= 1370 - Math.max( 1371 - maxHeight, 1372 - card 1373 - .getBoundingClientRect() 1374 - .height 1375 - ); 1376 - }); 1287 + rows.forEach(function(row){ 1288 + var delta= 1289 + target- 1290 + row.relativeTop; 1377 1377 1378 - maxHeight= 1379 - Math.ceil(maxHeight); 1292 + if(delta<=1)return; 1380 1380 1381 - group.cards.forEach(function(card){ 1382 - saveStyle( 1383 - card, 1384 - originalHeight, 1385 - "min-height" 1386 - ); 1294 + saveOriginal( 1295 + row.content, 1296 + originalMarginTop, 1297 + "margin-top" 1298 + ); 1387 1387 1388 - card.style.setProperty( 1389 - "min-height", 1390 - maxHeight+"px" 1300 + var current= 1301 + num( 1302 + getComputedStyle( 1303 + row.content 1304 + ).marginTop 1391 1391 ); 1392 1392 1393 - card.setAttribute( 1394 - "data-sn-master-equal-height", 1395 - "1" 1396 - ); 1307 + row.content.style.setProperty( 1308 + "margin-top", 1309 + ( 1310 + current+ 1311 + delta 1312 + )+"px" 1313 + ); 1397 1397 1398 - managedHeight.add( 1399 - card 1400 - ); 1401 - }); 1315 + row.content.setAttribute( 1316 + "data-sn-first-content-aligned", 1317 + "7" 1318 + ); 1319 + 1320 + contentManaged.add( 1321 + row.content 1322 + ); 1402 1402 }); 1324 + 1325 + return true; 1403 1403 } 1404 1404 1405 - /* ======================================================= 1406 - DETAIL GRID EQUAL HEIGHT, DESKTOP ONLY 1407 - ======================================================= */ 1328 + function applyRow(group){ 1329 + if(!validRow(group))return false; 1408 1408 1409 - function equaliseDetailGrids(){ 1331 + var cards=[]; 1332 + var seen=new Set(); 1333 + 1334 + group.entries.forEach(function(entry){ 1335 + if(!seen.has(entry.target)){ 1336 + seen.add(entry.target); 1337 + cards.push(entry.target); 1338 + } 1339 + }); 1340 + 1341 + if(cards.length<2)return false; 1342 + 1410 1410 if( 1411 - PAGE_KIND!=="detail"|| 1412 - window.innerWidth<=MOBILE_MAX 1344 + !alignKnownBars(cards) 1413 1413 ){ 1414 - return;1346 + alignGeneric(cards); 1415 1415 } 1416 1416 1417 - var selectors=[ 1418 - ".arsn-grid", 1419 - ".arsn-grid-2", 1420 - ".arsn-grid-3", 1421 - ".dmp-grid", 1422 - ".ido-grid", 1423 - ".pp-grid" 1424 - ]; 1349 + var maxHeight=0; 1425 1425 1426 - selectors.forEach(function(selector){ 1427 - Array.from( 1428 - root.querySelectorAll(selector) 1429 - ).forEach(function(grid){ 1430 - var children= 1431 - Array.from( 1432 - grid.children||[] 1433 - ).filter(visible); 1351 + cards.forEach(function(card){ 1352 + maxHeight= 1353 + Math.max( 1354 + maxHeight, 1355 + card.getBoundingClientRect().height 1356 + ); 1357 + }); 1434 1434 1435 - if(children.length<2){ 1436 - return; 1437 - } 1359 + maxHeight= 1360 + Math.ceil( 1361 + maxHeight 1362 + ); 1438 1438 1439 - vargroups=[];1364 + if(maxHeight<MIN_H)return false; 1440 1440 1441 - children.forEach(function(child){ 1442 - var top= 1443 - child 1444 - .getBoundingClientRect() 1445 - .top; 1366 + cards.forEach(function(card){ 1367 + saveOriginal( 1368 + card, 1369 + originalMinHeight, 1370 + "min-height" 1371 + ); 1446 1446 1447 - var group=null; 1373 + card.style.setProperty( 1374 + "min-height", 1375 + maxHeight+"px" 1376 + ); 1448 1448 1449 - for(var i=0;i<groups.length;i++){ 1450 - if( 1451 - Math.abs( 1452 - groups[i].top-top 1453 - )<=ROW_TOLERANCE 1454 - ){ 1455 - group=groups[i]; 1456 - break; 1457 - } 1458 - } 1378 + card.setAttribute( 1379 + "data-sn-equal-height-managed", 1380 + "7" 1381 + ); 1459 1459 1460 - if(!group){ 1461 - group={ 1462 - top:top, 1463 - items:[] 1464 - }; 1465 - groups.push(group); 1466 - } 1383 + heightManaged.add(card); 1384 + }); 1467 1467 1468 - group.items.push(child);1469 - });1386 + return true; 1387 + } 1470 1470 1471 - groups.forEach(function(group){ 1472 - if(group.items.length<2){ 1473 - return; 1474 - } 1389 + function calculate(force){ 1390 + if(applying)return; 1475 1475 1476 - var maxHeight=0; 1392 + var width= 1393 + Math.round( 1394 + window.innerWidth 1395 + ); 1477 1477 1478 - group.items.forEach(function(item){ 1479 - maxHeight= 1480 - Math.max( 1481 - maxHeight, 1482 - item 1483 - .getBoundingClientRect() 1484 - .height 1485 - ); 1486 - }); 1397 + var meaningful= 1398 + lastWidth<0|| 1399 + Math.abs( 1400 + width- 1401 + lastWidth 1402 + )>= 1403 + MIN_WIDTH_CHANGE; 1487 1487 1488 - maxHeight= 1489 - Math.ceil(maxHeight); 1405 + if( 1406 + hasApplied&& 1407 + !force&& 1408 + !meaningful 1409 + ){ 1410 + return; 1411 + } 1490 1490 1491 - group.items.forEach(function(item){ 1492 - saveStyle( 1493 - item, 1494 - originalHeight, 1495 - "min-height" 1496 - ); 1413 + applying=true; 1497 1497 1498 - item.style.setProperty( 1499 - "min-height", 1500 - maxHeight+"px" 1501 - ); 1415 + try{ 1416 + harmoniseCustomCallouts(); 1502 1502 1503 - item.setAttribute(1504 - "data-sn-master-equal-height",1505 - "1"1506 - );1418 + if(width<=MOBILE_MAX){ 1419 + if(hasApplied){ 1420 + resetRuntime(); 1421 + } 1507 1507 1508 - managedHeight.add(item); 1509 - }); 1423 + hasApplied=false; 1424 + lastWidth=width; 1425 + return; 1426 + } 1427 + 1428 + if(hasApplied){ 1429 + resetRuntime(); 1430 + } 1431 + 1432 + var parents= 1433 + Array.from( 1434 + root.querySelectorAll("*") 1435 + ) 1436 + .filter(function(parent){ 1437 + return ( 1438 + visible( 1439 + parent, 1440 + MIN_W, 1441 + MIN_H 1442 + )&& 1443 + parent.children&& 1444 + parent.children.length>=2&& 1445 + parent.children.length<= 1446 + MAX_PARENT_CHILDREN 1447 + ); 1510 1510 }); 1511 - }); 1512 - }); 1513 - } 1514 1514 1515 - /* ======================================================= 1516 - RUN / RESPONSIVE SCHEDULING 1517 - ======================================================= */ 1450 + var touched= 1451 + new Set(); 1518 1518 1519 - function run(){1520 - if(running)return;1453 + parents.forEach(function(parent){ 1454 + var entries=[]; 1521 1521 1522 - running=true; 1456 + Array.from( 1457 + parent.children 1458 + ).forEach(function(child){ 1459 + if( 1460 + !visible( 1461 + child, 1462 + MIN_W, 1463 + MIN_H 1464 + ) 1465 + ){ 1466 + return; 1467 + } 1523 1523 1524 - try{ 1525 - resetRuntime(); 1526 - applyPlaceholderBadge(); 1527 - propagateDetailAccents(); 1469 + var target= 1470 + pickTarget(child); 1528 1528 1529 - var headers= 1530 - applyOverviewPalette(); 1472 + if(!target)return; 1531 1531 1532 - if( 1533 - window.innerWidth> 1534 - MOBILE_MAX 1535 - ){ 1536 - alignOverviewCards( 1537 - headers 1538 - ); 1474 + entries.push({ 1475 + target:target, 1476 + rect: 1477 + target.getBoundingClientRect() 1478 + }); 1479 + }); 1539 1539 1540 - equaliseDetailGrids(); 1541 - } 1481 + groupRows( 1482 + entries 1483 + ).forEach(function(group){ 1484 + if(!validRow(group))return; 1485 + 1486 + var targets= 1487 + group.entries.map(function(entry){ 1488 + return entry.target; 1489 + }); 1490 + 1491 + if( 1492 + !targets.some(function(el){ 1493 + return !touched.has(el); 1494 + }) 1495 + ){ 1496 + return; 1497 + } 1498 + 1499 + if(applyRow(group)){ 1500 + targets.forEach(function(el){ 1501 + touched.add(el); 1502 + }); 1503 + } 1504 + }); 1505 + }); 1506 + 1507 + lastWidth=width; 1508 + hasApplied=true; 1542 1542 }finally{ 1543 - running=false;1510 + applying=false; 1544 1544 } 1545 1545 } 1546 1546 1547 - function onResize(){1514 + function resize(){ 1548 1548 if(resizeTimer){ 1549 1549 clearTimeout( 1550 1550 resizeTimer ... ... @@ -1555,40 +1555,19 @@ 1555 1555 setTimeout( 1556 1556 function(){ 1557 1557 resizeTimer=0; 1558 - run();1525 + calculate(false); 1559 1559 }, 1560 1560 RESIZE_DEBOUNCE 1561 1561 ); 1562 1562 } 1563 1563 1564 - async function waitForReady(){ 1565 - if( 1566 - document.readyState!=="complete" 1567 - ){ 1568 - await new Promise(function(resolve){ 1569 - window.addEventListener( 1570 - "load", 1571 - resolve, 1572 - {once:true} 1573 - ); 1574 - }); 1575 - } 1576 - 1577 - if( 1578 - document.fonts&& 1579 - document.fonts.ready 1580 - ){ 1581 - try{ 1582 - await document.fonts.ready; 1583 - }catch(error){} 1584 - } 1585 - 1531 + function waitImages(){ 1586 1586 var images= 1587 1587 Array.from( 1588 1588 root.querySelectorAll("img") 1589 1589 ); 1590 1590 1591 - await Promise.all(1537 + return Promise.all( 1592 1592 images.map(function(img){ 1593 1593 if(img.complete){ 1594 1594 return Promise.resolve(); ... ... @@ -1613,20 +1613,46 @@ 1613 1613 }); 1614 1614 }) 1615 1615 ); 1562 + } 1616 1616 1617 - run(); 1564 + async function initial(){ 1565 + if( 1566 + document.readyState!== 1567 + "complete" 1568 + ){ 1569 + await new Promise(function(resolve){ 1570 + addEventListener( 1571 + "load", 1572 + resolve, 1573 + {once:true} 1574 + ); 1575 + }); 1576 + } 1577 + 1578 + if( 1579 + document.fonts&& 1580 + document.fonts.ready 1581 + ){ 1582 + try{ 1583 + await document.fonts.ready; 1584 + }catch(error){} 1585 + } 1586 + 1587 + await waitImages(); 1588 + 1589 + // Exactly one initial layout calculation. 1590 + calculate(true); 1618 1618 } 1619 1619 1620 - window.addEventListener(1593 + addEventListener( 1621 1621 "resize", 1622 - onResize,1595 + resize, 1623 1623 {passive:true} 1624 1624 ); 1625 1625 1626 - waitForReady();1599 + initial(); 1627 1627 })(); 1628 1628 </script> 1629 1629 1630 -<!-- SN_SERVICE_NAVIGATOR_MASTER_STYLE_END --> 1631 -{{/html}} 1632 - 1603 +<!-- SN_HORIZONTAL_BOX_HARMONIZER_END --> 1604 +{{/html}}\n