? ?
avatar infograf768
infograf768
21 Aug 2019

Steps to reproduce the issue

Create a custom admin menu with no presets (we have other issues with presets and I will create another issue for that.)
Create a menu module for that menu in the "menu" position.
Make sure the module is placed AFTER the default Admin Menu module in the Manager.

Create a Heading menu item in that custom admin menu.
Create any other menu item as child of that Heading menu item.

The result is that we have both the default Admin Menu and this custom one in the menu side bar. Below, the custom admin menu starts with Global Config.

Screen Shot 2019-08-21 at 10 31 37

Expected result

When clicking on the Heading menu item, it should expand.
Same for a Container menu item

Actual result

It does not expand and no error is displayed.
The event is not added to the element.

We would get the same issue if the Custom Menu is on top of the side bar but this time for all the Menus of the default admin menu which should expand.

Is it metismenu.js issue or somewhere else?

@Fedik

avatar infograf768 infograf768 - open - 21 Aug 2019
avatar joomla-cms-bot joomla-cms-bot - change - 21 Aug 2019
Labels Added: ? ?
avatar joomla-cms-bot joomla-cms-bot - labeled - 21 Aug 2019
avatar infograf768 infograf768 - change - 21 Aug 2019
The description was changed
avatar infograf768 infograf768 - edited - 21 Aug 2019
avatar Fedik
Fedik - comment - 21 Aug 2019

It actually a mod_menu in general, and admin-menu.js.
a mod_menu produces menus with duplicated ids:
screen 2019-08-21 15 13 13 682x111

and admin-menu.js cannot handle multiple menu, it was coded only for one #menu

screen 2019-08-21 15 22 14 396x82

Possible solution:
Drop use of ID, and use a "class" instead

Duplicated ID not allowed anyway.

avatar infograf768
infograf768 - comment - 21 Aug 2019

@Fedik
I understand. Not sure I can solve myself.

avatar Fedik
Fedik - comment - 21 Aug 2019

best would be if it will fix who wrote it :)

avatar franz-wohlkoenig franz-wohlkoenig - change - 22 Aug 2019
Status New Discussion
avatar infograf768
infograf768 - comment - 22 Aug 2019

Looks like metismenu wants only an id
https://onokumus.com/metismenujs/#install

As we are loading the same module twice, we have the same id which is not incremented.
echo '<ul id="menu" class="' . $class . '">' . "\n";

avatar Fedik
Fedik - comment - 22 Aug 2019

Looks like metismenu wants only an id

hm, not really, it want an element or string selector https://github.com/onokumus/metismenujs/blob/5648f65/src/index.ts#L23

in theory we can change the code from new window.MetisMenu('#menu');
to smething like:

var allMenus = document.querySelectorAll('ul.foo-bar-menu-class');
allMenus.forEach(function(menu){
  new MetisMenu(menu);
});

It will not depend from ID, but ID still must be incremented,
Maybe just id="menu<? echo $module->Id ?>"
But I not sure about styling, I suspect it may used in CSS, then also will be need changed CSS to use class instead of id.

avatar Fedik
Fedik - comment - 22 Aug 2019

a suggested fix seems works, but
unfortunately there more code that depend from "only single menu"

