Changes for page Menu Macro
Last modified by Сергей Коршунов on 2025/09/03 12:19
From version 15.1
edited by Сергей Коршунов
on 2025/09/03 12:19
on 2025/09/03 12:19
Change comment:
Install extension [org.xwiki.platform:xwiki-platform-menu-ui/17.7.0]
To version 5.1
edited by Сергей Коршунов
on 2023/04/25 14:14
on 2023/04/25 14:14
Change comment:
Migrated property [type] from class [XWiki.WikiMacroParameterClass]
Summary
-
Objects (3 modified, 0 added, 1 removed)
Details
- XWiki.JavaScriptExtension[0]
-
- Code
-
... ... @@ -1,97 +1,26 @@ 1 -define('menu-ui-translation-keys', { 2 - prefix: 'menu.ui.', 3 - keys: [ 4 - "openSubMenu", 5 - "closeSubMenu" 6 - ] 7 -}); 8 -require(['jquery','xwiki-l10n!menu-ui-translation-keys'], function($, l10n) { 1 +require(['jquery'], function($) { 9 9 // It's not possible to write a CSS selector that targets list items containing lists so we rely on JavaScript. 10 10 // The 'dropdown' CSS class is used only to display the down/left arrow. 11 - // All nodes on the tree. 12 - $('.menu-horizontal ul , .menu-vertical ul') 13 - .attr('role', 'menu'); 14 - // All leaves on the tree. 15 - $('.menu-horizontal li, .menu-vertical li') 16 - .attr('role', 'menuitem'); 17 - $('.menu-horizontal li ul, .menu-vertical li ul') 18 - .parent() 19 - .addClass('xDropdown'); 4 + $('.menu-horizontal li ul').parent().addClass('xDropdown'); 5 + 20 20 // Make sure the menu separators are really empty. 21 - var menus = $('.menu-horizontal, .menu-vertical'); 22 - menus.find('li > br:first-child').remove(); 7 + $('.menu-horizontal, .menu-vertical').find('li > br:first-child').remove(); 23 23 24 - // Add aria attributes to the menu separators. 25 - menus.find('li') 26 - .filter(function() {return this.textContent.trim() === ""; }) 27 - .attr('role', 'separator') 28 - .attr('aria-hidden', 'true'); 29 - 30 - // Vertical menus are initially expanded 31 - $('.menu-vertical.collapsible').each(function() { 9 + // Collapsible menu bahavior. 10 + $('.menu-vertical.collapsible').each(function(){ 32 32 var open = $(this).hasClass('open'); 33 33 $(this).find('li ul').each(function() { 34 34 $(this).addClass('xDropdown-menu').parent().addClass('xDropdown' + (open ? ' open' : '')); 35 - }); 36 - }); 37 - 38 - function setDropdownButtonTitle(dropDownButton) { 39 - var xDropdown = $(dropDownButton).parent().parent(); 40 - if($(xDropdown).hasClass('open')) { 41 - $(dropDownButton).attr('title', l10n['closeSubMenu']); 42 - $(xDropdown).attr('aria-expanded', "true"); 43 - } else { 44 - $(dropDownButton).attr('title', l10n['openSubMenu']); 45 - $(xDropdown).attr('aria-expanded', "false"); 46 - } 47 - } 48 - 49 - $('.xDropdown').each(function() { 50 - var dropDownHeader = this.ownerDocument.createElement("div"); 51 - $(dropDownHeader).addClass("xDropdown-header"); 52 - var dropDownButton = this.ownerDocument.createElement("button"); 53 - $(dropDownButton).addClass("xDropdown-header-toggle"); 54 - setDropdownButtonTitle(dropDownButton); 55 - dropDownButton.addEventListener('click',function() { 56 - //Swaps the state of the submenu. 57 - var xDropdown = $(this).parent().parent(); 58 - xDropdown.toggleClass('open'); 59 - setDropdownButtonTitle(dropDownButton); 60 - }); 61 - let dropDownContent = $(this).contents(); 62 - // We put all the content of the entry in the header, 63 - // except for the last one which is the content of the dropdown. This dropdown stays where it is. 64 - for (let index = 0; index < dropDownContent.length - 1 ; index++) { 65 - let item = dropDownContent[index]; 66 - dropDownHeader.append(item); 14 + // Wrap everything (including text nodes) before the sub-menu in a DIV that will toggle its state. 15 + var toggle = this.ownerDocument.createElement('div'); 16 + $(this).parent().prepend(toggle); 17 + for(var next = toggle.nextSibling; next != this; next = toggle.nextSibling) { 18 + toggle.appendChild(next); 67 67 } 68 - dropDownHeader.append(dropDownButton); 69 - $(this).prepend(dropDownHeader); 70 - $(dropDownHeader).next().addClass('xDropdown-menu'); 71 - }); 72 - 73 - $('.xDropdown-menu').each(function() { 74 - this.addEventListener('keyup', function(event) { 75 - if (event.key === 'Escape') { 76 - // We change the state of the parent xDropdown 77 - this.parentNode.classList.remove('open'); 78 - // We set the focus on the toggle button of the section we just collapsed 79 - this.parentNode.querySelector(':scope > .xDropdown-header > .xDropdown-header-toggle').focus(); 80 - } 81 - event.stopPropagation(); 82 - }); 83 - }); 84 - 85 - $('.menu-horizontal .xDropdown').each(function() { 86 - // In case of horizontal menus, make it so that a class is added on hover, instead of using the :hover pseudo-class 87 - this.addEventListener("mouseover", function() { 88 - $(this).addClass('open'); 89 - setDropdownButtonTitle(this.firstChild.lastChild); 20 + $(toggle).addClass('xDropdown-toggle').on('click', function() { 21 + $(this).parent().toggleClass('open'); 22 + }); 90 90 }); 91 - this.addEventListener("mouseout", function() { 92 - $(this).removeClass('open'); 93 - setDropdownButtonTitle(this.firstChild.lastChild); 94 - }); 95 95 }); 96 96 97 97 // In case of horizontal responsive menus, make sub-submenus in the navbar work on mobile devices
- XWiki.StyleSheetExtension[1]
-
- Code
-
... ... @@ -4,32 +4,6 @@ 4 4 } 5 5 } 6 6 .menu { 7 - /* Rotate the carets when the menu is opened. */ 8 - .xDropdown{ 9 - > .xDropdown-header > .xDropdown-header-toggle:before { 10 - transform: rotate(90deg); 11 - } 12 - &.open > .xDropdown-header > .xDropdown-header-toggle:before { 13 - transform: rotate(0); 14 - } 15 - } 16 - .xDropdown-header-toggle { 17 - background: transparent; 18 - border:none; 19 - border-radius: @border-radius-base; 20 - margin: 0 .3em; 21 - line-height: (@line-height-computed / 2); 22 - min-width: 24px; 23 - min-height: 24px; 24 - &:hover, &:focus-within { 25 - background-color: @dropdown-bg; 26 - } 27 - &:before { 28 - .caret; 29 - margin-left: 0; 30 - content: ''; 31 - } 32 - } 33 33 &.menu-vertical { 34 34 ul { 35 35 list-style-type: none; ... ... @@ -51,8 +51,32 @@ 51 51 .xDropdown-menu { 52 52 display: none; 53 53 } 28 + .xDropdown-toggle { 29 + cursor: pointer; 30 + position: relative; 31 + &:hover { 32 + background-color: @nav-link-hover-bg; 33 + } 34 + &:after { 35 + .caret; 36 + content: ''; 37 + /* Positioning */ 38 + position: absolute; 39 + margin-top: @line-height-computed / 3; 40 + right: 1em; 41 + /* Collapsed arrow style */ 42 + border-bottom: 4px solid transparent; 43 + border-right: 4px solid; 44 + border-top: 4px solid transparent; 45 + } 46 + } 54 54 .xDropdown.open { 55 - > ul { 48 + > .xDropdown-toggle:after { 49 + /* Expanded arrow style */ 50 + .caret; 51 + margin-top: @line-height-computed / 2; 52 + } 53 + > .xDropdown-menu { 56 56 display: block; 57 57 } 58 58 } ... ... @@ -60,52 +60,42 @@ 60 60 &.menu-horizontal { 61 61 /* Stylization: Navbars */ 62 62 .clearfix; 63 - background-color: @menu-default-bg; 64 - border-color: @menu-default-border; 65 - min-height: @menu-height; 61 + background-color: @navbar-default-bg; 62 + border-color: @navbar-default-border; 63 + /* Custom styling */ 64 + .box-shadow(0 2px 8px rgba(0,0,0,0.4) inset); 65 + min-height: @navbar-height; 66 66 padding-left: 25px; 67 - .xDropdown.open { 68 - > .xDropdown-header > .xDropdown-header-toggle:before { 69 - transform: rotate(0); 70 - } 71 - > ul { 72 - display: block; 73 - } 74 - } 75 75 & > ul { 76 76 padding-left: 0; 77 77 list-style-type: none; 78 78 margin: 0; 79 - min-height: @menu-height; 80 - display: flex; 81 - align-items: stretch; 82 82 & > li { 83 83 position: relative; 84 - min-height: 50px; 85 - display: flex; 86 - align-items: center; 73 + display: block; 87 87 padding: @nav-link-padding; 88 - padding-top: 0;89 - padding-bottom: 0;75 + padding-top: @navbar-padding-vertical; 76 + padding-bottom: @navbar-padding-vertical; 90 90 @media (min-width: @grid-float-breakpoint) { 91 91 float: left; 92 92 } 93 - color: @menu-default-link-color; 94 - &:hover, &:focus-within { 95 - color: @menu-default-link-hover-color; 96 - background-color: @menu-default-link-hover-bg; 97 - background-color: @menu-default-link-active-bg; 98 - color: @menu-default-link-active-color; 80 + line-height: @line-height-computed; 81 + color: @navbar-default-link-color; 82 + &:hover { 83 + color: @navbar-default-link-hover-color; 84 + background-color: @navbar-default-link-hover-bg; 85 + background-color: @navbar-default-link-active-bg; 86 + color: @navbar-default-link-active-color; 99 99 /* When hovering, have the same color for text and link usage */ 100 100 & > span > a { 101 - background-color: @ menu-default-link-active-bg;102 - color: @ menu-default-link-active-color;89 + background-color: @navbar-default-link-active-bg; 90 + color: @navbar-default-link-active-color; 103 103 } 104 104 } 105 105 /* Links inside menu */ 106 106 a { 107 - color: @ menu-default-link-color;108 - &:hover ,&:focus-within{95 + color: @navbar-default-link-color; 96 + &:hover { 109 109 text-decoration: none; 110 110 } 111 111 } ... ... @@ -112,26 +112,15 @@ 112 112 /* Containers, images inside menu */ 113 113 div, img { 114 114 /* Limit the height to the nav height minus the padding and minus border */ 115 - max-height: @ menu-height - (2 * @navbar-padding-vertical) - 2px;103 + max-height: @navbar-height - (2 * @navbar-padding-vertical) - 2px; 116 116 overflow: hidden; 117 - &.xDropdown-header{ 118 - /* No border on the dropdown header */ 119 - max-height: unset; 120 - } 121 121 } 122 - /* Horizontal menu top-level headers. */ 123 - & > .xDropdown-header > .xDropdown-header-toggle { 124 - &:hover, &:focus-within { 125 - /* Change background color of the caret when hovering on the navbar. */ 126 - background-color: @menu-default-bg; 127 - } 128 - } 129 129 /* Separator vertical inside menu */ 130 130 &:empty { 131 - height: @ menu-height;108 + height: @navbar-height; 132 132 margin: 0 ((@line-height-computed / 2) - 1); 133 133 padding: 0; 134 - border-right: 1px solid @ menu-default-border;111 + border-right: 1px solid @navbar-default-border; 135 135 } 136 136 } 137 137 /* Stylization: Dropdowns */ ... ... @@ -151,27 +151,25 @@ 151 151 background-color: @dropdown-bg; 152 152 border: 1px solid @dropdown-border; 153 153 border-radius: @border-radius-base; 154 - /* On this element, the box-shadow is very useful since it appears in front of other elements. 155 - We don't want to remove it despite the Flamingo theme now using flat designs almost everywhere. */ 156 156 .box-shadow(0 6px 12px rgba(0,0,0,.175)); 157 157 background-clip: padding-box; 158 158 margin-top: 0; 159 159 border-top-right-radius: 0; 160 160 border-top-left-radius: 0; 161 - overflow-wrap: break-word; 162 - hyphens: auto; 163 163 li { 164 164 /* Text inside menu */ 165 165 color: @dropdown-link-color; 166 - padding: 3px 20px; 167 167 /* Links inside menu */ 168 168 a { 169 169 display: block; 142 + padding: 3px 20px; 170 170 clear: both; 171 171 font-weight: normal; 172 172 line-height: @line-height-base; 173 173 color: @dropdown-link-color; 174 - &:hover, &:focus-within { 147 + overflow: hidden; 148 + text-overflow: ellipsis; // Displaying ... if the text is too long 149 + &:hover { 175 175 /* &:extend(.dropdown-menu>li>a:hover); */ 176 176 text-decoration: none; 177 177 color: @dropdown-link-hover-color; ... ... @@ -188,8 +188,8 @@ 188 188 line-height: @line-height-base; 189 189 color: @dropdown-link-color; 190 190 /* Empty dropdowns should have height in order to display the arrow */ 191 - min-height: 1lh;192 - &:hover ,&:focus-within{166 + min-height: 2 * @font-size-base; 167 + &:hover { 193 193 text-decoration: none; 194 194 color: @dropdown-link-hover-color; 195 195 background-color: @dropdown-link-hover-bg; ... ... @@ -199,16 +199,15 @@ 199 199 } 200 200 } 201 201 /* When in dropdown we also have a link, reset the duplicated padding */ 202 - & > .xDropdown-header >span > a {177 + & > span > a { 203 203 padding: 0; 204 204 display: inherit; 205 205 } 206 - /* Reposition the toggle when in a dropdown of fixed size 207 - to avoid eating away at the bit of space we have for the text. */ 208 - & > .xDropdown-header > .xDropdown-header-toggle { 181 + /* Place the arrow on the right */ 182 + &:after { 209 209 position: absolute; 210 - right :0;211 - t op:0;184 + margin-top: @line-height-computed / 2; 185 + right: 8px; 212 212 } 213 213 } 214 214 /* Separator horizontal inside menu */ ... ... @@ -222,9 +222,17 @@ 222 222 /* Stylization: Generic */ 223 223 li { 224 224 /* Display submenus on hover */ 225 - & .open> ul {199 + &:hover > ul { 226 226 display: block; 227 227 } 202 + /* Display an arrow for expandable items */ 203 + &.xDropdown { 204 + &:after { 205 + .caret; 206 + content: ''; 207 + margin-left: .5em; 208 + } 209 + } 228 228 } 229 229 /* The only way to have a menu with more than 2 levels without JavaScript is to use a fixed width. */ 230 230 &.fixedWidth { ... ... @@ -246,11 +246,11 @@ 246 246 } 247 247 /* Resetting rules for mobile view */ 248 248 @media (max-width: @screen-xs-max) { 249 - > ul { 231 + > ul { 250 250 margin: 0 0 0 -25px; /* Remove padding added in normal view */ 251 251 > li { 252 252 &:empty { 253 - .nav-divider(@ menu-default-border);235 + .nav-divider(@navbar-default-border); 254 254 } 255 255 } 256 256 ul { ... ... @@ -264,25 +264,28 @@ 264 264 box-shadow: none; 265 265 li { 266 266 /* Text inside menu */ 267 - color: @ menu-default-link-color;249 + color: @navbar-default-link-color; 268 268 /* Links inside menu */ 269 269 a { 270 - color: @menu-default-link-color; 252 + color: @navbar-default-link-color; 253 + &:hover { 254 + /* Preserve the styling from dropdown */ 255 + } 271 271 } 272 272 /* Submenus inside menu */ 273 273 &.xDropdown { 274 - color: @ menu-default-link-color;275 - & .open{259 + color: @navbar-default-link-color; 260 + &:hover { 276 276 background-color: transparent; 277 277 color: inherit; 278 278 } 279 279 /* When in dropdown we also have a link */ 280 - > span > a { 281 - color: @ menu-default-link-color;265 + > span > a { 266 + color: @navbar-default-link-color; 282 282 } 283 283 } 284 284 &:empty { 285 - .nav-divider(@ menu-default-border);270 + .nav-divider(@navbar-default-border); 286 286 } 287 287 } 288 288 } ... ... @@ -312,16 +312,15 @@ 312 312 313 313 .menu-horizontal-toggle { 314 314 .clearfix; 315 - background-color: @menu-default-bg; 316 - border-color: @menu-default-border; 317 - min-height: @menu-height; 300 + background-color: @navbar-default-bg; 301 + border-color: @navbar-default-border; 302 + .box-shadow(0 2px 8px rgba(0,0,0,0.4) inset); 303 + min-height: @navbar-height; 318 318 & .navbar-toggle { 319 319 float: left; 320 320 padding-left: 15px; 321 - padding-top: 0; 322 - padding-bottom: 0; 323 323 & .icon-bar { 324 - background-color: @ menu-default-link-color;308 + background-color: @navbar-default-link-color; 325 325 transition: .3s ease all; 326 326 &:nth-of-type(2) { 327 327 opacity: 0;
- XWiki.WikiMacroClass[0]
-
- Macro code
-
... ... @@ -1,7 +1,6 @@ 1 1 {{velocity}} 2 2 #set ($id = $xcontext.macro.params.id) 3 3 #set ($type = $xcontext.macro.params.type) 4 -#set ($label = $xcontext.macro.params.label) 5 5 #set ($colorTheme = $xwiki.getUserPreference('colorTheme')) 6 6 #if ("$!colorTheme" != '') 7 7 ## Make sure we use an absolute reference (see XWIKI-9672) ... ... @@ -9,24 +9,16 @@ 9 9 #end 10 10 #set ($discard = $xwiki.ssx.use("$xcontext.macro.doc.prefixedFullName", {'colorTheme': $colorTheme})) 11 11 #set ($discard = $xwiki.jsx.use("$xcontext.macro.doc.prefixedFullName")) 12 -## Make sure the label is non-empty as otherwise the aria-label doesn't work. 13 -#if ("$!label" != '') 14 - #set ($label = $wikimacro.context.getXDOM().getIdGenerator().generateUniqueId('Menu','')) 15 -#end 16 16 #if($type.contains('horizontal')) 17 17 ## Make sure the id is non-empty for horizontal menus as otherwise the toggle doesn't work. 18 - #if ("$!id" == '')13 + #if ($stringtool.isBlank("$!id")) 19 19 #set ($id = $wikimacro.context.getXDOM().getIdGenerator().generateUniqueId("M", "GeneratedMenuId")) 20 20 #end 21 - (% role='navigation' class='menu-horizontal-toggle' 22 - aria-label="${services.rendering.escape($label, 'xwiki/2.1')}" %)((( 16 + (% role="navigation" class="menu-horizontal-toggle" %)((( 23 23 (% class="navbar-header" %)((( 24 24 {{html}} 25 - <button type="button" class="navbar-toggle collapsed" data-toggle="collapse" data-target="#$!{escapetool.xml($id)}" 26 - aria-expanded="false" aria-controls="$!{escapetool.xml($id)}"> 27 - <span class="sr-only"> 28 - $escapetool.xml($services.localization.render('menu.ui.horizontal.toggler.description')) 29 - </span> 19 + <button type="button" class="navbar-toggle collapsed" data-toggle="collapse" data-target="#$!{escapetool.xml($id)}" aria-expanded="false"> 20 + <span class="sr-only"></span> 30 30 <span class="icon-bar"></span> 31 31 <span class="icon-bar"></span> 32 32 <span class="icon-bar"></span> ... ... @@ -33,13 +33,12 @@ 33 33 </button> 34 34 {{/html}} 35 35 ))) 36 - (% id="$!{services.rendering.escape($id, 'xwiki/2.1')}" class="menu menu-${services.rendering.escape($!type, 'xwiki/2.1')} collapse navbar-collapse" role="navigation"%)(((27 + (% id="$!{services.rendering.escape($id, 'xwiki/2.1')}" class="menu menu-${services.rendering.escape($!type, 'xwiki/2.1')} collapse navbar-collapse" %)((( 37 37 {{wikimacrocontent/}} 38 38 ))) 39 39 ))) 40 40 #else 41 - (% role="navigation" #if ("$!id" != '') id="${services.rendering.escape($id, 'xwiki/2.1')}"#end class="menu menu-${services.rendering.escape($!type, 'xwiki/2.1')}" 42 - aria-label="${services.rendering.escape($label, 'xwiki/2.1')}" %)((( 32 + (% #if ("$!id" != '') id="${services.rendering.escape($id, 'xwiki/2.1')}"#end class="menu menu-${services.rendering.escape($!type, 'xwiki/2.1')}" %)((( 43 43 {{wikimacrocontent/}} 44 44 ))) 45 45 #end
- XWiki.WikiMacroParameterClass[3]
-
- Parameter name
-
... ... @@ -1,1 +1,0 @@ 1 -label - Parameter description
-
... ... @@ -1,1 +1,0 @@ 1 -Optional menu label used to describe the content of the menu. - Parameter mandatory
-
... ... @@ -1,1 +1,0 @@ 1 -No