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 }});