/**
* Sidebar Nav
*/
const allLinks = wrapper.querySelectorAll('a.no-dropdown, a.collapse-arrow, .menu-dashboard > a');
const currentUrl = window.location.href.toLowerCase();
const mainNav = document.getElementById('menu');
const menuParents = [].slice.call(mainNav.querySelectorAll('li.parent > a'));
const subMenusClose = [].slice.call(mainNav.querySelectorAll('li.parent .close'));
// Set active class
allLinks.forEach((link) => {
if (currentUrl === link.href) {
link.classList.add('active');
// Auto Expand Levels
if (!link.parentNode.classList.contains('parent')) {
const firstLevel = closest(link, '.collapse-level-1');
const secondLevel = closest(link, '.collapse-level-2');
if (firstLevel) firstLevel.parentNode.classList.add('active');
if (firstLevel) firstLevel.classList.add('in');
if (secondLevel) secondLevel.parentNode.classList.add('active');
if (secondLevel) secondLevel.classList.add('in');
}
}
});
// Child open toggle
const openToggle = (event) => {
let menuItem = event.currentTarget.parentNode;
if (menuItem.tagName.toLowerCase() === 'span') {
menuItem = event.currentTarget.parentNode.parentNode;
}
if (menuItem.classList.contains('open')) {
mainNav.classList.remove('child-open');
menuItem.classList.remove('open');
} else {
const siblings = [].slice.call(menuItem.parentNode.children);
siblings.forEach((sibling) => {
sibling.classList.remove('open');
});
wrapper.classList.remove('closed');
localStorage.setItem('atum-sidebar', 'open');
if (menuToggleIcon.classList.contains('fa-toggle-off')) {
menuToggleIcon.classList.toggle('fa-toggle-off');
menuToggleIcon.classList.toggle('fa-toggle-on');
}
mainNav.classList.add('child-open');
if (menuItem.parentNode.classList.contains('main-nav')) {
menuItem.classList.add('open');
}
}
Joomla.Event.dispatch('joomla:menu-toggle', 'open');
};
menuParents.forEach((parent) => {
parent.addEventListener('click', openToggle);
parent.addEventListener('keyup', openToggle);
});
// Menu close
subMenusClose.forEach((subMenu) => {
subMenu.addEventListener('click', () => {
const menuChildsOpen = [].slice.call(mainNav.querySelectorAll('.open'));
menuChildsOpen.forEach((menuChild) => {
menuChild.classList.remove('open');
});
mainNav.classList.remove('child-open');
});
});

so it not that easy

avatar infograf768
infograf768 - comment - 22 Aug 2019

Modified default.php to use
echo '<ul id="menu' . $module->id . '" class="' . $class . '">' . "\n";
then we indeed get a different id per module which anyway solved that aspect.

I then simplified the class code in admin-menu.js to see what happens

  var allMenus = document.querySelectorAll('ul.main-nav');

  allMenus.forEach(function(menu) {
  new MetisMenu(menu);
  });

tested and it works (after making sure a thousand times that we have no cache anywhere) and also got an error
ReferenceError: mainNav is not defined
because we have further down
var mainNav = document.getElementById('menu');
which obviously is wrong as module id is added to menu

Therefore it looks like we do have to get the id anyway.

avatar Fedik
Fedik - comment - 22 Aug 2019

var mainNav = document.getElementById('menu');

this thing also has to be changed to use class, and loop over all menu, or use only first menu.
I just not very understood, for what all that extra code in "Sidebar Nav"

avatar infograf768
infograf768 - comment - 23 Aug 2019

I just not very understood, for what all that extra code in "Sidebar Nav"

Agree. It looks like working eventhough we have this js error.

avatar infograf768
infograf768 - comment - 23 Aug 2019

@Fedik
I tried another way to get the id

    var forEach = function (array, callback, scope) {
      for (var i = 0; i < array.length; i++) {
        callback.call(scope, i, array[i]); // passes back stuff we need
      }
    };

    var allMenus = document.querySelectorAll('ul.main-nav');

    forEach(allMenus, function (index) {
      var x = document.getElementsByTagName('ul')[index];
      var mainNav = document.getElementById(x.id);
      console.log(x.id);
    });

But x.id gives both the menu# and the ul id of the children ul i.e. collapse#

Screen Shot 2019-08-23 at 11 42 07

Screen Shot 2019-08-23 at 11 40 48

avatar Fedik
Fedik - comment - 23 Aug 2019

maybe try do as you did before, and var mainNav = document.getElementById('menu'); replace to
var mainNav = document.querySelector('ul.main-nav');
this will pick a first found menu,
it a bit dirty but also should work, in theory

avatar infograf768
infograf768 - comment - 23 Aug 2019

+1 Indeed, I do not get any more errors.
I will make a PR

avatar franz-wohlkoenig franz-wohlkoenig - change - 23 Aug 2019
Status Discussion Closed
Closed_Date 0000-00-00 00:00:00 2019-08-23 14:44:07
Closed_By franz-wohlkoenig
avatar franz-wohlkoenig
franz-wohlkoenig - comment - 23 Aug 2019

Closed as having Pull Request #25995

avatar franz-wohlkoenig franz-wohlkoenig - close - 23 Aug 2019

Add a Comment

Login with GitHub to post a comment