Changes for page Menu Macro
Last modified by Ruud de Jong on 2024/10/24 11:40
From version 7.1
edited by Ruud de Jong
on 2024/07/13 21:59
on 2024/07/13 21:59
Change comment:
Install extension [org.xwiki.platform:xwiki-platform-menu-ui/16.5.0]
To version 4.1
edited by Bart Vastenhouw
on 2022/08/02 10:56
on 2022/08/02 10:56
Change comment:
Install extension [org.xwiki.platform:xwiki-platform-menu-ui/14.6]
Summary
-
Page properties (1 modified, 0 added, 0 removed)
-
Objects (3 modified, 0 added, 1 removed)
Details
- Page properties
-
- Author
-
... ... @@ -1,1 +1,1 @@ 1 -XWiki. RuuddeJong1 +XWiki.BartVastenhouw
- XWiki.JavaScriptExtension[0]
-
- Code
-
... ... @@ -1,85 +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 - $('.menu-horizontal .xDropdown').each(function() { 74 - // In case of horizontal menus, make it so that a class is added on hover, instead of using the :hover pseudo-class 75 - this.addEventListener("mouseover", function() { 76 - $(this).addClass('open'); 77 - setDropdownButtonTitle(this.firstChild.lastChild); 20 + $(toggle).addClass('xDropdown-toggle').on('click', function() { 21 + $(this).parent().toggleClass('open'); 22 + }); 78 78 }); 79 - this.addEventListener("mouseout", function() { 80 - $(this).removeClass('open'); 81 - setDropdownButtonTitle(this.firstChild.lastChild); 82 - }); 83 83 }); 84 84 85 85 // 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 } ... ... @@ -66,35 +66,22 @@ 66 66 .box-shadow(0 2px 8px rgba(0,0,0,0.4) inset); 67 67 min-height: @navbar-height; 68 68 padding-left: 25px; 69 - .xDropdown.open { 70 - > .xDropdown-header > .xDropdown-header-toggle:before { 71 - transform: rotate(0); 72 - } 73 - > ul { 74 - display: block; 75 - } 76 - } 77 77 & > ul { 78 78 padding-left: 0; 79 79 list-style-type: none; 80 80 margin: 0; 81 - min-height: 50px; 82 - display: flex; 83 - align-items: stretch; 84 84 & > li { 85 85 position: relative; 86 - min-height: 50px; 87 - display: flex; 88 - align-items: center; 73 + display: block; 89 89 padding: @nav-link-padding; 90 - padding-top: 0;91 - padding-bottom: 0;75 + padding-top: @navbar-padding-vertical; 76 + padding-bottom: @navbar-padding-vertical; 92 92 @media (min-width: @grid-float-breakpoint) { 93 93 float: left; 94 94 } 95 95 line-height: @line-height-computed; 96 96 color: @navbar-default-link-color; 97 - &:hover ,&:focus-within{82 + &:hover { 98 98 color: @navbar-default-link-hover-color; 99 99 background-color: @navbar-default-link-hover-bg; 100 100 background-color: @navbar-default-link-active-bg; ... ... @@ -108,7 +108,7 @@ 108 108 /* Links inside menu */ 109 109 a { 110 110 color: @navbar-default-link-color; 111 - &:hover ,&:focus-within{96 + &:hover { 112 112 text-decoration: none; 113 113 } 114 114 } ... ... @@ -117,10 +117,6 @@ 117 117 /* Limit the height to the nav height minus the padding and minus border */ 118 118 max-height: @navbar-height - (2 * @navbar-padding-vertical) - 2px; 119 119 overflow: hidden; 120 - &.xDropdown-header{ 121 - /* No border on the dropdown header */ 122 - max-height: unset; 123 - } 124 124 } 125 125 /* Separator vertical inside menu */ 126 126 &:empty { ... ... @@ -166,7 +166,7 @@ 166 166 color: @dropdown-link-color; 167 167 overflow: hidden; 168 168 text-overflow: ellipsis; // Displaying ... if the text is too long 169 - &:hover ,&:focus-within{150 + &:hover { 170 170 /* &:extend(.dropdown-menu>li>a:hover); */ 171 171 text-decoration: none; 172 172 color: @dropdown-link-hover-color; ... ... @@ -184,7 +184,7 @@ 184 184 color: @dropdown-link-color; 185 185 /* Empty dropdowns should have height in order to display the arrow */ 186 186 min-height: 2 * @font-size-base; 187 - &:hover ,&:focus-within{168 + &:hover { 188 188 text-decoration: none; 189 189 color: @dropdown-link-hover-color; 190 190 background-color: @dropdown-link-hover-bg; ... ... @@ -194,16 +194,15 @@ 194 194 } 195 195 } 196 196 /* When in dropdown we also have a link, reset the duplicated padding */ 197 - & > .xDropdown-header >span > a {178 + & > span > a { 198 198 padding: 0; 199 199 display: inherit; 200 200 } 201 - /* Reposition the toggle when in a dropdown of fixed size 202 - to avoid eating away at the bit of space we have for the text. */ 203 - & > .xDropdown-header > .xDropdown-header-toggle { 182 + /* Place the arrow on the right */ 183 + &:after { 204 204 position: absolute; 205 - right :0;206 - t op:0;185 + margin-top: @line-height-computed / 2; 186 + right: 8px; 207 207 } 208 208 } 209 209 /* Separator horizontal inside menu */ ... ... @@ -217,9 +217,17 @@ 217 217 /* Stylization: Generic */ 218 218 li { 219 219 /* Display submenus on hover */ 220 - & .open> ul {200 + &:hover > ul { 221 221 display: block; 222 222 } 203 + /* Display an arrow for expandable items */ 204 + &.xDropdown { 205 + &:after { 206 + .caret; 207 + content: ''; 208 + margin-left: .5em; 209 + } 210 + } 223 223 } 224 224 /* The only way to have a menu with more than 2 levels without JavaScript is to use a fixed width. */ 225 225 &.fixedWidth { ... ... @@ -241,7 +241,7 @@ 241 241 } 242 242 /* Resetting rules for mobile view */ 243 243 @media (max-width: @screen-xs-max) { 244 - > ul { 232 + > ul { 245 245 margin: 0 0 0 -25px; /* Remove padding added in normal view */ 246 246 > li { 247 247 &:empty { ... ... @@ -263,16 +263,19 @@ 263 263 /* Links inside menu */ 264 264 a { 265 265 color: @navbar-default-link-color; 254 + &:hover { 255 + /* Preserve the styling from dropdown */ 256 + } 266 266 } 267 267 /* Submenus inside menu */ 268 268 &.xDropdown { 269 269 color: @navbar-default-link-color; 270 - & .open{261 + &:hover { 271 271 background-color: transparent; 272 272 color: inherit; 273 273 } 274 274 /* When in dropdown we also have a link */ 275 - > span > a { 266 + > span > a { 276 276 color: @navbar-default-link-color; 277 277 } 278 278 }
- 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 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 - Parameter name
-
... ... @@ -1,1 +1,0 @@ 1 -label