swisnl / jQuery-contextMenu

jQuery contextMenu plugin & polyfill
https://swisnl.github.io/jQuery-contextMenu/
MIT License
2.25k stars 744 forks source link

Option selectableSubMenu does not work #687

Open milosbielik opened 5 years ago

milosbielik commented 5 years ago

(source: jQuery contextMenu v2.8.0) for { selectableSubMenu: true }...

my comments (FIXME) in code...

  // contextMenu item click
  itemClick: function (e) {
      var $this = $(this),
          data = $this.data(),
          opt = data.contextMenu,
          root = data.contextMenuRoot,
          key = data.contextMenuKey,
          callback;

      /* ----- FIXME: opt (for every submenu) is incorrect, items does not contain key, so first part of condition stops eval and returns */ 
      // abort if the key is unknown or disabled or is a menu
      if (!opt.items[key] || $this.is('.' + root.classNames.disabled + ', .context-menu-separator, .' + root.classNames.notSelectable) || ($this.is('.context-menu-submenu') && root.selectableSubMenu === false )) {
          return;
      }
milosbielik commented 5 years ago

Maybe this should help to fix the issue...

 // FIXED/REPLACED (on line 1289): $t.data('contextMenu', item).addClass('context-menu-submenu');
 $t.addClass('context-menu-submenu');
ThaGeege commented 5 years ago

Also noticed this issue. Any ETA on a fix? Have a menu with a tree like structure and want all items to be clickable. my workaround is to put add the parent item within the child but its not a great user experience.

for instance A has children and I cant click it due to the bug so I add A in the submenu: A ->A ->B -->B -->C

Edit: I actually found a strange thing. If I add a clickable A in the submenu then I actually can click the parent A. So I am adding it in both places and setting the child A item visible:false. I can now have a more user friendly menu tree and still click on the parent item. Here is a workaround sample below until the bug gets fixed. Top menu has A and B. B has submenu C. I can click on any of A/B/C with this trick.

$.contextMenu({
    selector: '#menu1', 
selectableSubMenu: true,
    build: function(trigger, e) {
        return {
            selectableSubMenu: true,
            callback:function(key,options){alert(key);},
            items: {
                "A":{name:"A"},
                "B":{name:"B", items:{
                    "B":{name:"B",visible:false},
                    "C":{name:"C"}
                    }}},
            selectableSubMenu: true
        }
    }
});
Ashwinning commented 4 years ago

https://github.com/swisnl/jQuery-contextMenu/issues/687#issuecomment-485832996 worked for me to solve this issue. Thanks!

CipherTrustee commented 4 years ago

Hopefully this would be fixed in the next release:)

To add to the hacky workarounds.

Step 1: Make the sub menu creation similar to the default case of a menu item by attaching the callbacks.

 case 'sub':
                                $.each([opt, root], function (i, k) {
                                    k.commands[key] = item;
                                    // Overwrite only if undefined or the item is appended to the root. This so it
                                    // doesn't overwrite callbacks of root elements if the name is the same.
                                    if ($.isFunction(item.callback) && (typeof k.callbacks[key] === 'undefined' || typeof opt.type === 'undefined')) {
                                        k.callbacks[key] = item.callback;
                                    }
                                });     

Step 2: When processing a click event for a clickable submenu, switch the item context to its parent.

itemClick: function (e) {

                var $this = $(this),
                    data = $this.data(),
                    opt = data.contextMenu,
                    root = data.contextMenuRoot,
                    key = data.contextMenuKey,
                    callback;

                //if, clickable submenu, switch the item context to its parent
                if(($this.is('.context-menu-submenu') && root.selectableSubMenu))
                {
                    $this = $(this).parent(),
                    data = $this.data(),
                    opt = data.contextMenu,
                    root = data.contextMenuRoot;
                }

This appears to be a robust workaround.