Configuring jstree right-click contextmenu for different node types Configuring jstree right-click contextmenu for different node types jquery jquery

Configuring jstree right-click contextmenu for different node types


The contextmenu plugin already has support for this. From the documentation you linked to:

items: Expects an object or a function, which should return an object. If a function is used it fired in the tree's context and receives one argument - the node that was right clicked.

So rather than give contextmenu a hard-coded object to work with, you can supply the following function. It checks the element that was clicked for a class named "folder", and removes the "delete" menu item by deleting it from the object:

function customMenu(node) {    // The default set of all items    var items = {        renameItem: { // The "rename" menu item            label: "Rename",            action: function () {...}        },        deleteItem: { // The "delete" menu item            label: "Delete",            action: function () {...}        }    };    if ($(node).hasClass("folder")) {        // Delete the "delete" menu item        delete items.deleteItem;    }    return items;}

Note that the above will hide the delete option completely, but the plugin also allows you to show an item while disabling its behaviour, by adding _disabled: true to the relevant item. In this case you can use items.deleteItem._disabled = true within the if statement instead.

Should be obvious, but remember to initialise the plugin with the customMenu function instead of what you had previously:

$("#tree").jstree({plugins: ["contextmenu"], contextmenu: {items: customMenu}});//                                                                    ^// ___________________________________________________________________|

Edit: If you don't want the menu to be recreated on every right-click, you can put the logic in the action handler for the delete menu item itself.

"label": "Delete","action": function (obj) {    if ($(this._get_node(obj)).hasClass("folder") return; // cancel action}

Edit again: After looking at the jsTree source code, it looks like the contextmenu is being re-created every time it is shown anyway (see the show() and parse() functions), so I don't see a problem with my first solution.

However, I do like the notation you are suggesting, with a function as the value for _disabled. A potential path to explore is to wrap their parse() function with your own one that evaluates the function at disabled: function () {...} and stores the result in _disabled, before calling the original parse().

It won't be difficult either to modify their source code directly. Line 2867 of version 1.0-rc1 is the relevant one:

str += "<li class='" + (val._class || "") + (val._disabled ? " jstree-contextmenu-disabled " : "") + "'><ins ";

You can simply add a line before this one that checks $.isFunction(val._disabled), and if so, val._disabled = val._disabled(). Then submit it to the creators as a patch :)


Implemented with different node types:

$('#jstree').jstree({    'contextmenu' : {        'items' : customMenu    },    'plugins' : ['contextmenu', 'types'],    'types' : {        '#' : { /* options */ },        'level_1' : { /* options */ },        'level_2' : { /* options */ }        // etc...    }});

And the customMenu function:

function customMenu(node){    var items = {        'item1' : {            'label' : 'item1',            'action' : function () { /* action */ }        },        'item2' : {            'label' : 'item2',            'action' : function () { /* action */ }        }    }    if (node.type === 'level_1') {        delete items.item2;    } else if (node.type === 'level_2') {        delete items.item1;    }    return items;}

Works beautifully.


To clear everything.

Instead of this:

$("#xxx").jstree({    'plugins' : 'contextmenu',    'contextmenu' : {        'items' : { ... bla bla bla ...}    }});

Use this:

$("#xxx").jstree({    'plugins' : 'contextmenu',    'contextmenu' : {        'items' : customMenu    }});