Changes for page Art & Research Services Navigator
Last modified by Veronika Kocher on Friday, 18 Sep 2026 16:47
From version 39.22
edited by Veronika Kocher
on Thursday, 03 Sep 2026 9:34
on Thursday, 03 Sep 2026 9:34
Change comment:
There is no comment for this version
To version 39.23
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
-
... ... @@ -639,15 +639,104 @@ 639 639 {{/info}} 640 640 ))) 641 641 642 -{{html clean="false"}} 642 +\n\n 643 +\n\n{{html clean="false"}} 643 643 <!-- SN_HORIZONTAL_BOX_HARMONIZER_START --> 644 -<style data-sn-horizontal-box-harmonizer="4"> 645 -[data-sn-equal-height-managed], 646 -[data-sn-first-section-aligned]{ 645 + 646 +<style data-sn-horizontal-box-harmonizer="7"> 647 +/* ---------- Typography: never justify headings ---------- */ 648 +#xwikicontent h1, 649 +#xwikicontent h2, 650 +#xwikicontent h3, 651 +#xwikicontent h4, 652 +#xwikicontent h5, 653 +#xwikicontent h6, 654 +#xwikicontent .box-title, 655 +#xwikicontent [role="heading"], 656 +#xwikicontent h1 a, 657 +#xwikicontent h2 a, 658 +#xwikicontent h3 a, 659 +#xwikicontent h4 a, 660 +#xwikicontent h5 a, 661 +#xwikicontent h6 a, 662 +#xwikicontent .box-title a, 663 +#xwikicontent [role="heading"] a{ 664 + text-align:left!important; 665 + text-justify:auto!important; 666 + word-spacing:normal!important; 667 +} 668 + 669 +/* ---------- Native XWiki semantic callouts ---------- */ 670 +#xwikicontent .box.infomessage, 671 +#xwikicontent .infomessage, 672 +#xwikicontent .box.warningmessage, 673 +#xwikicontent .warningmessage, 674 +#xwikicontent .box.successmessage, 675 +#xwikicontent .successmessage, 676 +#xwikicontent .box.errormessage, 677 +#xwikicontent .errormessage, 678 +#xwikicontent [data-sn-callout-harmonized="1"]{ 679 + box-sizing:border-box!important; 680 + border-radius:8px!important; 681 + border-top:1px solid rgba(0,0,0,.08)!important; 682 + border-right:1px solid rgba(0,0,0,.08)!important; 683 + border-bottom:1px solid rgba(0,0,0,.08)!important; 684 + border-left:4px solid var(--sn-callout-accent,#21b6d7)!important; 685 + padding:14px 16px!important; 686 + text-align:left!important; 687 + text-justify:auto!important; 688 + word-spacing:normal!important; 689 + box-shadow:none!important; 690 +} 691 + 692 +#xwikicontent .box.infomessage, 693 +#xwikicontent .infomessage{ 694 + --sn-callout-accent:#21b6d7; 695 + background:#eaf7fb!important; 696 +} 697 + 698 +#xwikicontent .box.warningmessage, 699 +#xwikicontent .warningmessage{ 700 + --sn-callout-accent:#f0aa00; 701 + background:#fff8e7!important; 702 +} 703 + 704 +#xwikicontent .box.successmessage, 705 +#xwikicontent .successmessage{ 706 + --sn-callout-accent:#38b76a; 707 + background:#edf9f1!important; 708 +} 709 + 710 +#xwikicontent .box.errormessage, 711 +#xwikicontent .errormessage{ 712 + --sn-callout-accent:#e94b13; 713 + background:#fff1ec!important; 714 +} 715 + 716 +#xwikicontent [data-sn-callout-harmonized="1"] > :first-child, 717 +#xwikicontent .infomessage > :first-child, 718 +#xwikicontent .warningmessage > :first-child, 719 +#xwikicontent .successmessage > :first-child, 720 +#xwikicontent .errormessage > :first-child{ 721 + margin-top:0!important; 722 +} 723 + 724 +#xwikicontent [data-sn-callout-harmonized="1"] > :last-child, 725 +#xwikicontent .infomessage > :last-child, 726 +#xwikicontent .warningmessage > :last-child, 727 +#xwikicontent .successmessage > :last-child, 728 +#xwikicontent .errormessage > :last-child{ 729 + margin-bottom:0!important; 730 +} 731 + 732 +#xwikicontent [data-sn-equal-height-managed], 733 +#xwikicontent [data-sn-first-section-aligned], 734 +#xwikicontent [data-sn-first-content-aligned]{ 647 647 box-sizing:border-box; 648 648 } 649 649 </style> 650 -<script data-sn-horizontal-box-harmonizer="4"> 738 + 739 +<script data-sn-horizontal-box-harmonizer="7"> 651 651 (function(){ 652 652 "use strict"; 653 653 ... ... @@ -655,8 +655,10 @@ 655 655 var ROW_TOLERANCE=6; 656 656 var MIN_W=150; 657 657 var MIN_H=36; 658 - var MAX_PARENT_CHILDREN=1 6;747 + var MAX_PARENT_CHILDREN=18; 659 659 var SEARCH_DEPTH=5; 749 + var RESIZE_DEBOUNCE=220; 750 + var MIN_WIDTH_CHANGE=2; 660 660 661 661 var root= 662 662 document.getElementById("xwikicontent")|| ... ... @@ -668,10 +668,16 @@ 668 668 669 669 var heightManaged=new Set(); 670 670 var sectionManaged=new Set(); 762 + var contentManaged=new Set(); 763 + 671 671 var originalMinHeight=new WeakMap(); 672 672 var originalMarginTop=new WeakMap(); 673 - var raf=0; 674 674 767 + var resizeTimer=0; 768 + var lastWidth=-1; 769 + var hasApplied=false; 770 + var applying=false; 771 + 675 675 function num(v){ 676 676 var n=parseFloat(v); 677 677 return Number.isFinite(n)?n:0; ... ... @@ -698,6 +698,13 @@ 698 698 ); 699 699 } 700 700 798 + function normalizeText(text){ 799 + return String(text||"") 800 + .replace(/\s+/g," ") 801 + .trim() 802 + .toUpperCase(); 803 + } 804 + 701 701 function excluded(el){ 702 702 return ( 703 703 !el.matches|| ... ... @@ -707,57 +707,84 @@ 707 707 ); 708 708 } 709 709 710 - function namedLikeBox(el){ 814 + /* ---------- Custom coloured callouts ---------- */ 815 + 816 + function nativeCallout(el){ 711 711 var c= 712 712 typeof el.className==="string" 713 - ? el.className 819 + ? el.className.toLowerCase() 714 714 : ""; 715 715 716 - return /(^|[s_-])(box|card|tile|panel|role|check|service|source|call|area|detail|resource|topic|warn|info)([s_-]|$)/i.test(c); 822 + return ( 823 + /(^|\s)(infomessage|warningmessage|successmessage|errormessage)(\s|$)/.test(c) 824 + ); 717 717 } 718 718 719 - function boxLike(el){720 - if(!visible(el, MIN_W,MIN_H)||excluded(el))return false;827 + function customCallout(el){ 828 + if(!visible(el,220,42)||excluded(el))return false; 721 721 722 - var s=getComputedStyle(el); 723 723 var r=el.getBoundingClientRect(); 724 724 725 - var border= 726 - num(s.borderTopWidth)+ 727 - num(s.borderRightWidth)+ 728 - num(s.borderBottomWidth)+ 729 - num(s.borderLeftWidth); 832 + if(r.height>520)return false; 730 730 731 - var radius=Math.max( 732 - num(s.borderTopLeftRadius), 733 - num(s.borderTopRightRadius), 734 - num(s.borderBottomLeftRadius), 735 - num(s.borderBottomRightRadius) 736 - ); 834 + var s=getComputedStyle(el); 737 737 738 738 var bg= 739 739 s.backgroundColor&& 740 740 s.backgroundColor!=="rgba(0, 0, 0, 0)"&& 741 - s.backgroundColor!=="transparent"; 839 + s.backgroundColor!=="transparent"&& 840 + s.backgroundColor!=="rgb(255, 255, 255)"; 742 742 743 - var shadow= 744 - s.boxShadow&& 745 - s.boxShadow!=="none"; 842 + var left= 843 + num(s.borderLeftWidth); 746 746 747 747 return ( 748 - namedLikeBox(el)|| 749 - border>=1|| 750 - (bg&&radius>=3)|| 751 - (shadow&&r.width>=180) 846 + bg&& 847 + left>=2 752 752 ); 753 753 } 754 754 851 + function harmoniseCustomCallouts(){ 852 + Array.from( 853 + root.querySelectorAll( 854 + "div,aside,section" 855 + ) 856 + ).forEach(function(el){ 857 + if(nativeCallout(el))return; 858 + if(!customCallout(el))return; 859 + 860 + var s=getComputedStyle(el); 861 + 862 + el.setAttribute( 863 + "data-sn-callout-harmonized", 864 + "1" 865 + ); 866 + 867 + if( 868 + s.borderLeftColor 869 + ){ 870 + el.style.setProperty( 871 + "--sn-callout-accent", 872 + s.borderLeftColor 873 + ); 874 + } 875 + }); 876 + } 877 + 878 + /* ---------- Restore only values V7 itself changed ---------- */ 879 + 755 755 function saveOriginal(el,map,property){ 756 756 if(map.has(el))return; 757 757 758 758 map.set(el,{ 759 - value:el.style.getPropertyValue(property), 760 - priority:el.style.getPropertyPriority(property) 884 + value: 885 + el.style.getPropertyValue( 886 + property 887 + ), 888 + priority: 889 + el.style.getPropertyPriority( 890 + property 891 + ) 761 761 }); 762 762 } 763 763 ... ... @@ -771,11 +771,13 @@ 771 771 original.priority||"" 772 772 ); 773 773 }else{ 774 - el.style.removeProperty(property); 905 + el.style.removeProperty( 906 + property 907 + ); 775 775 } 776 776 } 777 777 778 - function reset(){ 911 + function resetRuntime(){ 779 779 heightManaged.forEach(function(el){ 780 780 restoreOriginal( 781 781 el, ... ... @@ -800,16 +800,79 @@ 800 800 ); 801 801 }); 802 802 936 + contentManaged.forEach(function(el){ 937 + restoreOriginal( 938 + el, 939 + originalMarginTop, 940 + "margin-top" 941 + ); 942 + 943 + el.removeAttribute( 944 + "data-sn-first-content-aligned" 945 + ); 946 + }); 947 + 803 803 heightManaged.clear(); 804 804 sectionManaged.clear(); 950 + contentManaged.clear(); 805 805 } 806 806 953 + /* ---------- Card detection ---------- */ 954 + 955 + function namedLikeBox(el){ 956 + var c= 957 + typeof el.className==="string" 958 + ? el.className 959 + : ""; 960 + 961 + return /(^|[\s_-])(box|card|tile|panel|role|check|service|source|call|area|detail|resource|topic|warn|info)([\s_-]|$)/i.test(c); 962 + } 963 + 964 + function boxLike(el){ 965 + if( 966 + !visible(el,MIN_W,MIN_H)|| 967 + excluded(el) 968 + ){ 969 + return false; 970 + } 971 + 972 + var s=getComputedStyle(el); 973 + var r=el.getBoundingClientRect(); 974 + 975 + var border= 976 + num(s.borderTopWidth)+ 977 + num(s.borderRightWidth)+ 978 + num(s.borderBottomWidth)+ 979 + num(s.borderLeftWidth); 980 + 981 + var radius=Math.max( 982 + num(s.borderTopLeftRadius), 983 + num(s.borderTopRightRadius), 984 + num(s.borderBottomLeftRadius), 985 + num(s.borderBottomRightRadius) 986 + ); 987 + 988 + var bg= 989 + s.backgroundColor&& 990 + s.backgroundColor!=="rgba(0, 0, 0, 0)"&& 991 + s.backgroundColor!=="transparent"; 992 + 993 + var shadow= 994 + s.boxShadow&& 995 + s.boxShadow!=="none"; 996 + 997 + return ( 998 + namedLikeBox(el)|| 999 + border>=1|| 1000 + (bg&&radius>=3)|| 1001 + (shadow&&r.width>=180) 1002 + ); 1003 + } 1004 + 807 807 function pickTarget(child){ 808 808 if(!visible(child,MIN_W,MIN_H))return null; 809 809 810 - if(boxLike(child)){ 811 - return child; 812 - } 1008 + if(boxLike(child))return child; 813 813 814 814 var cr=child.getBoundingClientRect(); 815 815 var q=[]; ... ... @@ -871,7 +871,7 @@ 871 871 return best; 872 872 } 873 873 874 - function group sByVisualRow(entries){1070 + function groupRows(entries){ 875 875 var groups=[]; 876 876 877 877 entries ... ... @@ -911,7 +911,7 @@ 911 911 return groups; 912 912 } 913 913 914 - function valid HorizontalGroup(group){1110 + function validRow(group){ 915 915 if(group.entries.length<2)return false; 916 916 917 917 var lefts= ... ... @@ -934,25 +934,26 @@ 934 934 935 935 if(widths.length<2)return false; 936 936 937 - var minW idth=Math.min.apply(Math,widths);938 - varmaxWidth=Math.max.apply(Math,widths);1133 + var minW= 1134 + Math.min.apply(Math,widths); 939 939 1136 + var maxW= 1137 + Math.max.apply(Math,widths); 1138 + 940 940 return ( 941 - maxW idth/942 - Math.max(1,minW idth)<=1140 + maxW/ 1141 + Math.max(1,minW)<= 943 943 1.9 944 944 ); 945 945 } 946 946 947 - function normalizeText(text){ 948 - return String(text||"") 949 - .replace(/s+/g," ") 950 - .trim() 951 - .toUpperCase(); 952 - } 1146 + /* ---------- Known ARSN first section bars ---------- */ 953 953 954 - function exactKnownFirstSection(el){ 955 - var text=normalizeText(el.textContent); 1148 + function knownBar(el){ 1149 + var text= 1150 + normalizeText( 1151 + el.textContent 1152 + ); 956 956 957 957 return ( 958 958 text==="HIER STARTEN"|| ... ... @@ -966,150 +966,274 @@ 966 966 ); 967 967 } 968 968 969 - function visuallyFirstSectionBar(card){970 - var cardRect= card.getBoundingClientRect();971 - varcandidates=[];1166 + function findKnownBar(card){ 1167 + var cardRect= 1168 + card.getBoundingClientRect(); 972 972 973 - Array.from( 974 - card.querySelectorAll( 975 - "div,p,span,strong,h3,h4,h5,h6" 1170 + var rows= 1171 + Array.from( 1172 + card.querySelectorAll( 1173 + "div,p,span,strong,h3,h4,h5,h6" 1174 + ) 976 976 ) 977 - ).forEach(function(el){978 - if(!visible(el,20,6))return; 979 - if( excluded(el))return;1176 + .filter(function(el){ 1177 + if(!visible(el,20,6))return false; 1178 + if(!knownBar(el))return false; 980 980 981 - var r=el.getBoundingClientRect(); 982 - var relativeTop=r.top-cardRect.top; 1180 + var r=el.getBoundingClientRect(); 983 983 984 - if( 985 - relativeTop<45|| 986 - relativeTop>cardRect.height*.72 987 - ){ 988 - return; 989 - } 1182 + var rel= 1183 + r.top- 1184 + cardRect.top; 990 990 991 - var widthRatio= 992 - r.width/ 993 - Math.max(1,cardRect.width); 1186 + return ( 1187 + rel>=35&& 1188 + rel<= 1189 + cardRect.height*.75 1190 + ); 1191 + }) 1192 + .sort(function(a,b){ 1193 + return ( 1194 + a.getBoundingClientRect().top- 1195 + b.getBoundingClientRect().top 1196 + ); 1197 + }); 994 994 995 - if( 996 - widthRatio<.55|| 997 - widthRatio>1.05|| 998 - r.height>54 999 - ){ 1000 - return; 1001 - } 1199 + return rows[0]||null; 1200 + } 1002 1002 1003 - var text=normalizeText(el.textContent); 1202 + function alignKnownBars(cards){ 1203 + var rows= 1204 + cards.map(function(card){ 1205 + var bar= 1206 + findKnownBar(card); 1004 1004 1005 - if( 1006 - text.length<2|| 1007 - text.length>90 1008 - ){ 1009 - return; 1010 - } 1208 + if(!bar)return null; 1011 1011 1012 - var style=getComputedStyle(el); 1210 + var cr= 1211 + card.getBoundingClientRect(); 1013 1013 1014 - var bg= 1015 - style.backgroundColor&& 1016 - style.backgroundColor!=="rgba(0, 0, 0, 0)"&& 1017 - style.backgroundColor!=="transparent"; 1213 + var br= 1214 + bar.getBoundingClientRect(); 1018 1018 1019 - var border= 1020 - num(style.borderTopWidth)+ 1021 - num(style.borderRightWidth)+ 1022 - num(style.borderBottomWidth)+ 1023 - num(style.borderLeftWidth); 1216 + return { 1217 + bar:bar, 1218 + relativeTop: 1219 + br.top- 1220 + cr.top 1221 + }; 1222 + }); 1024 1024 1025 - var mostlyUpper= 1026 - text.length>=3&& 1027 - text===text.toUpperCase(); 1224 + if( 1225 + rows.some(function(row){ 1226 + return !row; 1227 + }) 1228 + ){ 1229 + return false; 1230 + } 1028 1028 1029 - var exact=exactKnownFirstSection(el); 1232 + var target= 1233 + Math.max.apply( 1234 + Math, 1235 + rows.map(function(row){ 1236 + return row.relativeTop; 1237 + }) 1238 + ); 1030 1030 1031 - var score= 1032 - (exact?20:0)+ 1033 - (bg?6:0)+ 1034 - (border>=1?2:0)+ 1035 - (mostlyUpper?4:0)+ 1036 - (num(style.fontWeight)>=600?1:0); 1240 + rows.forEach(function(row){ 1241 + var delta= 1242 + target- 1243 + row.relativeTop; 1037 1037 1038 - if(score>=7){ 1039 - candidates.push({ 1040 - el:el, 1041 - relativeTop:relativeTop, 1042 - width:r.width, 1043 - score:score 1044 - }); 1045 - } 1046 - }); 1245 + if(delta<=1)return; 1047 1047 1048 - if(!candidates.length)return null; 1247 + saveOriginal( 1248 + row.bar, 1249 + originalMarginTop, 1250 + "margin-top" 1251 + ); 1049 1049 1050 - candidates.sort(function(a,b){ 1051 - if(a.score!==b.score)return b.score-a.score; 1052 - if(Math.abs(a.relativeTop-b.relativeTop)>3){ 1053 - return a.relativeTop-b.relativeTop; 1054 - } 1055 - return b.width-a.width; 1056 - }); 1253 + var current= 1254 + num( 1255 + getComputedStyle( 1256 + row.bar 1257 + ).marginTop 1258 + ); 1057 1057 1058 - // For exact known labels always prefer the earliest exact match. 1059 - var exacts=candidates.filter(function(c){ 1060 - return exactKnownFirstSection(c.el); 1260 + row.bar.style.setProperty( 1261 + "margin-top", 1262 + ( 1263 + current+ 1264 + delta 1265 + )+"px" 1266 + ); 1267 + 1268 + row.bar.setAttribute( 1269 + "data-sn-first-section-aligned", 1270 + "7" 1271 + ); 1272 + 1273 + sectionManaged.add( 1274 + row.bar 1275 + ); 1061 1061 }); 1062 1062 1063 - if(exacts.length){ 1064 - exacts.sort(function(a,b){ 1065 - return a.relativeTop-b.relativeTop||b.width-a.width; 1278 + return true; 1279 + } 1280 + 1281 + /* ---------- Generic first content after heading ---------- */ 1282 + 1283 + function heading(card){ 1284 + var cr= 1285 + card.getBoundingClientRect(); 1286 + 1287 + var rows= 1288 + Array.from( 1289 + card.querySelectorAll( 1290 + "h1,h2,h3,h4,h5,h6,.box-title,[role=heading]" 1291 + ) 1292 + ) 1293 + .filter(function(el){ 1294 + if(!visible(el,20,8))return false; 1295 + 1296 + var r=el.getBoundingClientRect(); 1297 + 1298 + var rel= 1299 + r.top- 1300 + cr.top; 1301 + 1302 + return ( 1303 + rel>=0&& 1304 + rel<= 1305 + Math.min( 1306 + 160, 1307 + cr.height*.45 1308 + ) 1309 + ); 1310 + }) 1311 + .sort(function(a,b){ 1312 + return ( 1313 + a.getBoundingClientRect().top- 1314 + b.getBoundingClientRect().top 1315 + ); 1066 1066 }); 1067 - return exacts[0].el; 1068 - } 1069 1069 1070 - // Generic fallback: earliest high-confidence bar. 1071 - candidates.sort(function(a,b){ 1072 - return a.relativeTop-b.relativeTop||b.score-a.score||b.width-a.width; 1073 - }); 1318 + return rows[0]||null; 1319 + } 1074 1074 1075 - return candidates[0].el; 1321 + function firstContent(card,h){ 1322 + if(!h)return null; 1323 + 1324 + var cr= 1325 + card.getBoundingClientRect(); 1326 + 1327 + var hr= 1328 + h.getBoundingClientRect(); 1329 + 1330 + var rows= 1331 + Array.from( 1332 + card.querySelectorAll( 1333 + "p,div,ul,ol,dl,blockquote" 1334 + ) 1335 + ) 1336 + .filter(function(el){ 1337 + if( 1338 + el===h|| 1339 + h.contains(el)|| 1340 + el.contains(h) 1341 + ){ 1342 + return false; 1343 + } 1344 + 1345 + if(!visible(el,30,8))return false; 1346 + 1347 + var text= 1348 + String(el.textContent||"") 1349 + .replace(/\s+/g," ") 1350 + .trim(); 1351 + 1352 + if(text.length<3)return false; 1353 + 1354 + var r=el.getBoundingClientRect(); 1355 + 1356 + if( 1357 + r.top< 1358 + hr.bottom-1 1359 + ){ 1360 + return false; 1361 + } 1362 + 1363 + if( 1364 + r.top-cr.top> 1365 + Math.min( 1366 + 280, 1367 + cr.height*.65 1368 + ) 1369 + ){ 1370 + return false; 1371 + } 1372 + 1373 + if( 1374 + r.height> 1375 + cr.height*.58 1376 + ){ 1377 + return false; 1378 + } 1379 + 1380 + return true; 1381 + }) 1382 + .sort(function(a,b){ 1383 + var ar= 1384 + a.getBoundingClientRect(); 1385 + 1386 + var br= 1387 + b.getBoundingClientRect(); 1388 + 1389 + return ( 1390 + ar.top-br.top|| 1391 + ar.height-br.height 1392 + ); 1393 + }); 1394 + 1395 + return rows[0]||null; 1076 1076 } 1077 1077 1078 - function align FirstSections(cards){1398 + function alignGeneric(cards){ 1079 1079 var rows= 1080 1080 cards.map(function(card){ 1081 - var bar=1082 - visuallyFirstSectionBar(card);1401 + var h= 1402 + heading(card); 1083 1083 1084 - if(!bar)return null; 1404 + var c= 1405 + firstContent( 1406 + card, 1407 + h 1408 + ); 1085 1085 1086 - var cardRect= 1410 + if(!h||!c)return null; 1411 + 1412 + var cr= 1087 1087 card.getBoundingClientRect(); 1088 1088 1089 - var barRect=1090 - bar.getBoundingClientRect();1415 + var rr= 1416 + c.getBoundingClientRect(); 1091 1091 1092 1092 return { 1093 - card:card, 1094 - bar:bar, 1419 + content:c, 1095 1095 relativeTop: 1096 - barRect.top-cardRect.top, 1097 - label: 1098 - normalizeText(bar.textContent) 1421 + rr.top-cr.top 1099 1099 }; 1100 1100 }); 1101 1101 1102 - // Conservative: only align when every card in the horizontal row 1103 - // has a reliable first section bar. 1104 1104 if( 1105 1105 rows.some(function(row){ 1106 1106 return !row; 1107 1107 }) 1108 1108 ){ 1109 - return null;1430 + return false; 1110 1110 } 1111 1111 1112 - var target Top=1433 + var target= 1113 1113 Math.max.apply( 1114 1114 Math, 1115 1115 rows.map(function(row){ ... ... @@ -1119,54 +1119,47 @@ 1119 1119 1120 1120 rows.forEach(function(row){ 1121 1121 var delta= 1122 - target Top-1443 + target- 1123 1123 row.relativeTop; 1124 1124 1125 1125 if(delta<=1)return; 1126 1126 1127 1127 saveOriginal( 1128 - row. bar,1449 + row.content, 1129 1129 originalMarginTop, 1130 1130 "margin-top" 1131 1131 ); 1132 1132 1133 - var current Margin=1454 + var current= 1134 1134 num( 1135 1135 getComputedStyle( 1136 - row. bar1457 + row.content 1137 1137 ).marginTop 1138 1138 ); 1139 1139 1140 - row. bar.style.setProperty(1461 + row.content.style.setProperty( 1141 1141 "margin-top", 1142 1142 ( 1143 - current Margin+1464 + current+ 1144 1144 delta 1145 1145 )+"px" 1146 1146 ); 1147 1147 1148 - row. bar.setAttribute(1149 - "data-sn-first- section-aligned",1150 - " 4"1469 + row.content.setAttribute( 1470 + "data-sn-first-content-aligned", 1471 + "7" 1151 1151 ); 1152 1152 1153 - sectionManaged.add(row.bar); 1474 + contentManaged.add( 1475 + row.content 1476 + ); 1154 1154 }); 1155 1155 1156 - return { 1157 - labels: 1158 - rows.map(function(row){ 1159 - return row.label; 1160 - }), 1161 - targetRelativeTop: 1162 - Math.round(targetTop) 1163 - }; 1479 + return true; 1164 1164 } 1165 1165 1166 - function applyGroup(group){ 1167 - if(!validHorizontalGroup(group)){ 1168 - return null; 1169 - } 1482 + function applyRow(group){ 1483 + if(!validRow(group))return false; 1170 1170 1171 1171 var cards=[]; 1172 1172 var seen=new Set(); ... ... @@ -1178,25 +1178,30 @@ 1178 1178 } 1179 1179 }); 1180 1180 1181 - if(cards.length<2)return null;1495 + if(cards.length<2)return false; 1182 1182 1183 - var firstSection= 1184 - alignFirstSections(cards); 1497 + if( 1498 + !alignKnownBars(cards) 1499 + ){ 1500 + alignGeneric(cards); 1501 + } 1185 1185 1186 - // The section alignment can change natural card heights. 1187 - // Measure only afterwards. 1188 1188 var maxHeight=0; 1189 1189 1190 1190 cards.forEach(function(card){ 1191 - maxHeight=Math.max( 1192 - maxHeight, 1193 - card.getBoundingClientRect().height 1194 - ); 1506 + maxHeight= 1507 + Math.max( 1508 + maxHeight, 1509 + card.getBoundingClientRect().height 1510 + ); 1195 1195 }); 1196 1196 1197 - maxHeight=Math.ceil(maxHeight); 1513 + maxHeight= 1514 + Math.ceil( 1515 + maxHeight 1516 + ); 1198 1198 1199 - if(maxHeight<MIN_H)return null;1518 + if(maxHeight<MIN_H)return false; 1200 1200 1201 1201 cards.forEach(function(card){ 1202 1202 saveOriginal( ... ... @@ -1212,125 +1212,228 @@ 1212 1212 1213 1213 card.setAttribute( 1214 1214 "data-sn-equal-height-managed", 1215 - " 4"1534 + "7" 1216 1216 ); 1217 1217 1218 1218 heightManaged.add(card); 1219 1219 }); 1220 1220 1221 - return { 1222 - cards:cards.length, 1223 - height:maxHeight, 1224 - firstSection:firstSection 1225 - }; 1540 + return true; 1226 1226 } 1227 1227 1228 - function run(){1229 - re set();1543 + function calculate(force){ 1544 + if(applying)return; 1230 1230 1546 + var width= 1547 + Math.round( 1548 + window.innerWidth 1549 + ); 1550 + 1551 + var meaningful= 1552 + lastWidth<0|| 1553 + Math.abs( 1554 + width- 1555 + lastWidth 1556 + )>= 1557 + MIN_WIDTH_CHANGE; 1558 + 1231 1231 if( 1232 - window.innerWidth<=MOBILE_MAX 1560 + hasApplied&& 1561 + !force&& 1562 + !meaningful 1233 1233 ){ 1234 1234 return; 1235 1235 } 1236 1236 1237 - var parents= 1238 - Array.from( 1239 - root.querySelectorAll("*") 1240 - ).filter(function(parent){ 1241 - return ( 1242 - visible(parent,MIN_W,MIN_H)&& 1243 - parent.children&& 1244 - parent.children.length>=2&& 1245 - parent.children.length<=MAX_PARENT_CHILDREN 1246 - ); 1247 - }); 1567 + applying=true; 1248 1248 1249 - var touched=new Set(); 1569 + try{ 1570 + harmoniseCustomCallouts(); 1250 1250 1251 - parents.forEach(function(parent){ 1252 - var entries=[]; 1572 + if(width<=MOBILE_MAX){ 1573 + if(hasApplied){ 1574 + resetRuntime(); 1575 + } 1253 1253 1254 - Array.from(parent.children).forEach(function(child){ 1255 - if(!visible(child,MIN_W,MIN_H))return; 1577 + hasApplied=false; 1578 + lastWidth=width; 1579 + return; 1580 + } 1256 1256 1257 - var target=pickTarget(child); 1258 - if(!target)return; 1582 + if(hasApplied){ 1583 + resetRuntime(); 1584 + } 1259 1259 1260 - entries.push({ 1261 - target:target, 1262 - rect:target.getBoundingClientRect() 1586 + var parents= 1587 + Array.from( 1588 + root.querySelectorAll("*") 1589 + ) 1590 + .filter(function(parent){ 1591 + return ( 1592 + visible( 1593 + parent, 1594 + MIN_W, 1595 + MIN_H 1596 + )&& 1597 + parent.children&& 1598 + parent.children.length>=2&& 1599 + parent.children.length<= 1600 + MAX_PARENT_CHILDREN 1601 + ); 1263 1263 }); 1264 - }); 1265 1265 1266 - if(entries.length<2)return; 1604 + var touched= 1605 + new Set(); 1267 1267 1268 - groupsByVisualRow(entries).forEach(function(group){1269 - if(!validHorizontalGroup(group))return;1607 + parents.forEach(function(parent){ 1608 + var entries=[]; 1270 1270 1271 - var signature= 1272 - group.entries.map(function(entry){ 1273 - return entry.target; 1274 - }); 1610 + Array.from( 1611 + parent.children 1612 + ).forEach(function(child){ 1613 + if( 1614 + !visible( 1615 + child, 1616 + MIN_W, 1617 + MIN_H 1618 + ) 1619 + ){ 1620 + return; 1621 + } 1275 1275 1276 - if( 1277 - !signature.some(function(el){ 1278 - return !touched.has(el); 1279 - }) 1280 - ){ 1281 - return; 1282 - } 1623 + var target= 1624 + pickTarget(child); 1283 1283 1284 - var applied= 1285 - applyGroup(group); 1626 + if(!target)return; 1286 1286 1287 - if(applied){ 1288 - signature.forEach(function(el){ 1289 - touched.add(el); 1628 + entries.push({ 1629 + target:target, 1630 + rect: 1631 + target.getBoundingClientRect() 1290 1290 }); 1291 - } 1633 + }); 1634 + 1635 + groupRows( 1636 + entries 1637 + ).forEach(function(group){ 1638 + if(!validRow(group))return; 1639 + 1640 + var targets= 1641 + group.entries.map(function(entry){ 1642 + return entry.target; 1643 + }); 1644 + 1645 + if( 1646 + !targets.some(function(el){ 1647 + return !touched.has(el); 1648 + }) 1649 + ){ 1650 + return; 1651 + } 1652 + 1653 + if(applyRow(group)){ 1654 + targets.forEach(function(el){ 1655 + touched.add(el); 1656 + }); 1657 + } 1658 + }); 1292 1292 }); 1293 - }); 1660 + 1661 + lastWidth=width; 1662 + hasApplied=true; 1663 + }finally{ 1664 + applying=false; 1665 + } 1294 1294 } 1295 1295 1296 - function schedule(){ 1297 - if(raf)cancelAnimationFrame(raf); 1668 + function resize(){ 1669 + if(resizeTimer){ 1670 + clearTimeout( 1671 + resizeTimer 1672 + ); 1673 + } 1298 1298 1299 - raf=requestAnimationFrame(function(){ 1300 - raf=requestAnimationFrame(function(){ 1301 - raf=0; 1302 - run(); 1303 - }); 1304 - }); 1675 + resizeTimer= 1676 + setTimeout( 1677 + function(){ 1678 + resizeTimer=0; 1679 + calculate(false); 1680 + }, 1681 + RESIZE_DEBOUNCE 1682 + ); 1305 1305 } 1306 1306 1307 - addEventListener("resize",schedule,{passive:true}); 1308 - addEventListener("load",schedule,{once:true}); 1685 + function waitImages(){ 1686 + var images= 1687 + Array.from( 1688 + root.querySelectorAll("img") 1689 + ); 1309 1309 1310 - root.addEventListener( 1311 - "click", 1312 - function(){ 1313 - setTimeout(schedule,0); 1314 - }, 1315 - true 1316 - ); 1691 + return Promise.all( 1692 + images.map(function(img){ 1693 + if(img.complete){ 1694 + return Promise.resolve(); 1695 + } 1317 1317 1318 - Array.from(root.querySelectorAll("img")).forEach(function(img){ 1319 - if(!img.complete){ 1320 - img.addEventListener("load",schedule,{once:true}); 1697 + return new Promise(function(resolve){ 1698 + var done=function(){ 1699 + resolve(); 1700 + }; 1701 + 1702 + img.addEventListener( 1703 + "load", 1704 + done, 1705 + {once:true} 1706 + ); 1707 + 1708 + img.addEventListener( 1709 + "error", 1710 + done, 1711 + {once:true} 1712 + ); 1713 + }); 1714 + }) 1715 + ); 1716 + } 1717 + 1718 + async function initial(){ 1719 + if( 1720 + document.readyState!== 1721 + "complete" 1722 + ){ 1723 + await new Promise(function(resolve){ 1724 + addEventListener( 1725 + "load", 1726 + resolve, 1727 + {once:true} 1728 + ); 1729 + }); 1321 1321 } 1322 - }); 1323 1323 1324 - if(document.fonts&&document.fonts.ready){ 1325 - document.fonts.ready.then(schedule); 1732 + if( 1733 + document.fonts&& 1734 + document.fonts.ready 1735 + ){ 1736 + try{ 1737 + await document.fonts.ready; 1738 + }catch(error){} 1739 + } 1740 + 1741 + await waitImages(); 1742 + 1743 + // Exactly one initial layout calculation. 1744 + calculate(true); 1326 1326 } 1327 1327 1328 - schedule(); 1329 - setTimeout(schedule,200); 1330 - setTimeout(schedule,650); 1331 - setTimeout(schedule,1400); 1747 + addEventListener( 1748 + "resize", 1749 + resize, 1750 + {passive:true} 1751 + ); 1752 + 1753 + initial(); 1332 1332 })(); 1333 1333 </script> 1334 -<!-- SN_HORIZONTAL_BOX_HARMONIZER_END --> 1335 -{{/html}} 1336 1336 1757 +<!-- SN_HORIZONTAL_BOX_HARMONIZER_END --> 1758 +{{/html}}\n