Änderungen von Dokument Get Started
Zuletzt geändert von Veronika Kocher am Freitag, 04 Sep. 2026 14:45
Von Version 2.6
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 2.7
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
-
... ... @@ -387,15 +387,104 @@ 387 387 </div> 388 388 {{/html}} 389 389 390 -{{html clean="false"}} 390 +\n\n 391 +\n\n{{html clean="false"}} 391 391 <!-- SN_HORIZONTAL_BOX_HARMONIZER_START --> 392 -<style data-sn-horizontal-box-harmonizer="4"> 393 -[data-sn-equal-height-managed], 394 -[data-sn-first-section-aligned]{ 393 + 394 +<style data-sn-horizontal-box-harmonizer="7"> 395 +/* ---------- Typography: never justify headings ---------- */ 396 +#xwikicontent h1, 397 +#xwikicontent h2, 398 +#xwikicontent h3, 399 +#xwikicontent h4, 400 +#xwikicontent h5, 401 +#xwikicontent h6, 402 +#xwikicontent .box-title, 403 +#xwikicontent [role="heading"], 404 +#xwikicontent h1 a, 405 +#xwikicontent h2 a, 406 +#xwikicontent h3 a, 407 +#xwikicontent h4 a, 408 +#xwikicontent h5 a, 409 +#xwikicontent h6 a, 410 +#xwikicontent .box-title a, 411 +#xwikicontent [role="heading"] a{ 412 + text-align:left!important; 413 + text-justify:auto!important; 414 + word-spacing:normal!important; 415 +} 416 + 417 +/* ---------- Native XWiki semantic callouts ---------- */ 418 +#xwikicontent .box.infomessage, 419 +#xwikicontent .infomessage, 420 +#xwikicontent .box.warningmessage, 421 +#xwikicontent .warningmessage, 422 +#xwikicontent .box.successmessage, 423 +#xwikicontent .successmessage, 424 +#xwikicontent .box.errormessage, 425 +#xwikicontent .errormessage, 426 +#xwikicontent [data-sn-callout-harmonized="1"]{ 427 + box-sizing:border-box!important; 428 + border-radius:8px!important; 429 + border-top:1px solid rgba(0,0,0,.08)!important; 430 + border-right:1px solid rgba(0,0,0,.08)!important; 431 + border-bottom:1px solid rgba(0,0,0,.08)!important; 432 + border-left:4px solid var(--sn-callout-accent,#21b6d7)!important; 433 + padding:14px 16px!important; 434 + text-align:left!important; 435 + text-justify:auto!important; 436 + word-spacing:normal!important; 437 + box-shadow:none!important; 438 +} 439 + 440 +#xwikicontent .box.infomessage, 441 +#xwikicontent .infomessage{ 442 + --sn-callout-accent:#21b6d7; 443 + background:#eaf7fb!important; 444 +} 445 + 446 +#xwikicontent .box.warningmessage, 447 +#xwikicontent .warningmessage{ 448 + --sn-callout-accent:#f0aa00; 449 + background:#fff8e7!important; 450 +} 451 + 452 +#xwikicontent .box.successmessage, 453 +#xwikicontent .successmessage{ 454 + --sn-callout-accent:#38b76a; 455 + background:#edf9f1!important; 456 +} 457 + 458 +#xwikicontent .box.errormessage, 459 +#xwikicontent .errormessage{ 460 + --sn-callout-accent:#e94b13; 461 + background:#fff1ec!important; 462 +} 463 + 464 +#xwikicontent [data-sn-callout-harmonized="1"] > :first-child, 465 +#xwikicontent .infomessage > :first-child, 466 +#xwikicontent .warningmessage > :first-child, 467 +#xwikicontent .successmessage > :first-child, 468 +#xwikicontent .errormessage > :first-child{ 469 + margin-top:0!important; 470 +} 471 + 472 +#xwikicontent [data-sn-callout-harmonized="1"] > :last-child, 473 +#xwikicontent .infomessage > :last-child, 474 +#xwikicontent .warningmessage > :last-child, 475 +#xwikicontent .successmessage > :last-child, 476 +#xwikicontent .errormessage > :last-child{ 477 + margin-bottom:0!important; 478 +} 479 + 480 +#xwikicontent [data-sn-equal-height-managed], 481 +#xwikicontent [data-sn-first-section-aligned], 482 +#xwikicontent [data-sn-first-content-aligned]{ 395 395 box-sizing:border-box; 396 396 } 397 397 </style> 398 -<script data-sn-horizontal-box-harmonizer="4"> 486 + 487 +<script data-sn-horizontal-box-harmonizer="7"> 399 399 (function(){ 400 400 "use strict"; 401 401 ... ... @@ -403,8 +403,10 @@ 403 403 var ROW_TOLERANCE=6; 404 404 var MIN_W=150; 405 405 var MIN_H=36; 406 - var MAX_PARENT_CHILDREN=1 6;495 + var MAX_PARENT_CHILDREN=18; 407 407 var SEARCH_DEPTH=5; 497 + var RESIZE_DEBOUNCE=220; 498 + var MIN_WIDTH_CHANGE=2; 408 408 409 409 var root= 410 410 document.getElementById("xwikicontent")|| ... ... @@ -416,10 +416,16 @@ 416 416 417 417 var heightManaged=new Set(); 418 418 var sectionManaged=new Set(); 510 + var contentManaged=new Set(); 511 + 419 419 var originalMinHeight=new WeakMap(); 420 420 var originalMarginTop=new WeakMap(); 421 - var raf=0; 422 422 515 + var resizeTimer=0; 516 + var lastWidth=-1; 517 + var hasApplied=false; 518 + var applying=false; 519 + 423 423 function num(v){ 424 424 var n=parseFloat(v); 425 425 return Number.isFinite(n)?n:0; ... ... @@ -446,6 +446,13 @@ 446 446 ); 447 447 } 448 448 546 + function normalizeText(text){ 547 + return String(text||"") 548 + .replace(/\s+/g," ") 549 + .trim() 550 + .toUpperCase(); 551 + } 552 + 449 449 function excluded(el){ 450 450 return ( 451 451 !el.matches|| ... ... @@ -455,57 +455,84 @@ 455 455 ); 456 456 } 457 457 458 - function namedLikeBox(el){ 562 + /* ---------- Custom coloured callouts ---------- */ 563 + 564 + function nativeCallout(el){ 459 459 var c= 460 460 typeof el.className==="string" 461 - ? el.className 567 + ? el.className.toLowerCase() 462 462 : ""; 463 463 464 - return /(^|[s_-])(box|card|tile|panel|role|check|service|source|call|area|detail|resource|topic|warn|info)([s_-]|$)/i.test(c); 570 + return ( 571 + /(^|\s)(infomessage|warningmessage|successmessage|errormessage)(\s|$)/.test(c) 572 + ); 465 465 } 466 466 467 - function boxLike(el){468 - if(!visible(el, MIN_W,MIN_H)||excluded(el))return false;575 + function customCallout(el){ 576 + if(!visible(el,220,42)||excluded(el))return false; 469 469 470 - var s=getComputedStyle(el); 471 471 var r=el.getBoundingClientRect(); 472 472 473 - var border= 474 - num(s.borderTopWidth)+ 475 - num(s.borderRightWidth)+ 476 - num(s.borderBottomWidth)+ 477 - num(s.borderLeftWidth); 580 + if(r.height>520)return false; 478 478 479 - var radius=Math.max( 480 - num(s.borderTopLeftRadius), 481 - num(s.borderTopRightRadius), 482 - num(s.borderBottomLeftRadius), 483 - num(s.borderBottomRightRadius) 484 - ); 582 + var s=getComputedStyle(el); 485 485 486 486 var bg= 487 487 s.backgroundColor&& 488 488 s.backgroundColor!=="rgba(0, 0, 0, 0)"&& 489 - s.backgroundColor!=="transparent"; 587 + s.backgroundColor!=="transparent"&& 588 + s.backgroundColor!=="rgb(255, 255, 255)"; 490 490 491 - var shadow= 492 - s.boxShadow&& 493 - s.boxShadow!=="none"; 590 + var left= 591 + num(s.borderLeftWidth); 494 494 495 495 return ( 496 - namedLikeBox(el)|| 497 - border>=1|| 498 - (bg&&radius>=3)|| 499 - (shadow&&r.width>=180) 594 + bg&& 595 + left>=2 500 500 ); 501 501 } 502 502 599 + function harmoniseCustomCallouts(){ 600 + Array.from( 601 + root.querySelectorAll( 602 + "div,aside,section" 603 + ) 604 + ).forEach(function(el){ 605 + if(nativeCallout(el))return; 606 + if(!customCallout(el))return; 607 + 608 + var s=getComputedStyle(el); 609 + 610 + el.setAttribute( 611 + "data-sn-callout-harmonized", 612 + "1" 613 + ); 614 + 615 + if( 616 + s.borderLeftColor 617 + ){ 618 + el.style.setProperty( 619 + "--sn-callout-accent", 620 + s.borderLeftColor 621 + ); 622 + } 623 + }); 624 + } 625 + 626 + /* ---------- Restore only values V7 itself changed ---------- */ 627 + 503 503 function saveOriginal(el,map,property){ 504 504 if(map.has(el))return; 505 505 506 506 map.set(el,{ 507 - value:el.style.getPropertyValue(property), 508 - priority:el.style.getPropertyPriority(property) 632 + value: 633 + el.style.getPropertyValue( 634 + property 635 + ), 636 + priority: 637 + el.style.getPropertyPriority( 638 + property 639 + ) 509 509 }); 510 510 } 511 511 ... ... @@ -519,11 +519,13 @@ 519 519 original.priority||"" 520 520 ); 521 521 }else{ 522 - el.style.removeProperty(property); 653 + el.style.removeProperty( 654 + property 655 + ); 523 523 } 524 524 } 525 525 526 - function reset(){ 659 + function resetRuntime(){ 527 527 heightManaged.forEach(function(el){ 528 528 restoreOriginal( 529 529 el, ... ... @@ -548,16 +548,79 @@ 548 548 ); 549 549 }); 550 550 684 + contentManaged.forEach(function(el){ 685 + restoreOriginal( 686 + el, 687 + originalMarginTop, 688 + "margin-top" 689 + ); 690 + 691 + el.removeAttribute( 692 + "data-sn-first-content-aligned" 693 + ); 694 + }); 695 + 551 551 heightManaged.clear(); 552 552 sectionManaged.clear(); 698 + contentManaged.clear(); 553 553 } 554 554 701 + /* ---------- Card detection ---------- */ 702 + 703 + function namedLikeBox(el){ 704 + var c= 705 + typeof el.className==="string" 706 + ? el.className 707 + : ""; 708 + 709 + return /(^|[\s_-])(box|card|tile|panel|role|check|service|source|call|area|detail|resource|topic|warn|info)([\s_-]|$)/i.test(c); 710 + } 711 + 712 + function boxLike(el){ 713 + if( 714 + !visible(el,MIN_W,MIN_H)|| 715 + excluded(el) 716 + ){ 717 + return false; 718 + } 719 + 720 + var s=getComputedStyle(el); 721 + var r=el.getBoundingClientRect(); 722 + 723 + var border= 724 + num(s.borderTopWidth)+ 725 + num(s.borderRightWidth)+ 726 + num(s.borderBottomWidth)+ 727 + num(s.borderLeftWidth); 728 + 729 + var radius=Math.max( 730 + num(s.borderTopLeftRadius), 731 + num(s.borderTopRightRadius), 732 + num(s.borderBottomLeftRadius), 733 + num(s.borderBottomRightRadius) 734 + ); 735 + 736 + var bg= 737 + s.backgroundColor&& 738 + s.backgroundColor!=="rgba(0, 0, 0, 0)"&& 739 + s.backgroundColor!=="transparent"; 740 + 741 + var shadow= 742 + s.boxShadow&& 743 + s.boxShadow!=="none"; 744 + 745 + return ( 746 + namedLikeBox(el)|| 747 + border>=1|| 748 + (bg&&radius>=3)|| 749 + (shadow&&r.width>=180) 750 + ); 751 + } 752 + 555 555 function pickTarget(child){ 556 556 if(!visible(child,MIN_W,MIN_H))return null; 557 557 558 - if(boxLike(child)){ 559 - return child; 560 - } 756 + if(boxLike(child))return child; 561 561 562 562 var cr=child.getBoundingClientRect(); 563 563 var q=[]; ... ... @@ -619,7 +619,7 @@ 619 619 return best; 620 620 } 621 621 622 - function group sByVisualRow(entries){818 + function groupRows(entries){ 623 623 var groups=[]; 624 624 625 625 entries ... ... @@ -659,7 +659,7 @@ 659 659 return groups; 660 660 } 661 661 662 - function valid HorizontalGroup(group){858 + function validRow(group){ 663 663 if(group.entries.length<2)return false; 664 664 665 665 var lefts= ... ... @@ -682,25 +682,26 @@ 682 682 683 683 if(widths.length<2)return false; 684 684 685 - var minW idth=Math.min.apply(Math,widths);686 - varmaxWidth=Math.max.apply(Math,widths);881 + var minW= 882 + Math.min.apply(Math,widths); 687 687 884 + var maxW= 885 + Math.max.apply(Math,widths); 886 + 688 688 return ( 689 - maxW idth/690 - Math.max(1,minW idth)<=888 + maxW/ 889 + Math.max(1,minW)<= 691 691 1.9 692 692 ); 693 693 } 694 694 695 - function normalizeText(text){ 696 - return String(text||"") 697 - .replace(/s+/g," ") 698 - .trim() 699 - .toUpperCase(); 700 - } 894 + /* ---------- Known ARSN first section bars ---------- */ 701 701 702 - function exactKnownFirstSection(el){ 703 - var text=normalizeText(el.textContent); 896 + function knownBar(el){ 897 + var text= 898 + normalizeText( 899 + el.textContent 900 + ); 704 704 705 705 return ( 706 706 text==="HIER STARTEN"|| ... ... @@ -714,150 +714,274 @@ 714 714 ); 715 715 } 716 716 717 - function visuallyFirstSectionBar(card){718 - var cardRect= card.getBoundingClientRect();719 - varcandidates=[];914 + function findKnownBar(card){ 915 + var cardRect= 916 + card.getBoundingClientRect(); 720 720 721 - Array.from( 722 - card.querySelectorAll( 723 - "div,p,span,strong,h3,h4,h5,h6" 918 + var rows= 919 + Array.from( 920 + card.querySelectorAll( 921 + "div,p,span,strong,h3,h4,h5,h6" 922 + ) 724 724 ) 725 - ).forEach(function(el){726 - if(!visible(el,20,6))return; 727 - if( excluded(el))return;924 + .filter(function(el){ 925 + if(!visible(el,20,6))return false; 926 + if(!knownBar(el))return false; 728 728 729 - var r=el.getBoundingClientRect(); 730 - var relativeTop=r.top-cardRect.top; 928 + var r=el.getBoundingClientRect(); 731 731 732 - if( 733 - relativeTop<45|| 734 - relativeTop>cardRect.height*.72 735 - ){ 736 - return; 737 - } 930 + var rel= 931 + r.top- 932 + cardRect.top; 738 738 739 - var widthRatio= 740 - r.width/ 741 - Math.max(1,cardRect.width); 934 + return ( 935 + rel>=35&& 936 + rel<= 937 + cardRect.height*.75 938 + ); 939 + }) 940 + .sort(function(a,b){ 941 + return ( 942 + a.getBoundingClientRect().top- 943 + b.getBoundingClientRect().top 944 + ); 945 + }); 742 742 743 - if( 744 - widthRatio<.55|| 745 - widthRatio>1.05|| 746 - r.height>54 747 - ){ 748 - return; 749 - } 947 + return rows[0]||null; 948 + } 750 750 751 - var text=normalizeText(el.textContent); 950 + function alignKnownBars(cards){ 951 + var rows= 952 + cards.map(function(card){ 953 + var bar= 954 + findKnownBar(card); 752 752 753 - if( 754 - text.length<2|| 755 - text.length>90 756 - ){ 757 - return; 758 - } 956 + if(!bar)return null; 759 759 760 - var style=getComputedStyle(el); 958 + var cr= 959 + card.getBoundingClientRect(); 761 761 762 - var bg= 763 - style.backgroundColor&& 764 - style.backgroundColor!=="rgba(0, 0, 0, 0)"&& 765 - style.backgroundColor!=="transparent"; 961 + var br= 962 + bar.getBoundingClientRect(); 766 766 767 - var border= 768 - num(style.borderTopWidth)+ 769 - num(style.borderRightWidth)+ 770 - num(style.borderBottomWidth)+ 771 - num(style.borderLeftWidth); 964 + return { 965 + bar:bar, 966 + relativeTop: 967 + br.top- 968 + cr.top 969 + }; 970 + }); 772 772 773 - var mostlyUpper= 774 - text.length>=3&& 775 - text===text.toUpperCase(); 972 + if( 973 + rows.some(function(row){ 974 + return !row; 975 + }) 976 + ){ 977 + return false; 978 + } 776 776 777 - var exact=exactKnownFirstSection(el); 980 + var target= 981 + Math.max.apply( 982 + Math, 983 + rows.map(function(row){ 984 + return row.relativeTop; 985 + }) 986 + ); 778 778 779 - var score= 780 - (exact?20:0)+ 781 - (bg?6:0)+ 782 - (border>=1?2:0)+ 783 - (mostlyUpper?4:0)+ 784 - (num(style.fontWeight)>=600?1:0); 988 + rows.forEach(function(row){ 989 + var delta= 990 + target- 991 + row.relativeTop; 785 785 786 - if(score>=7){ 787 - candidates.push({ 788 - el:el, 789 - relativeTop:relativeTop, 790 - width:r.width, 791 - score:score 792 - }); 793 - } 794 - }); 993 + if(delta<=1)return; 795 795 796 - if(!candidates.length)return null; 995 + saveOriginal( 996 + row.bar, 997 + originalMarginTop, 998 + "margin-top" 999 + ); 797 797 798 - candidates.sort(function(a,b){ 799 - if(a.score!==b.score)return b.score-a.score; 800 - if(Math.abs(a.relativeTop-b.relativeTop)>3){ 801 - return a.relativeTop-b.relativeTop; 802 - } 803 - return b.width-a.width; 804 - }); 1001 + var current= 1002 + num( 1003 + getComputedStyle( 1004 + row.bar 1005 + ).marginTop 1006 + ); 805 805 806 - // For exact known labels always prefer the earliest exact match. 807 - var exacts=candidates.filter(function(c){ 808 - return exactKnownFirstSection(c.el); 1008 + row.bar.style.setProperty( 1009 + "margin-top", 1010 + ( 1011 + current+ 1012 + delta 1013 + )+"px" 1014 + ); 1015 + 1016 + row.bar.setAttribute( 1017 + "data-sn-first-section-aligned", 1018 + "7" 1019 + ); 1020 + 1021 + sectionManaged.add( 1022 + row.bar 1023 + ); 809 809 }); 810 810 811 - if(exacts.length){ 812 - exacts.sort(function(a,b){ 813 - return a.relativeTop-b.relativeTop||b.width-a.width; 1026 + return true; 1027 + } 1028 + 1029 + /* ---------- Generic first content after heading ---------- */ 1030 + 1031 + function heading(card){ 1032 + var cr= 1033 + card.getBoundingClientRect(); 1034 + 1035 + var rows= 1036 + Array.from( 1037 + card.querySelectorAll( 1038 + "h1,h2,h3,h4,h5,h6,.box-title,[role=heading]" 1039 + ) 1040 + ) 1041 + .filter(function(el){ 1042 + if(!visible(el,20,8))return false; 1043 + 1044 + var r=el.getBoundingClientRect(); 1045 + 1046 + var rel= 1047 + r.top- 1048 + cr.top; 1049 + 1050 + return ( 1051 + rel>=0&& 1052 + rel<= 1053 + Math.min( 1054 + 160, 1055 + cr.height*.45 1056 + ) 1057 + ); 1058 + }) 1059 + .sort(function(a,b){ 1060 + return ( 1061 + a.getBoundingClientRect().top- 1062 + b.getBoundingClientRect().top 1063 + ); 814 814 }); 815 - return exacts[0].el; 816 - } 817 817 818 - // Generic fallback: earliest high-confidence bar. 819 - candidates.sort(function(a,b){ 820 - return a.relativeTop-b.relativeTop||b.score-a.score||b.width-a.width; 821 - }); 1066 + return rows[0]||null; 1067 + } 822 822 823 - return candidates[0].el; 1069 + function firstContent(card,h){ 1070 + if(!h)return null; 1071 + 1072 + var cr= 1073 + card.getBoundingClientRect(); 1074 + 1075 + var hr= 1076 + h.getBoundingClientRect(); 1077 + 1078 + var rows= 1079 + Array.from( 1080 + card.querySelectorAll( 1081 + "p,div,ul,ol,dl,blockquote" 1082 + ) 1083 + ) 1084 + .filter(function(el){ 1085 + if( 1086 + el===h|| 1087 + h.contains(el)|| 1088 + el.contains(h) 1089 + ){ 1090 + return false; 1091 + } 1092 + 1093 + if(!visible(el,30,8))return false; 1094 + 1095 + var text= 1096 + String(el.textContent||"") 1097 + .replace(/\s+/g," ") 1098 + .trim(); 1099 + 1100 + if(text.length<3)return false; 1101 + 1102 + var r=el.getBoundingClientRect(); 1103 + 1104 + if( 1105 + r.top< 1106 + hr.bottom-1 1107 + ){ 1108 + return false; 1109 + } 1110 + 1111 + if( 1112 + r.top-cr.top> 1113 + Math.min( 1114 + 280, 1115 + cr.height*.65 1116 + ) 1117 + ){ 1118 + return false; 1119 + } 1120 + 1121 + if( 1122 + r.height> 1123 + cr.height*.58 1124 + ){ 1125 + return false; 1126 + } 1127 + 1128 + return true; 1129 + }) 1130 + .sort(function(a,b){ 1131 + var ar= 1132 + a.getBoundingClientRect(); 1133 + 1134 + var br= 1135 + b.getBoundingClientRect(); 1136 + 1137 + return ( 1138 + ar.top-br.top|| 1139 + ar.height-br.height 1140 + ); 1141 + }); 1142 + 1143 + return rows[0]||null; 824 824 } 825 825 826 - function align FirstSections(cards){1146 + function alignGeneric(cards){ 827 827 var rows= 828 828 cards.map(function(card){ 829 - var bar=830 - visuallyFirstSectionBar(card);1149 + var h= 1150 + heading(card); 831 831 832 - if(!bar)return null; 1152 + var c= 1153 + firstContent( 1154 + card, 1155 + h 1156 + ); 833 833 834 - var cardRect= 1158 + if(!h||!c)return null; 1159 + 1160 + var cr= 835 835 card.getBoundingClientRect(); 836 836 837 - var barRect=838 - bar.getBoundingClientRect();1163 + var rr= 1164 + c.getBoundingClientRect(); 839 839 840 840 return { 841 - card:card, 842 - bar:bar, 1167 + content:c, 843 843 relativeTop: 844 - barRect.top-cardRect.top, 845 - label: 846 - normalizeText(bar.textContent) 1169 + rr.top-cr.top 847 847 }; 848 848 }); 849 849 850 - // Conservative: only align when every card in the horizontal row 851 - // has a reliable first section bar. 852 852 if( 853 853 rows.some(function(row){ 854 854 return !row; 855 855 }) 856 856 ){ 857 - return null;1178 + return false; 858 858 } 859 859 860 - var target Top=1181 + var target= 861 861 Math.max.apply( 862 862 Math, 863 863 rows.map(function(row){ ... ... @@ -867,54 +867,47 @@ 867 867 868 868 rows.forEach(function(row){ 869 869 var delta= 870 - target Top-1191 + target- 871 871 row.relativeTop; 872 872 873 873 if(delta<=1)return; 874 874 875 875 saveOriginal( 876 - row. bar,1197 + row.content, 877 877 originalMarginTop, 878 878 "margin-top" 879 879 ); 880 880 881 - var current Margin=1202 + var current= 882 882 num( 883 883 getComputedStyle( 884 - row. bar1205 + row.content 885 885 ).marginTop 886 886 ); 887 887 888 - row. bar.style.setProperty(1209 + row.content.style.setProperty( 889 889 "margin-top", 890 890 ( 891 - current Margin+1212 + current+ 892 892 delta 893 893 )+"px" 894 894 ); 895 895 896 - row. bar.setAttribute(897 - "data-sn-first- section-aligned",898 - " 4"1217 + row.content.setAttribute( 1218 + "data-sn-first-content-aligned", 1219 + "7" 899 899 ); 900 900 901 - sectionManaged.add(row.bar); 1222 + contentManaged.add( 1223 + row.content 1224 + ); 902 902 }); 903 903 904 - return { 905 - labels: 906 - rows.map(function(row){ 907 - return row.label; 908 - }), 909 - targetRelativeTop: 910 - Math.round(targetTop) 911 - }; 1227 + return true; 912 912 } 913 913 914 - function applyGroup(group){ 915 - if(!validHorizontalGroup(group)){ 916 - return null; 917 - } 1230 + function applyRow(group){ 1231 + if(!validRow(group))return false; 918 918 919 919 var cards=[]; 920 920 var seen=new Set(); ... ... @@ -926,25 +926,30 @@ 926 926 } 927 927 }); 928 928 929 - if(cards.length<2)return null;1243 + if(cards.length<2)return false; 930 930 931 - var firstSection= 932 - alignFirstSections(cards); 1245 + if( 1246 + !alignKnownBars(cards) 1247 + ){ 1248 + alignGeneric(cards); 1249 + } 933 933 934 - // The section alignment can change natural card heights. 935 - // Measure only afterwards. 936 936 var maxHeight=0; 937 937 938 938 cards.forEach(function(card){ 939 - maxHeight=Math.max( 940 - maxHeight, 941 - card.getBoundingClientRect().height 942 - ); 1254 + maxHeight= 1255 + Math.max( 1256 + maxHeight, 1257 + card.getBoundingClientRect().height 1258 + ); 943 943 }); 944 944 945 - maxHeight=Math.ceil(maxHeight); 1261 + maxHeight= 1262 + Math.ceil( 1263 + maxHeight 1264 + ); 946 946 947 - if(maxHeight<MIN_H)return null;1266 + if(maxHeight<MIN_H)return false; 948 948 949 949 cards.forEach(function(card){ 950 950 saveOriginal( ... ... @@ -960,125 +960,228 @@ 960 960 961 961 card.setAttribute( 962 962 "data-sn-equal-height-managed", 963 - " 4"1282 + "7" 964 964 ); 965 965 966 966 heightManaged.add(card); 967 967 }); 968 968 969 - return { 970 - cards:cards.length, 971 - height:maxHeight, 972 - firstSection:firstSection 973 - }; 1288 + return true; 974 974 } 975 975 976 - function run(){977 - re set();1291 + function calculate(force){ 1292 + if(applying)return; 978 978 1294 + var width= 1295 + Math.round( 1296 + window.innerWidth 1297 + ); 1298 + 1299 + var meaningful= 1300 + lastWidth<0|| 1301 + Math.abs( 1302 + width- 1303 + lastWidth 1304 + )>= 1305 + MIN_WIDTH_CHANGE; 1306 + 979 979 if( 980 - window.innerWidth<=MOBILE_MAX 1308 + hasApplied&& 1309 + !force&& 1310 + !meaningful 981 981 ){ 982 982 return; 983 983 } 984 984 985 - var parents= 986 - Array.from( 987 - root.querySelectorAll("*") 988 - ).filter(function(parent){ 989 - return ( 990 - visible(parent,MIN_W,MIN_H)&& 991 - parent.children&& 992 - parent.children.length>=2&& 993 - parent.children.length<=MAX_PARENT_CHILDREN 994 - ); 995 - }); 1315 + applying=true; 996 996 997 - var touched=new Set(); 1317 + try{ 1318 + harmoniseCustomCallouts(); 998 998 999 - parents.forEach(function(parent){ 1000 - var entries=[]; 1320 + if(width<=MOBILE_MAX){ 1321 + if(hasApplied){ 1322 + resetRuntime(); 1323 + } 1001 1001 1002 - Array.from(parent.children).forEach(function(child){ 1003 - if(!visible(child,MIN_W,MIN_H))return; 1325 + hasApplied=false; 1326 + lastWidth=width; 1327 + return; 1328 + } 1004 1004 1005 - var target=pickTarget(child); 1006 - if(!target)return; 1330 + if(hasApplied){ 1331 + resetRuntime(); 1332 + } 1007 1007 1008 - entries.push({ 1009 - target:target, 1010 - rect:target.getBoundingClientRect() 1334 + var parents= 1335 + Array.from( 1336 + root.querySelectorAll("*") 1337 + ) 1338 + .filter(function(parent){ 1339 + return ( 1340 + visible( 1341 + parent, 1342 + MIN_W, 1343 + MIN_H 1344 + )&& 1345 + parent.children&& 1346 + parent.children.length>=2&& 1347 + parent.children.length<= 1348 + MAX_PARENT_CHILDREN 1349 + ); 1011 1011 }); 1012 - }); 1013 1013 1014 - if(entries.length<2)return; 1352 + var touched= 1353 + new Set(); 1015 1015 1016 - groupsByVisualRow(entries).forEach(function(group){1017 - if(!validHorizontalGroup(group))return;1355 + parents.forEach(function(parent){ 1356 + var entries=[]; 1018 1018 1019 - var signature= 1020 - group.entries.map(function(entry){ 1021 - return entry.target; 1022 - }); 1358 + Array.from( 1359 + parent.children 1360 + ).forEach(function(child){ 1361 + if( 1362 + !visible( 1363 + child, 1364 + MIN_W, 1365 + MIN_H 1366 + ) 1367 + ){ 1368 + return; 1369 + } 1023 1023 1024 - if( 1025 - !signature.some(function(el){ 1026 - return !touched.has(el); 1027 - }) 1028 - ){ 1029 - return; 1030 - } 1371 + var target= 1372 + pickTarget(child); 1031 1031 1032 - var applied= 1033 - applyGroup(group); 1374 + if(!target)return; 1034 1034 1035 - if(applied){ 1036 - signature.forEach(function(el){ 1037 - touched.add(el); 1376 + entries.push({ 1377 + target:target, 1378 + rect: 1379 + target.getBoundingClientRect() 1038 1038 }); 1039 - } 1381 + }); 1382 + 1383 + groupRows( 1384 + entries 1385 + ).forEach(function(group){ 1386 + if(!validRow(group))return; 1387 + 1388 + var targets= 1389 + group.entries.map(function(entry){ 1390 + return entry.target; 1391 + }); 1392 + 1393 + if( 1394 + !targets.some(function(el){ 1395 + return !touched.has(el); 1396 + }) 1397 + ){ 1398 + return; 1399 + } 1400 + 1401 + if(applyRow(group)){ 1402 + targets.forEach(function(el){ 1403 + touched.add(el); 1404 + }); 1405 + } 1406 + }); 1040 1040 }); 1041 - }); 1408 + 1409 + lastWidth=width; 1410 + hasApplied=true; 1411 + }finally{ 1412 + applying=false; 1413 + } 1042 1042 } 1043 1043 1044 - function schedule(){ 1045 - if(raf)cancelAnimationFrame(raf); 1416 + function resize(){ 1417 + if(resizeTimer){ 1418 + clearTimeout( 1419 + resizeTimer 1420 + ); 1421 + } 1046 1046 1047 - raf=requestAnimationFrame(function(){ 1048 - raf=requestAnimationFrame(function(){ 1049 - raf=0; 1050 - run(); 1051 - }); 1052 - }); 1423 + resizeTimer= 1424 + setTimeout( 1425 + function(){ 1426 + resizeTimer=0; 1427 + calculate(false); 1428 + }, 1429 + RESIZE_DEBOUNCE 1430 + ); 1053 1053 } 1054 1054 1055 - addEventListener("resize",schedule,{passive:true}); 1056 - addEventListener("load",schedule,{once:true}); 1433 + function waitImages(){ 1434 + var images= 1435 + Array.from( 1436 + root.querySelectorAll("img") 1437 + ); 1057 1057 1058 - root.addEventListener( 1059 - "click", 1060 - function(){ 1061 - setTimeout(schedule,0); 1062 - }, 1063 - true 1064 - ); 1439 + return Promise.all( 1440 + images.map(function(img){ 1441 + if(img.complete){ 1442 + return Promise.resolve(); 1443 + } 1065 1065 1066 - Array.from(root.querySelectorAll("img")).forEach(function(img){ 1067 - if(!img.complete){ 1068 - img.addEventListener("load",schedule,{once:true}); 1445 + return new Promise(function(resolve){ 1446 + var done=function(){ 1447 + resolve(); 1448 + }; 1449 + 1450 + img.addEventListener( 1451 + "load", 1452 + done, 1453 + {once:true} 1454 + ); 1455 + 1456 + img.addEventListener( 1457 + "error", 1458 + done, 1459 + {once:true} 1460 + ); 1461 + }); 1462 + }) 1463 + ); 1464 + } 1465 + 1466 + async function initial(){ 1467 + if( 1468 + document.readyState!== 1469 + "complete" 1470 + ){ 1471 + await new Promise(function(resolve){ 1472 + addEventListener( 1473 + "load", 1474 + resolve, 1475 + {once:true} 1476 + ); 1477 + }); 1069 1069 } 1070 - }); 1071 1071 1072 - if(document.fonts&&document.fonts.ready){ 1073 - document.fonts.ready.then(schedule); 1480 + if( 1481 + document.fonts&& 1482 + document.fonts.ready 1483 + ){ 1484 + try{ 1485 + await document.fonts.ready; 1486 + }catch(error){} 1487 + } 1488 + 1489 + await waitImages(); 1490 + 1491 + // Exactly one initial layout calculation. 1492 + calculate(true); 1074 1074 } 1075 1075 1076 - schedule(); 1077 - setTimeout(schedule,200); 1078 - setTimeout(schedule,650); 1079 - setTimeout(schedule,1400); 1495 + addEventListener( 1496 + "resize", 1497 + resize, 1498 + {passive:true} 1499 + ); 1500 + 1501 + initial(); 1080 1080 })(); 1081 1081 </script> 1082 -<!-- SN_HORIZONTAL_BOX_HARMONIZER_END --> 1083 -{{/html}} 1084 1084 1505 +<!-- SN_HORIZONTAL_BOX_HARMONIZER_END --> 1506 +{{/html}}\n