Änderungen von Dokument Prepare
Zuletzt geändert von Veronika Kocher am Freitag, 18 Sep. 2026 16:47
Von Version 1.7
bearbeitet von Veronika Kocher
am Donnerstag, 03 Sep. 2026 9:34
am Donnerstag, 03 Sep. 2026 9:34
Änderungskommentar:
Es gibt keinen Kommentar für diese Version
Auf Version 1.8
bearbeitet von Veronika Kocher
am Donnerstag, 03 Sep. 2026 10:09
am Donnerstag, 03 Sep. 2026 10:09
Änderungskommentar:
Es gibt keinen Kommentar für diese Version
Zusammenfassung
-
Seiteneigenschaften (1 geändert, 0 hinzugefügt, 0 gelöscht)
Details
- Seiteneigenschaften
-
- Inhalt
-
... ... @@ -483,15 +483,104 @@ 483 483 </div> 484 484 {{/html}} 485 485 486 -{{html clean="false"}} 486 +\n\n 487 +\n\n{{html clean="false"}} 487 487 <!-- SN_HORIZONTAL_BOX_HARMONIZER_START --> 488 -<style data-sn-horizontal-box-harmonizer="4"> 489 -[data-sn-equal-height-managed], 490 -[data-sn-first-section-aligned]{ 489 + 490 +<style data-sn-horizontal-box-harmonizer="7"> 491 +/* ---------- Typography: never justify headings ---------- */ 492 +#xwikicontent h1, 493 +#xwikicontent h2, 494 +#xwikicontent h3, 495 +#xwikicontent h4, 496 +#xwikicontent h5, 497 +#xwikicontent h6, 498 +#xwikicontent .box-title, 499 +#xwikicontent [role="heading"], 500 +#xwikicontent h1 a, 501 +#xwikicontent h2 a, 502 +#xwikicontent h3 a, 503 +#xwikicontent h4 a, 504 +#xwikicontent h5 a, 505 +#xwikicontent h6 a, 506 +#xwikicontent .box-title a, 507 +#xwikicontent [role="heading"] a{ 508 + text-align:left!important; 509 + text-justify:auto!important; 510 + word-spacing:normal!important; 511 +} 512 + 513 +/* ---------- Native XWiki semantic callouts ---------- */ 514 +#xwikicontent .box.infomessage, 515 +#xwikicontent .infomessage, 516 +#xwikicontent .box.warningmessage, 517 +#xwikicontent .warningmessage, 518 +#xwikicontent .box.successmessage, 519 +#xwikicontent .successmessage, 520 +#xwikicontent .box.errormessage, 521 +#xwikicontent .errormessage, 522 +#xwikicontent [data-sn-callout-harmonized="1"]{ 523 + box-sizing:border-box!important; 524 + border-radius:8px!important; 525 + border-top:1px solid rgba(0,0,0,.08)!important; 526 + border-right:1px solid rgba(0,0,0,.08)!important; 527 + border-bottom:1px solid rgba(0,0,0,.08)!important; 528 + border-left:4px solid var(--sn-callout-accent,#21b6d7)!important; 529 + padding:14px 16px!important; 530 + text-align:left!important; 531 + text-justify:auto!important; 532 + word-spacing:normal!important; 533 + box-shadow:none!important; 534 +} 535 + 536 +#xwikicontent .box.infomessage, 537 +#xwikicontent .infomessage{ 538 + --sn-callout-accent:#21b6d7; 539 + background:#eaf7fb!important; 540 +} 541 + 542 +#xwikicontent .box.warningmessage, 543 +#xwikicontent .warningmessage{ 544 + --sn-callout-accent:#f0aa00; 545 + background:#fff8e7!important; 546 +} 547 + 548 +#xwikicontent .box.successmessage, 549 +#xwikicontent .successmessage{ 550 + --sn-callout-accent:#38b76a; 551 + background:#edf9f1!important; 552 +} 553 + 554 +#xwikicontent .box.errormessage, 555 +#xwikicontent .errormessage{ 556 + --sn-callout-accent:#e94b13; 557 + background:#fff1ec!important; 558 +} 559 + 560 +#xwikicontent [data-sn-callout-harmonized="1"] > :first-child, 561 +#xwikicontent .infomessage > :first-child, 562 +#xwikicontent .warningmessage > :first-child, 563 +#xwikicontent .successmessage > :first-child, 564 +#xwikicontent .errormessage > :first-child{ 565 + margin-top:0!important; 566 +} 567 + 568 +#xwikicontent [data-sn-callout-harmonized="1"] > :last-child, 569 +#xwikicontent .infomessage > :last-child, 570 +#xwikicontent .warningmessage > :last-child, 571 +#xwikicontent .successmessage > :last-child, 572 +#xwikicontent .errormessage > :last-child{ 573 + margin-bottom:0!important; 574 +} 575 + 576 +#xwikicontent [data-sn-equal-height-managed], 577 +#xwikicontent [data-sn-first-section-aligned], 578 +#xwikicontent [data-sn-first-content-aligned]{ 491 491 box-sizing:border-box; 492 492 } 493 493 </style> 494 -<script data-sn-horizontal-box-harmonizer="4"> 582 + 583 +<script data-sn-horizontal-box-harmonizer="7"> 495 495 (function(){ 496 496 "use strict"; 497 497 ... ... @@ -499,8 +499,10 @@ 499 499 var ROW_TOLERANCE=6; 500 500 var MIN_W=150; 501 501 var MIN_H=36; 502 - var MAX_PARENT_CHILDREN=1 6;591 + var MAX_PARENT_CHILDREN=18; 503 503 var SEARCH_DEPTH=5; 593 + var RESIZE_DEBOUNCE=220; 594 + var MIN_WIDTH_CHANGE=2; 504 504 505 505 var root= 506 506 document.getElementById("xwikicontent")|| ... ... @@ -512,10 +512,16 @@ 512 512 513 513 var heightManaged=new Set(); 514 514 var sectionManaged=new Set(); 606 + var contentManaged=new Set(); 607 + 515 515 var originalMinHeight=new WeakMap(); 516 516 var originalMarginTop=new WeakMap(); 517 - var raf=0; 518 518 611 + var resizeTimer=0; 612 + var lastWidth=-1; 613 + var hasApplied=false; 614 + var applying=false; 615 + 519 519 function num(v){ 520 520 var n=parseFloat(v); 521 521 return Number.isFinite(n)?n:0; ... ... @@ -542,6 +542,13 @@ 542 542 ); 543 543 } 544 544 642 + function normalizeText(text){ 643 + return String(text||"") 644 + .replace(/\s+/g," ") 645 + .trim() 646 + .toUpperCase(); 647 + } 648 + 545 545 function excluded(el){ 546 546 return ( 547 547 !el.matches|| ... ... @@ -551,57 +551,84 @@ 551 551 ); 552 552 } 553 553 554 - function namedLikeBox(el){ 658 + /* ---------- Custom coloured callouts ---------- */ 659 + 660 + function nativeCallout(el){ 555 555 var c= 556 556 typeof el.className==="string" 557 - ? el.className 663 + ? el.className.toLowerCase() 558 558 : ""; 559 559 560 - return /(^|[s_-])(box|card|tile|panel|role|check|service|source|call|area|detail|resource|topic|warn|info)([s_-]|$)/i.test(c); 666 + return ( 667 + /(^|\s)(infomessage|warningmessage|successmessage|errormessage)(\s|$)/.test(c) 668 + ); 561 561 } 562 562 563 - function boxLike(el){564 - if(!visible(el, MIN_W,MIN_H)||excluded(el))return false;671 + function customCallout(el){ 672 + if(!visible(el,220,42)||excluded(el))return false; 565 565 566 - var s=getComputedStyle(el); 567 567 var r=el.getBoundingClientRect(); 568 568 569 - var border= 570 - num(s.borderTopWidth)+ 571 - num(s.borderRightWidth)+ 572 - num(s.borderBottomWidth)+ 573 - num(s.borderLeftWidth); 676 + if(r.height>520)return false; 574 574 575 - var radius=Math.max( 576 - num(s.borderTopLeftRadius), 577 - num(s.borderTopRightRadius), 578 - num(s.borderBottomLeftRadius), 579 - num(s.borderBottomRightRadius) 580 - ); 678 + var s=getComputedStyle(el); 581 581 582 582 var bg= 583 583 s.backgroundColor&& 584 584 s.backgroundColor!=="rgba(0, 0, 0, 0)"&& 585 - s.backgroundColor!=="transparent"; 683 + s.backgroundColor!=="transparent"&& 684 + s.backgroundColor!=="rgb(255, 255, 255)"; 586 586 587 - var shadow= 588 - s.boxShadow&& 589 - s.boxShadow!=="none"; 686 + var left= 687 + num(s.borderLeftWidth); 590 590 591 591 return ( 592 - namedLikeBox(el)|| 593 - border>=1|| 594 - (bg&&radius>=3)|| 595 - (shadow&&r.width>=180) 690 + bg&& 691 + left>=2 596 596 ); 597 597 } 598 598 695 + function harmoniseCustomCallouts(){ 696 + Array.from( 697 + root.querySelectorAll( 698 + "div,aside,section" 699 + ) 700 + ).forEach(function(el){ 701 + if(nativeCallout(el))return; 702 + if(!customCallout(el))return; 703 + 704 + var s=getComputedStyle(el); 705 + 706 + el.setAttribute( 707 + "data-sn-callout-harmonized", 708 + "1" 709 + ); 710 + 711 + if( 712 + s.borderLeftColor 713 + ){ 714 + el.style.setProperty( 715 + "--sn-callout-accent", 716 + s.borderLeftColor 717 + ); 718 + } 719 + }); 720 + } 721 + 722 + /* ---------- Restore only values V7 itself changed ---------- */ 723 + 599 599 function saveOriginal(el,map,property){ 600 600 if(map.has(el))return; 601 601 602 602 map.set(el,{ 603 - value:el.style.getPropertyValue(property), 604 - priority:el.style.getPropertyPriority(property) 728 + value: 729 + el.style.getPropertyValue( 730 + property 731 + ), 732 + priority: 733 + el.style.getPropertyPriority( 734 + property 735 + ) 605 605 }); 606 606 } 607 607 ... ... @@ -615,11 +615,13 @@ 615 615 original.priority||"" 616 616 ); 617 617 }else{ 618 - el.style.removeProperty(property); 749 + el.style.removeProperty( 750 + property 751 + ); 619 619 } 620 620 } 621 621 622 - function reset(){ 755 + function resetRuntime(){ 623 623 heightManaged.forEach(function(el){ 624 624 restoreOriginal( 625 625 el, ... ... @@ -644,16 +644,79 @@ 644 644 ); 645 645 }); 646 646 780 + contentManaged.forEach(function(el){ 781 + restoreOriginal( 782 + el, 783 + originalMarginTop, 784 + "margin-top" 785 + ); 786 + 787 + el.removeAttribute( 788 + "data-sn-first-content-aligned" 789 + ); 790 + }); 791 + 647 647 heightManaged.clear(); 648 648 sectionManaged.clear(); 794 + contentManaged.clear(); 649 649 } 650 650 797 + /* ---------- Card detection ---------- */ 798 + 799 + function namedLikeBox(el){ 800 + var c= 801 + typeof el.className==="string" 802 + ? el.className 803 + : ""; 804 + 805 + return /(^|[\s_-])(box|card|tile|panel|role|check|service|source|call|area|detail|resource|topic|warn|info)([\s_-]|$)/i.test(c); 806 + } 807 + 808 + function boxLike(el){ 809 + if( 810 + !visible(el,MIN_W,MIN_H)|| 811 + excluded(el) 812 + ){ 813 + return false; 814 + } 815 + 816 + var s=getComputedStyle(el); 817 + var r=el.getBoundingClientRect(); 818 + 819 + var border= 820 + num(s.borderTopWidth)+ 821 + num(s.borderRightWidth)+ 822 + num(s.borderBottomWidth)+ 823 + num(s.borderLeftWidth); 824 + 825 + var radius=Math.max( 826 + num(s.borderTopLeftRadius), 827 + num(s.borderTopRightRadius), 828 + num(s.borderBottomLeftRadius), 829 + num(s.borderBottomRightRadius) 830 + ); 831 + 832 + var bg= 833 + s.backgroundColor&& 834 + s.backgroundColor!=="rgba(0, 0, 0, 0)"&& 835 + s.backgroundColor!=="transparent"; 836 + 837 + var shadow= 838 + s.boxShadow&& 839 + s.boxShadow!=="none"; 840 + 841 + return ( 842 + namedLikeBox(el)|| 843 + border>=1|| 844 + (bg&&radius>=3)|| 845 + (shadow&&r.width>=180) 846 + ); 847 + } 848 + 651 651 function pickTarget(child){ 652 652 if(!visible(child,MIN_W,MIN_H))return null; 653 653 654 - if(boxLike(child)){ 655 - return child; 656 - } 852 + if(boxLike(child))return child; 657 657 658 658 var cr=child.getBoundingClientRect(); 659 659 var q=[]; ... ... @@ -715,7 +715,7 @@ 715 715 return best; 716 716 } 717 717 718 - function group sByVisualRow(entries){914 + function groupRows(entries){ 719 719 var groups=[]; 720 720 721 721 entries ... ... @@ -755,7 +755,7 @@ 755 755 return groups; 756 756 } 757 757 758 - function valid HorizontalGroup(group){954 + function validRow(group){ 759 759 if(group.entries.length<2)return false; 760 760 761 761 var lefts= ... ... @@ -778,25 +778,26 @@ 778 778 779 779 if(widths.length<2)return false; 780 780 781 - var minW idth=Math.min.apply(Math,widths);782 - varmaxWidth=Math.max.apply(Math,widths);977 + var minW= 978 + Math.min.apply(Math,widths); 783 783 980 + var maxW= 981 + Math.max.apply(Math,widths); 982 + 784 784 return ( 785 - maxW idth/786 - Math.max(1,minW idth)<=984 + maxW/ 985 + Math.max(1,minW)<= 787 787 1.9 788 788 ); 789 789 } 790 790 791 - function normalizeText(text){ 792 - return String(text||"") 793 - .replace(/s+/g," ") 794 - .trim() 795 - .toUpperCase(); 796 - } 990 + /* ---------- Known ARSN first section bars ---------- */ 797 797 798 - function exactKnownFirstSection(el){ 799 - var text=normalizeText(el.textContent); 992 + function knownBar(el){ 993 + var text= 994 + normalizeText( 995 + el.textContent 996 + ); 800 800 801 801 return ( 802 802 text==="HIER STARTEN"|| ... ... @@ -810,150 +810,274 @@ 810 810 ); 811 811 } 812 812 813 - function visuallyFirstSectionBar(card){814 - var cardRect= card.getBoundingClientRect();815 - varcandidates=[];1010 + function findKnownBar(card){ 1011 + var cardRect= 1012 + card.getBoundingClientRect(); 816 816 817 - Array.from( 818 - card.querySelectorAll( 819 - "div,p,span,strong,h3,h4,h5,h6" 1014 + var rows= 1015 + Array.from( 1016 + card.querySelectorAll( 1017 + "div,p,span,strong,h3,h4,h5,h6" 1018 + ) 820 820 ) 821 - ).forEach(function(el){822 - if(!visible(el,20,6))return; 823 - if( excluded(el))return;1020 + .filter(function(el){ 1021 + if(!visible(el,20,6))return false; 1022 + if(!knownBar(el))return false; 824 824 825 - var r=el.getBoundingClientRect(); 826 - var relativeTop=r.top-cardRect.top; 1024 + var r=el.getBoundingClientRect(); 827 827 828 - if( 829 - relativeTop<45|| 830 - relativeTop>cardRect.height*.72 831 - ){ 832 - return; 833 - } 1026 + var rel= 1027 + r.top- 1028 + cardRect.top; 834 834 835 - var widthRatio= 836 - r.width/ 837 - Math.max(1,cardRect.width); 1030 + return ( 1031 + rel>=35&& 1032 + rel<= 1033 + cardRect.height*.75 1034 + ); 1035 + }) 1036 + .sort(function(a,b){ 1037 + return ( 1038 + a.getBoundingClientRect().top- 1039 + b.getBoundingClientRect().top 1040 + ); 1041 + }); 838 838 839 - if( 840 - widthRatio<.55|| 841 - widthRatio>1.05|| 842 - r.height>54 843 - ){ 844 - return; 845 - } 1043 + return rows[0]||null; 1044 + } 846 846 847 - var text=normalizeText(el.textContent); 1046 + function alignKnownBars(cards){ 1047 + var rows= 1048 + cards.map(function(card){ 1049 + var bar= 1050 + findKnownBar(card); 848 848 849 - if( 850 - text.length<2|| 851 - text.length>90 852 - ){ 853 - return; 854 - } 1052 + if(!bar)return null; 855 855 856 - var style=getComputedStyle(el); 1054 + var cr= 1055 + card.getBoundingClientRect(); 857 857 858 - var bg= 859 - style.backgroundColor&& 860 - style.backgroundColor!=="rgba(0, 0, 0, 0)"&& 861 - style.backgroundColor!=="transparent"; 1057 + var br= 1058 + bar.getBoundingClientRect(); 862 862 863 - var border= 864 - num(style.borderTopWidth)+ 865 - num(style.borderRightWidth)+ 866 - num(style.borderBottomWidth)+ 867 - num(style.borderLeftWidth); 1060 + return { 1061 + bar:bar, 1062 + relativeTop: 1063 + br.top- 1064 + cr.top 1065 + }; 1066 + }); 868 868 869 - var mostlyUpper= 870 - text.length>=3&& 871 - text===text.toUpperCase(); 1068 + if( 1069 + rows.some(function(row){ 1070 + return !row; 1071 + }) 1072 + ){ 1073 + return false; 1074 + } 872 872 873 - var exact=exactKnownFirstSection(el); 1076 + var target= 1077 + Math.max.apply( 1078 + Math, 1079 + rows.map(function(row){ 1080 + return row.relativeTop; 1081 + }) 1082 + ); 874 874 875 - var score= 876 - (exact?20:0)+ 877 - (bg?6:0)+ 878 - (border>=1?2:0)+ 879 - (mostlyUpper?4:0)+ 880 - (num(style.fontWeight)>=600?1:0); 1084 + rows.forEach(function(row){ 1085 + var delta= 1086 + target- 1087 + row.relativeTop; 881 881 882 - if(score>=7){ 883 - candidates.push({ 884 - el:el, 885 - relativeTop:relativeTop, 886 - width:r.width, 887 - score:score 888 - }); 889 - } 890 - }); 1089 + if(delta<=1)return; 891 891 892 - if(!candidates.length)return null; 1091 + saveOriginal( 1092 + row.bar, 1093 + originalMarginTop, 1094 + "margin-top" 1095 + ); 893 893 894 - candidates.sort(function(a,b){ 895 - if(a.score!==b.score)return b.score-a.score; 896 - if(Math.abs(a.relativeTop-b.relativeTop)>3){ 897 - return a.relativeTop-b.relativeTop; 898 - } 899 - return b.width-a.width; 900 - }); 1097 + var current= 1098 + num( 1099 + getComputedStyle( 1100 + row.bar 1101 + ).marginTop 1102 + ); 901 901 902 - // For exact known labels always prefer the earliest exact match. 903 - var exacts=candidates.filter(function(c){ 904 - return exactKnownFirstSection(c.el); 1104 + row.bar.style.setProperty( 1105 + "margin-top", 1106 + ( 1107 + current+ 1108 + delta 1109 + )+"px" 1110 + ); 1111 + 1112 + row.bar.setAttribute( 1113 + "data-sn-first-section-aligned", 1114 + "7" 1115 + ); 1116 + 1117 + sectionManaged.add( 1118 + row.bar 1119 + ); 905 905 }); 906 906 907 - if(exacts.length){ 908 - exacts.sort(function(a,b){ 909 - return a.relativeTop-b.relativeTop||b.width-a.width; 1122 + return true; 1123 + } 1124 + 1125 + /* ---------- Generic first content after heading ---------- */ 1126 + 1127 + function heading(card){ 1128 + var cr= 1129 + card.getBoundingClientRect(); 1130 + 1131 + var rows= 1132 + Array.from( 1133 + card.querySelectorAll( 1134 + "h1,h2,h3,h4,h5,h6,.box-title,[role=heading]" 1135 + ) 1136 + ) 1137 + .filter(function(el){ 1138 + if(!visible(el,20,8))return false; 1139 + 1140 + var r=el.getBoundingClientRect(); 1141 + 1142 + var rel= 1143 + r.top- 1144 + cr.top; 1145 + 1146 + return ( 1147 + rel>=0&& 1148 + rel<= 1149 + Math.min( 1150 + 160, 1151 + cr.height*.45 1152 + ) 1153 + ); 1154 + }) 1155 + .sort(function(a,b){ 1156 + return ( 1157 + a.getBoundingClientRect().top- 1158 + b.getBoundingClientRect().top 1159 + ); 910 910 }); 911 - return exacts[0].el; 912 - } 913 913 914 - // Generic fallback: earliest high-confidence bar. 915 - candidates.sort(function(a,b){ 916 - return a.relativeTop-b.relativeTop||b.score-a.score||b.width-a.width; 917 - }); 1162 + return rows[0]||null; 1163 + } 918 918 919 - return candidates[0].el; 1165 + function firstContent(card,h){ 1166 + if(!h)return null; 1167 + 1168 + var cr= 1169 + card.getBoundingClientRect(); 1170 + 1171 + var hr= 1172 + h.getBoundingClientRect(); 1173 + 1174 + var rows= 1175 + Array.from( 1176 + card.querySelectorAll( 1177 + "p,div,ul,ol,dl,blockquote" 1178 + ) 1179 + ) 1180 + .filter(function(el){ 1181 + if( 1182 + el===h|| 1183 + h.contains(el)|| 1184 + el.contains(h) 1185 + ){ 1186 + return false; 1187 + } 1188 + 1189 + if(!visible(el,30,8))return false; 1190 + 1191 + var text= 1192 + String(el.textContent||"") 1193 + .replace(/\s+/g," ") 1194 + .trim(); 1195 + 1196 + if(text.length<3)return false; 1197 + 1198 + var r=el.getBoundingClientRect(); 1199 + 1200 + if( 1201 + r.top< 1202 + hr.bottom-1 1203 + ){ 1204 + return false; 1205 + } 1206 + 1207 + if( 1208 + r.top-cr.top> 1209 + Math.min( 1210 + 280, 1211 + cr.height*.65 1212 + ) 1213 + ){ 1214 + return false; 1215 + } 1216 + 1217 + if( 1218 + r.height> 1219 + cr.height*.58 1220 + ){ 1221 + return false; 1222 + } 1223 + 1224 + return true; 1225 + }) 1226 + .sort(function(a,b){ 1227 + var ar= 1228 + a.getBoundingClientRect(); 1229 + 1230 + var br= 1231 + b.getBoundingClientRect(); 1232 + 1233 + return ( 1234 + ar.top-br.top|| 1235 + ar.height-br.height 1236 + ); 1237 + }); 1238 + 1239 + return rows[0]||null; 920 920 } 921 921 922 - function align FirstSections(cards){1242 + function alignGeneric(cards){ 923 923 var rows= 924 924 cards.map(function(card){ 925 - var bar=926 - visuallyFirstSectionBar(card);1245 + var h= 1246 + heading(card); 927 927 928 - if(!bar)return null; 1248 + var c= 1249 + firstContent( 1250 + card, 1251 + h 1252 + ); 929 929 930 - var cardRect= 1254 + if(!h||!c)return null; 1255 + 1256 + var cr= 931 931 card.getBoundingClientRect(); 932 932 933 - var barRect=934 - bar.getBoundingClientRect();1259 + var rr= 1260 + c.getBoundingClientRect(); 935 935 936 936 return { 937 - card:card, 938 - bar:bar, 1263 + content:c, 939 939 relativeTop: 940 - barRect.top-cardRect.top, 941 - label: 942 - normalizeText(bar.textContent) 1265 + rr.top-cr.top 943 943 }; 944 944 }); 945 945 946 - // Conservative: only align when every card in the horizontal row 947 - // has a reliable first section bar. 948 948 if( 949 949 rows.some(function(row){ 950 950 return !row; 951 951 }) 952 952 ){ 953 - return null;1274 + return false; 954 954 } 955 955 956 - var target Top=1277 + var target= 957 957 Math.max.apply( 958 958 Math, 959 959 rows.map(function(row){ ... ... @@ -963,54 +963,47 @@ 963 963 964 964 rows.forEach(function(row){ 965 965 var delta= 966 - target Top-1287 + target- 967 967 row.relativeTop; 968 968 969 969 if(delta<=1)return; 970 970 971 971 saveOriginal( 972 - row. bar,1293 + row.content, 973 973 originalMarginTop, 974 974 "margin-top" 975 975 ); 976 976 977 - var current Margin=1298 + var current= 978 978 num( 979 979 getComputedStyle( 980 - row. bar1301 + row.content 981 981 ).marginTop 982 982 ); 983 983 984 - row. bar.style.setProperty(1305 + row.content.style.setProperty( 985 985 "margin-top", 986 986 ( 987 - current Margin+1308 + current+ 988 988 delta 989 989 )+"px" 990 990 ); 991 991 992 - row. bar.setAttribute(993 - "data-sn-first- section-aligned",994 - " 4"1313 + row.content.setAttribute( 1314 + "data-sn-first-content-aligned", 1315 + "7" 995 995 ); 996 996 997 - sectionManaged.add(row.bar); 1318 + contentManaged.add( 1319 + row.content 1320 + ); 998 998 }); 999 999 1000 - return { 1001 - labels: 1002 - rows.map(function(row){ 1003 - return row.label; 1004 - }), 1005 - targetRelativeTop: 1006 - Math.round(targetTop) 1007 - }; 1323 + return true; 1008 1008 } 1009 1009 1010 - function applyGroup(group){ 1011 - if(!validHorizontalGroup(group)){ 1012 - return null; 1013 - } 1326 + function applyRow(group){ 1327 + if(!validRow(group))return false; 1014 1014 1015 1015 var cards=[]; 1016 1016 var seen=new Set(); ... ... @@ -1022,25 +1022,30 @@ 1022 1022 } 1023 1023 }); 1024 1024 1025 - if(cards.length<2)return null;1339 + if(cards.length<2)return false; 1026 1026 1027 - var firstSection= 1028 - alignFirstSections(cards); 1341 + if( 1342 + !alignKnownBars(cards) 1343 + ){ 1344 + alignGeneric(cards); 1345 + } 1029 1029 1030 - // The section alignment can change natural card heights. 1031 - // Measure only afterwards. 1032 1032 var maxHeight=0; 1033 1033 1034 1034 cards.forEach(function(card){ 1035 - maxHeight=Math.max( 1036 - maxHeight, 1037 - card.getBoundingClientRect().height 1038 - ); 1350 + maxHeight= 1351 + Math.max( 1352 + maxHeight, 1353 + card.getBoundingClientRect().height 1354 + ); 1039 1039 }); 1040 1040 1041 - maxHeight=Math.ceil(maxHeight); 1357 + maxHeight= 1358 + Math.ceil( 1359 + maxHeight 1360 + ); 1042 1042 1043 - if(maxHeight<MIN_H)return null;1362 + if(maxHeight<MIN_H)return false; 1044 1044 1045 1045 cards.forEach(function(card){ 1046 1046 saveOriginal( ... ... @@ -1056,125 +1056,228 @@ 1056 1056 1057 1057 card.setAttribute( 1058 1058 "data-sn-equal-height-managed", 1059 - " 4"1378 + "7" 1060 1060 ); 1061 1061 1062 1062 heightManaged.add(card); 1063 1063 }); 1064 1064 1065 - return { 1066 - cards:cards.length, 1067 - height:maxHeight, 1068 - firstSection:firstSection 1069 - }; 1384 + return true; 1070 1070 } 1071 1071 1072 - function run(){1073 - re set();1387 + function calculate(force){ 1388 + if(applying)return; 1074 1074 1390 + var width= 1391 + Math.round( 1392 + window.innerWidth 1393 + ); 1394 + 1395 + var meaningful= 1396 + lastWidth<0|| 1397 + Math.abs( 1398 + width- 1399 + lastWidth 1400 + )>= 1401 + MIN_WIDTH_CHANGE; 1402 + 1075 1075 if( 1076 - window.innerWidth<=MOBILE_MAX 1404 + hasApplied&& 1405 + !force&& 1406 + !meaningful 1077 1077 ){ 1078 1078 return; 1079 1079 } 1080 1080 1081 - var parents= 1082 - Array.from( 1083 - root.querySelectorAll("*") 1084 - ).filter(function(parent){ 1085 - return ( 1086 - visible(parent,MIN_W,MIN_H)&& 1087 - parent.children&& 1088 - parent.children.length>=2&& 1089 - parent.children.length<=MAX_PARENT_CHILDREN 1090 - ); 1091 - }); 1411 + applying=true; 1092 1092 1093 - var touched=new Set(); 1413 + try{ 1414 + harmoniseCustomCallouts(); 1094 1094 1095 - parents.forEach(function(parent){ 1096 - var entries=[]; 1416 + if(width<=MOBILE_MAX){ 1417 + if(hasApplied){ 1418 + resetRuntime(); 1419 + } 1097 1097 1098 - Array.from(parent.children).forEach(function(child){ 1099 - if(!visible(child,MIN_W,MIN_H))return; 1421 + hasApplied=false; 1422 + lastWidth=width; 1423 + return; 1424 + } 1100 1100 1101 - var target=pickTarget(child); 1102 - if(!target)return; 1426 + if(hasApplied){ 1427 + resetRuntime(); 1428 + } 1103 1103 1104 - entries.push({ 1105 - target:target, 1106 - rect:target.getBoundingClientRect() 1430 + var parents= 1431 + Array.from( 1432 + root.querySelectorAll("*") 1433 + ) 1434 + .filter(function(parent){ 1435 + return ( 1436 + visible( 1437 + parent, 1438 + MIN_W, 1439 + MIN_H 1440 + )&& 1441 + parent.children&& 1442 + parent.children.length>=2&& 1443 + parent.children.length<= 1444 + MAX_PARENT_CHILDREN 1445 + ); 1107 1107 }); 1108 - }); 1109 1109 1110 - if(entries.length<2)return; 1448 + var touched= 1449 + new Set(); 1111 1111 1112 - groupsByVisualRow(entries).forEach(function(group){1113 - if(!validHorizontalGroup(group))return;1451 + parents.forEach(function(parent){ 1452 + var entries=[]; 1114 1114 1115 - var signature= 1116 - group.entries.map(function(entry){ 1117 - return entry.target; 1118 - }); 1454 + Array.from( 1455 + parent.children 1456 + ).forEach(function(child){ 1457 + if( 1458 + !visible( 1459 + child, 1460 + MIN_W, 1461 + MIN_H 1462 + ) 1463 + ){ 1464 + return; 1465 + } 1119 1119 1120 - if( 1121 - !signature.some(function(el){ 1122 - return !touched.has(el); 1123 - }) 1124 - ){ 1125 - return; 1126 - } 1467 + var target= 1468 + pickTarget(child); 1127 1127 1128 - var applied= 1129 - applyGroup(group); 1470 + if(!target)return; 1130 1130 1131 - if(applied){ 1132 - signature.forEach(function(el){ 1133 - touched.add(el); 1472 + entries.push({ 1473 + target:target, 1474 + rect: 1475 + target.getBoundingClientRect() 1134 1134 }); 1135 - } 1477 + }); 1478 + 1479 + groupRows( 1480 + entries 1481 + ).forEach(function(group){ 1482 + if(!validRow(group))return; 1483 + 1484 + var targets= 1485 + group.entries.map(function(entry){ 1486 + return entry.target; 1487 + }); 1488 + 1489 + if( 1490 + !targets.some(function(el){ 1491 + return !touched.has(el); 1492 + }) 1493 + ){ 1494 + return; 1495 + } 1496 + 1497 + if(applyRow(group)){ 1498 + targets.forEach(function(el){ 1499 + touched.add(el); 1500 + }); 1501 + } 1502 + }); 1136 1136 }); 1137 - }); 1504 + 1505 + lastWidth=width; 1506 + hasApplied=true; 1507 + }finally{ 1508 + applying=false; 1509 + } 1138 1138 } 1139 1139 1140 - function schedule(){ 1141 - if(raf)cancelAnimationFrame(raf); 1512 + function resize(){ 1513 + if(resizeTimer){ 1514 + clearTimeout( 1515 + resizeTimer 1516 + ); 1517 + } 1142 1142 1143 - raf=requestAnimationFrame(function(){ 1144 - raf=requestAnimationFrame(function(){ 1145 - raf=0; 1146 - run(); 1147 - }); 1148 - }); 1519 + resizeTimer= 1520 + setTimeout( 1521 + function(){ 1522 + resizeTimer=0; 1523 + calculate(false); 1524 + }, 1525 + RESIZE_DEBOUNCE 1526 + ); 1149 1149 } 1150 1150 1151 - addEventListener("resize",schedule,{passive:true}); 1152 - addEventListener("load",schedule,{once:true}); 1529 + function waitImages(){ 1530 + var images= 1531 + Array.from( 1532 + root.querySelectorAll("img") 1533 + ); 1153 1153 1154 - root.addEventListener( 1155 - "click", 1156 - function(){ 1157 - setTimeout(schedule,0); 1158 - }, 1159 - true 1160 - ); 1535 + return Promise.all( 1536 + images.map(function(img){ 1537 + if(img.complete){ 1538 + return Promise.resolve(); 1539 + } 1161 1161 1162 - Array.from(root.querySelectorAll("img")).forEach(function(img){ 1163 - if(!img.complete){ 1164 - img.addEventListener("load",schedule,{once:true}); 1541 + return new Promise(function(resolve){ 1542 + var done=function(){ 1543 + resolve(); 1544 + }; 1545 + 1546 + img.addEventListener( 1547 + "load", 1548 + done, 1549 + {once:true} 1550 + ); 1551 + 1552 + img.addEventListener( 1553 + "error", 1554 + done, 1555 + {once:true} 1556 + ); 1557 + }); 1558 + }) 1559 + ); 1560 + } 1561 + 1562 + async function initial(){ 1563 + if( 1564 + document.readyState!== 1565 + "complete" 1566 + ){ 1567 + await new Promise(function(resolve){ 1568 + addEventListener( 1569 + "load", 1570 + resolve, 1571 + {once:true} 1572 + ); 1573 + }); 1165 1165 } 1166 - }); 1167 1167 1168 - if(document.fonts&&document.fonts.ready){ 1169 - document.fonts.ready.then(schedule); 1576 + if( 1577 + document.fonts&& 1578 + document.fonts.ready 1579 + ){ 1580 + try{ 1581 + await document.fonts.ready; 1582 + }catch(error){} 1583 + } 1584 + 1585 + await waitImages(); 1586 + 1587 + // Exactly one initial layout calculation. 1588 + calculate(true); 1170 1170 } 1171 1171 1172 - schedule(); 1173 - setTimeout(schedule,200); 1174 - setTimeout(schedule,650); 1175 - setTimeout(schedule,1400); 1591 + addEventListener( 1592 + "resize", 1593 + resize, 1594 + {passive:true} 1595 + ); 1596 + 1597 + initial(); 1176 1176 })(); 1177 1177 </script> 1178 -<!-- SN_HORIZONTAL_BOX_HARMONIZER_END --> 1179 -{{/html}} 1180 1180 1601 +<!-- SN_HORIZONTAL_BOX_HARMONIZER_END --> 1602 +{{/html}}\n