Changes for page Prepare

Last modified by Veronika Kocher on Friday, 18 Sep 2026 16:47

From version 29.6
edited by Veronika Kocher
on Wednesday, 02 Sep 2026 16:48
Change comment: There is no comment for this version
To version 29.8
edited by Veronika Kocher
on Thursday, 03 Sep 2026 9:34
Change comment: There is no comment for this version

Summary

Details

Page properties
Content
... ... @@ -484,3 +484,699 @@
484 484  
485 485  </div>
486 486  {{/html}}
487 +
488 +{{html clean="false"}}
489 +<!-- SN_HORIZONTAL_BOX_HARMONIZER_START -->
490 +<style data-sn-horizontal-box-harmonizer="4">
491 +[data-sn-equal-height-managed],
492 +[data-sn-first-section-aligned]{
493 + box-sizing:border-box;
494 +}
495 +</style>
496 +<script data-sn-horizontal-box-harmonizer="4">
497 +(function(){
498 + "use strict";
499 +
500 + var MOBILE_MAX=767;
501 + var ROW_TOLERANCE=6;
502 + var MIN_W=150;
503 + var MIN_H=36;
504 + var MAX_PARENT_CHILDREN=16;
505 + var SEARCH_DEPTH=5;
506 +
507 + var root=
508 + document.getElementById("xwikicontent")||
509 + document.querySelector(".xwiki-rendering-content")||
510 + document.querySelector("main")||
511 + document.body;
512 +
513 + if(!root)return;
514 +
515 + var heightManaged=new Set();
516 + var sectionManaged=new Set();
517 + var originalMinHeight=new WeakMap();
518 + var originalMarginTop=new WeakMap();
519 + var raf=0;
520 +
521 + function num(v){
522 + var n=parseFloat(v);
523 + return Number.isFinite(n)?n:0;
524 + }
525 +
526 + function visible(el,minW,minH){
527 + if(!el||el.nodeType!==1)return false;
528 +
529 + var s=getComputedStyle(el);
530 +
531 + if(
532 + s.display==="none"||
533 + s.visibility==="hidden"||
534 + Number(s.opacity)===0
535 + ){
536 + return false;
537 + }
538 +
539 + var r=el.getBoundingClientRect();
540 +
541 + return (
542 + r.width>=(minW||1)&&
543 + r.height>=(minH||1)
544 + );
545 + }
546 +
547 + function excluded(el){
548 + return (
549 + !el.matches||
550 + el.matches(
551 + "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]"
552 + )
553 + );
554 + }
555 +
556 + function namedLikeBox(el){
557 + var c=
558 + typeof el.className==="string"
559 + ? el.className
560 + : "";
561 +
562 + return /(^|[s_-])(box|card|tile|panel|role|check|service|source|call|area|detail|resource|topic|warn|info)([s_-]|$)/i.test(c);
563 + }
564 +
565 + function boxLike(el){
566 + if(!visible(el,MIN_W,MIN_H)||excluded(el))return false;
567 +
568 + var s=getComputedStyle(el);
569 + var r=el.getBoundingClientRect();
570 +
571 + var border=
572 + num(s.borderTopWidth)+
573 + num(s.borderRightWidth)+
574 + num(s.borderBottomWidth)+
575 + num(s.borderLeftWidth);
576 +
577 + var radius=Math.max(
578 + num(s.borderTopLeftRadius),
579 + num(s.borderTopRightRadius),
580 + num(s.borderBottomLeftRadius),
581 + num(s.borderBottomRightRadius)
582 + );
583 +
584 + var bg=
585 + s.backgroundColor&&
586 + s.backgroundColor!=="rgba(0, 0, 0, 0)"&&
587 + s.backgroundColor!=="transparent";
588 +
589 + var shadow=
590 + s.boxShadow&&
591 + s.boxShadow!=="none";
592 +
593 + return (
594 + namedLikeBox(el)||
595 + border>=1||
596 + (bg&&radius>=3)||
597 + (shadow&&r.width>=180)
598 + );
599 + }
600 +
601 + function saveOriginal(el,map,property){
602 + if(map.has(el))return;
603 +
604 + map.set(el,{
605 + value:el.style.getPropertyValue(property),
606 + priority:el.style.getPropertyPriority(property)
607 + });
608 + }
609 +
610 + function restoreOriginal(el,map,property){
611 + var original=map.get(el);
612 +
613 + if(original&&original.value){
614 + el.style.setProperty(
615 + property,
616 + original.value,
617 + original.priority||""
618 + );
619 + }else{
620 + el.style.removeProperty(property);
621 + }
622 + }
623 +
624 + function reset(){
625 + heightManaged.forEach(function(el){
626 + restoreOriginal(
627 + el,
628 + originalMinHeight,
629 + "min-height"
630 + );
631 +
632 + el.removeAttribute(
633 + "data-sn-equal-height-managed"
634 + );
635 + });
636 +
637 + sectionManaged.forEach(function(el){
638 + restoreOriginal(
639 + el,
640 + originalMarginTop,
641 + "margin-top"
642 + );
643 +
644 + el.removeAttribute(
645 + "data-sn-first-section-aligned"
646 + );
647 + });
648 +
649 + heightManaged.clear();
650 + sectionManaged.clear();
651 + }
652 +
653 + function pickTarget(child){
654 + if(!visible(child,MIN_W,MIN_H))return null;
655 +
656 + if(boxLike(child)){
657 + return child;
658 + }
659 +
660 + var cr=child.getBoundingClientRect();
661 + var q=[];
662 +
663 + Array.from(child.children||[]).forEach(function(el){
664 + q.push({el:el,depth:1});
665 + });
666 +
667 + var best=null;
668 + var bestScore=-Infinity;
669 +
670 + while(q.length){
671 + var item=q.shift();
672 + var el=item.el;
673 +
674 + if(!visible(el,MIN_W,MIN_H))continue;
675 +
676 + var r=el.getBoundingClientRect();
677 +
678 + if(
679 + r.width>=cr.width*.68&&
680 + boxLike(el)
681 + ){
682 + var widthFit=
683 + 1-Math.min(
684 + 1,
685 + Math.abs(cr.width-r.width)/
686 + Math.max(1,cr.width)
687 + );
688 +
689 + var topFit=
690 + 1-Math.min(
691 + 1,
692 + Math.abs(cr.top-r.top)/100
693 + );
694 +
695 + var score=
696 + widthFit*6+
697 + topFit*3+
698 + Math.min(r.height,900)/450+
699 + Math.min(r.width*r.height,900000)/900000;
700 +
701 + if(score>bestScore){
702 + best=el;
703 + bestScore=score;
704 + }
705 + }
706 +
707 + if(item.depth<SEARCH_DEPTH){
708 + Array.from(el.children||[]).forEach(function(next){
709 + q.push({
710 + el:next,
711 + depth:item.depth+1
712 + });
713 + });
714 + }
715 + }
716 +
717 + return best;
718 + }
719 +
720 + function groupsByVisualRow(entries){
721 + var groups=[];
722 +
723 + entries
724 + .slice()
725 + .sort(function(a,b){
726 + return (
727 + a.rect.top-b.rect.top||
728 + a.rect.left-b.rect.left
729 + );
730 + })
731 + .forEach(function(entry){
732 + var group=null;
733 +
734 + for(var i=0;i<groups.length;i++){
735 + if(
736 + Math.abs(
737 + groups[i].top-
738 + entry.rect.top
739 + )<=ROW_TOLERANCE
740 + ){
741 + group=groups[i];
742 + break;
743 + }
744 + }
745 +
746 + if(!group){
747 + group={
748 + top:entry.rect.top,
749 + entries:[]
750 + };
751 + groups.push(group);
752 + }
753 +
754 + group.entries.push(entry);
755 + });
756 +
757 + return groups;
758 + }
759 +
760 + function validHorizontalGroup(group){
761 + if(group.entries.length<2)return false;
762 +
763 + var lefts=
764 + group.entries
765 + .map(function(e){return e.rect.left;})
766 + .sort(function(a,b){return a-b;});
767 +
768 + if(
769 + lefts[lefts.length-1]-
770 + lefts[0]<
771 + 80
772 + ){
773 + return false;
774 + }
775 +
776 + var widths=
777 + group.entries
778 + .map(function(e){return e.rect.width;})
779 + .filter(function(w){return w>0;});
780 +
781 + if(widths.length<2)return false;
782 +
783 + var minWidth=Math.min.apply(Math,widths);
784 + var maxWidth=Math.max.apply(Math,widths);
785 +
786 + return (
787 + maxWidth/
788 + Math.max(1,minWidth)<=
789 + 1.9
790 + );
791 + }
792 +
793 + function normalizeText(text){
794 + return String(text||"")
795 + .replace(/s+/g," ")
796 + .trim()
797 + .toUpperCase();
798 + }
799 +
800 + function exactKnownFirstSection(el){
801 + var text=normalizeText(el.textContent);
802 +
803 + return (
804 + text==="HIER STARTEN"||
805 + text==="ORGANISIEREN & DOKUMENTIEREN"||
806 + text==="ENTSCHEIDEN"||
807 + text==="START HERE"||
808 + text==="GET STARTED"||
809 + text==="ORGANISE & DOCUMENT"||
810 + text==="ORGANIZE & DOCUMENT"||
811 + text==="DECIDE"
812 + );
813 + }
814 +
815 + function visuallyFirstSectionBar(card){
816 + var cardRect=card.getBoundingClientRect();
817 + var candidates=[];
818 +
819 + Array.from(
820 + card.querySelectorAll(
821 + "div,p,span,strong,h3,h4,h5,h6"
822 + )
823 + ).forEach(function(el){
824 + if(!visible(el,20,6))return;
825 + if(excluded(el))return;
826 +
827 + var r=el.getBoundingClientRect();
828 + var relativeTop=r.top-cardRect.top;
829 +
830 + if(
831 + relativeTop<45||
832 + relativeTop>cardRect.height*.72
833 + ){
834 + return;
835 + }
836 +
837 + var widthRatio=
838 + r.width/
839 + Math.max(1,cardRect.width);
840 +
841 + if(
842 + widthRatio<.55||
843 + widthRatio>1.05||
844 + r.height>54
845 + ){
846 + return;
847 + }
848 +
849 + var text=normalizeText(el.textContent);
850 +
851 + if(
852 + text.length<2||
853 + text.length>90
854 + ){
855 + return;
856 + }
857 +
858 + var style=getComputedStyle(el);
859 +
860 + var bg=
861 + style.backgroundColor&&
862 + style.backgroundColor!=="rgba(0, 0, 0, 0)"&&
863 + style.backgroundColor!=="transparent";
864 +
865 + var border=
866 + num(style.borderTopWidth)+
867 + num(style.borderRightWidth)+
868 + num(style.borderBottomWidth)+
869 + num(style.borderLeftWidth);
870 +
871 + var mostlyUpper=
872 + text.length>=3&&
873 + text===text.toUpperCase();
874 +
875 + var exact=exactKnownFirstSection(el);
876 +
877 + var score=
878 + (exact?20:0)+
879 + (bg?6:0)+
880 + (border>=1?2:0)+
881 + (mostlyUpper?4:0)+
882 + (num(style.fontWeight)>=600?1:0);
883 +
884 + if(score>=7){
885 + candidates.push({
886 + el:el,
887 + relativeTop:relativeTop,
888 + width:r.width,
889 + score:score
890 + });
891 + }
892 + });
893 +
894 + if(!candidates.length)return null;
895 +
896 + candidates.sort(function(a,b){
897 + if(a.score!==b.score)return b.score-a.score;
898 + if(Math.abs(a.relativeTop-b.relativeTop)>3){
899 + return a.relativeTop-b.relativeTop;
900 + }
901 + return b.width-a.width;
902 + });
903 +
904 + // For exact known labels always prefer the earliest exact match.
905 + var exacts=candidates.filter(function(c){
906 + return exactKnownFirstSection(c.el);
907 + });
908 +
909 + if(exacts.length){
910 + exacts.sort(function(a,b){
911 + return a.relativeTop-b.relativeTop||b.width-a.width;
912 + });
913 + return exacts[0].el;
914 + }
915 +
916 + // Generic fallback: earliest high-confidence bar.
917 + candidates.sort(function(a,b){
918 + return a.relativeTop-b.relativeTop||b.score-a.score||b.width-a.width;
919 + });
920 +
921 + return candidates[0].el;
922 + }
923 +
924 + function alignFirstSections(cards){
925 + var rows=
926 + cards.map(function(card){
927 + var bar=
928 + visuallyFirstSectionBar(card);
929 +
930 + if(!bar)return null;
931 +
932 + var cardRect=
933 + card.getBoundingClientRect();
934 +
935 + var barRect=
936 + bar.getBoundingClientRect();
937 +
938 + return {
939 + card:card,
940 + bar:bar,
941 + relativeTop:
942 + barRect.top-cardRect.top,
943 + label:
944 + normalizeText(bar.textContent)
945 + };
946 + });
947 +
948 + // Conservative: only align when every card in the horizontal row
949 + // has a reliable first section bar.
950 + if(
951 + rows.some(function(row){
952 + return !row;
953 + })
954 + ){
955 + return null;
956 + }
957 +
958 + var targetTop=
959 + Math.max.apply(
960 + Math,
961 + rows.map(function(row){
962 + return row.relativeTop;
963 + })
964 + );
965 +
966 + rows.forEach(function(row){
967 + var delta=
968 + targetTop-
969 + row.relativeTop;
970 +
971 + if(delta<=1)return;
972 +
973 + saveOriginal(
974 + row.bar,
975 + originalMarginTop,
976 + "margin-top"
977 + );
978 +
979 + var currentMargin=
980 + num(
981 + getComputedStyle(
982 + row.bar
983 + ).marginTop
984 + );
985 +
986 + row.bar.style.setProperty(
987 + "margin-top",
988 + (
989 + currentMargin+
990 + delta
991 + )+"px"
992 + );
993 +
994 + row.bar.setAttribute(
995 + "data-sn-first-section-aligned",
996 + "4"
997 + );
998 +
999 + sectionManaged.add(row.bar);
1000 + });
1001 +
1002 + return {
1003 + labels:
1004 + rows.map(function(row){
1005 + return row.label;
1006 + }),
1007 + targetRelativeTop:
1008 + Math.round(targetTop)
1009 + };
1010 + }
1011 +
1012 + function applyGroup(group){
1013 + if(!validHorizontalGroup(group)){
1014 + return null;
1015 + }
1016 +
1017 + var cards=[];
1018 + var seen=new Set();
1019 +
1020 + group.entries.forEach(function(entry){
1021 + if(!seen.has(entry.target)){
1022 + seen.add(entry.target);
1023 + cards.push(entry.target);
1024 + }
1025 + });
1026 +
1027 + if(cards.length<2)return null;
1028 +
1029 + var firstSection=
1030 + alignFirstSections(cards);
1031 +
1032 + // The section alignment can change natural card heights.
1033 + // Measure only afterwards.
1034 + var maxHeight=0;
1035 +
1036 + cards.forEach(function(card){
1037 + maxHeight=Math.max(
1038 + maxHeight,
1039 + card.getBoundingClientRect().height
1040 + );
1041 + });
1042 +
1043 + maxHeight=Math.ceil(maxHeight);
1044 +
1045 + if(maxHeight<MIN_H)return null;
1046 +
1047 + cards.forEach(function(card){
1048 + saveOriginal(
1049 + card,
1050 + originalMinHeight,
1051 + "min-height"
1052 + );
1053 +
1054 + card.style.setProperty(
1055 + "min-height",
1056 + maxHeight+"px"
1057 + );
1058 +
1059 + card.setAttribute(
1060 + "data-sn-equal-height-managed",
1061 + "4"
1062 + );
1063 +
1064 + heightManaged.add(card);
1065 + });
1066 +
1067 + return {
1068 + cards:cards.length,
1069 + height:maxHeight,
1070 + firstSection:firstSection
1071 + };
1072 + }
1073 +
1074 + function run(){
1075 + reset();
1076 +
1077 + if(
1078 + window.innerWidth<=MOBILE_MAX
1079 + ){
1080 + return;
1081 + }
1082 +
1083 + var parents=
1084 + Array.from(
1085 + root.querySelectorAll("*")
1086 + ).filter(function(parent){
1087 + return (
1088 + visible(parent,MIN_W,MIN_H)&&
1089 + parent.children&&
1090 + parent.children.length>=2&&
1091 + parent.children.length<=MAX_PARENT_CHILDREN
1092 + );
1093 + });
1094 +
1095 + var touched=new Set();
1096 +
1097 + parents.forEach(function(parent){
1098 + var entries=[];
1099 +
1100 + Array.from(parent.children).forEach(function(child){
1101 + if(!visible(child,MIN_W,MIN_H))return;
1102 +
1103 + var target=pickTarget(child);
1104 + if(!target)return;
1105 +
1106 + entries.push({
1107 + target:target,
1108 + rect:target.getBoundingClientRect()
1109 + });
1110 + });
1111 +
1112 + if(entries.length<2)return;
1113 +
1114 + groupsByVisualRow(entries).forEach(function(group){
1115 + if(!validHorizontalGroup(group))return;
1116 +
1117 + var signature=
1118 + group.entries.map(function(entry){
1119 + return entry.target;
1120 + });
1121 +
1122 + if(
1123 + !signature.some(function(el){
1124 + return !touched.has(el);
1125 + })
1126 + ){
1127 + return;
1128 + }
1129 +
1130 + var applied=
1131 + applyGroup(group);
1132 +
1133 + if(applied){
1134 + signature.forEach(function(el){
1135 + touched.add(el);
1136 + });
1137 + }
1138 + });
1139 + });
1140 + }
1141 +
1142 + function schedule(){
1143 + if(raf)cancelAnimationFrame(raf);
1144 +
1145 + raf=requestAnimationFrame(function(){
1146 + raf=requestAnimationFrame(function(){
1147 + raf=0;
1148 + run();
1149 + });
1150 + });
1151 + }
1152 +
1153 + addEventListener("resize",schedule,{passive:true});
1154 + addEventListener("load",schedule,{once:true});
1155 +
1156 + root.addEventListener(
1157 + "click",
1158 + function(){
1159 + setTimeout(schedule,0);
1160 + },
1161 + true
1162 + );
1163 +
1164 + Array.from(root.querySelectorAll("img")).forEach(function(img){
1165 + if(!img.complete){
1166 + img.addEventListener("load",schedule,{once:true});
1167 + }
1168 + });
1169 +
1170 + if(document.fonts&&document.fonts.ready){
1171 + document.fonts.ready.then(schedule);
1172 + }
1173 +
1174 + schedule();
1175 + setTimeout(schedule,200);
1176 + setTimeout(schedule,650);
1177 + setTimeout(schedule,1400);
1178 +})();
1179 +</script>
1180 +<!-- SN_HORIZONTAL_BOX_HARMONIZER_END -->
1181 +{{/html}}
1182 +