为不同的节点typesconfigurationjstree右键单击上下文菜单

我在网上看过一个例子,展示了如何自定义jstree的右键菜单(使用contextmenu插件)的外观。

例如,允许我的用户删除“文档”,而不是“文件夹”(通过隐藏文件夹的上下文菜单中的“删除”选项)。

现在我找不到这个例子。 任何人都可以指向正确的方向吗? 官方文件并没有真正的帮助。

编辑:

因为我想要默认的上下文菜单只有一个或两个小的变化,我宁愿不重新创build整个菜单(当然,如果这是唯一的方法)。 我想要做的是这样的:

"contextmenu" : { items: { "ccp" : false, "create" : { // The item label "label" : "Create", // The function to execute upon a click "action": function (obj) { this.create(obj); }, "_disabled": function (obj) { alert("obj=" + obj); return "default" != obj.attr('rel'); } } } } 

但它不起作用 – 创build项目总是禁用(警报从不出现)。

contextmenu插件已经支持这个。 从您链接到的文档:

items :期望一个对象或函数,它应该返回一个对象 。 如果使用了一个函数,它会在树的上下文中触发并接收一个参数 – 右键单击​​的节点。

因此,不要给contextmenu一个硬编码的对象来处理,你可以提供以下function。 它检查名为“folder”的类被单击的元素,并通过从对象中删除“delete”菜单项来删除它:

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

请注意,上述操作将完全隐藏删除选项,但插件还允许您在禁用其行为的同时显示某个项目,方法是在相关项目中添加_disabled: true 。 在这种情况下,您可以在if语句中使用items.deleteItem._disabled = true

应该是显而易见的,但要记住使用customMenu函数而非以前的方法初始化插件:

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

编辑:如果你不想在每次右键单击时重新创build菜单,那么可以将逻辑放在删除菜单项本身的操作处理程序中。

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

再次编辑:查看jsTree源代码后,看起来每次显示contextmenu都会重新创build(请参阅show()parse()函数),所以我没有看到我的问题第一个scheme

不过,我喜欢你所build议的符号,用_disabled的值作为函数。 探索的一个潜在的途径是将自己的parse()函数与自己的parse()函数进行封装,并在调用原始parse()之前将函数的值设置为disabled: function () {...}并将结果存储在_disabled

直接修改源代码也不会有困难。 版本1.0-rc1的2867行是相关的:

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

你可以简单地在这个检查$.isFunction(val._disabled)之前添加一行,如果是, val._disabled = val._disabled() 。 然后将其作为补丁提交给创作者:)

用不同的节点types实现:

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

和customMenufunction:

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

精美的作品。

清除一切。

而不是这个:

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

用这个:

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

我已经改变了build议的解决schemetypes有点不同,但也许可以帮助别人:

其中#{$ id_arr [$ k]}是对div容器的引用…在我的情况下,我使用许多树,所以这些代码将输出到浏览器,但你明白了..基本上我想所有上下文菜单选项,但只有驱动器节点上的“创build”和“粘贴”。 显然,随后对这些操作的正确绑定:

 <div id="$id_arr[$k]" class="jstree_container"></div> </div> </li> <!-- JavaScript neccessary for this tree : {$value} --> <script type="text/javascript" > jQuery.noConflict(); jQuery(function ($) { // This is for the context menu to bind with operations on the right clicked node function customMenu(node) { // The default set of all items var control; var items = { createItem: { label: "Create", action: function (node) { return { createItem: this.create(node) }; } }, renameItem: { label: "Rename", action: function (node) { return { renameItem: this.rename(node) }; } }, deleteItem: { label: "Delete", action: function (node) { return { deleteItem: this.remove(node) }; }, "separator_after": true }, copyItem: { label: "Copy", action: function (node) { $(node).addClass("copy"); return { copyItem: this.copy(node) }; } }, cutItem: { label: "Cut", action: function (node) { $(node).addClass("cut"); return { cutItem: this.cut(node) }; } }, pasteItem: { label: "Paste", action: function (node) { $(node).addClass("paste"); return { pasteItem: this.paste(node) }; } } }; // We go over all the selected items as the context menu only takes action on the one that is right clicked $.jstree._reference("#{$id_arr[$k]}").get_selected(false, true).each(function (index, element) { if ($(element).attr("id") != $(node).attr("id")) { // Let's deselect all nodes that are unrelated to the context menu -- selected but are not the one right clicked $("#{$id_arr[$k]}").jstree("deselect_node", '#' + $(element).attr("id")); } }); //if any previous click has the class for copy or cut $("#{$id_arr[$k]}").find("li").each(function (index, element) { if ($(element) != $(node)) { if ($(element).hasClass("copy") || $(element).hasClass("cut")) control = 1; } else if ($(node).hasClass("cut") || $(node).hasClass("copy")) { control = 0; } }); //only remove the class for cut or copy if the current operation is to paste if ($(node).hasClass("paste")) { control = 0; // Let's loop through all elements and try to find if the paste operation was done already $("#{$id_arr[$k]}").find("li").each(function (index, element) { if ($(element).hasClass("copy")) $(this).removeClass("copy"); if ($(element).hasClass("cut")) $(this).removeClass("cut"); if ($(element).hasClass("paste")) $(this).removeClass("paste"); }); } switch (control) { //Remove the paste item from the context menu case 0: switch ($(node).attr("rel")) { case "drive": delete items.renameItem; delete items.deleteItem; delete items.cutItem; delete items.copyItem; delete items.pasteItem; break; case "default": delete items.pasteItem; break; } break; //Remove the paste item from the context menu only on the node that has either copy or cut added class case 1: if ($(node).hasClass("cut") || $(node).hasClass("copy")) { switch ($(node).attr("rel")) { case "drive": delete items.renameItem; delete items.deleteItem; delete items.cutItem; delete items.copyItem; delete items.pasteItem; break; case "default": delete items.pasteItem; break; } } else //Re-enable it on the clicked node that does not have the cut or copy class { switch ($(node).attr("rel")) { case "drive": delete items.renameItem; delete items.deleteItem; delete items.cutItem; delete items.copyItem; break; } } break; //initial state don't show the paste option on any node default: switch ($(node).attr("rel")) { case "drive": delete items.renameItem; delete items.deleteItem; delete items.cutItem; delete items.copyItem; delete items.pasteItem; break; case "default": delete items.pasteItem; break; } break; } return items; $("#{$id_arr[$k]}").jstree({ // List of active plugins used "plugins" : [ "themes","json_data", "ui", "crrm" , "hotkeys" , "types" , "dnd", "contextmenu"], "contextmenu" : { "items" : customMenu , "select_node": true}, 

您可以修改@ Box9代码,以适应您对dynamic禁用上下文菜单的要求:

 function customMenu(node) { ............ ................ // Disable the "delete" menu item // Original // delete items.deleteItem; if ( node[0].attributes.yyz.value == 'notdelete' ) { items.deleteItem._disabled = true; } } 

您需要在XML或JSOn数据中添加一个属性“xyz”

作为jsTree 3.0.9我需要使用类似的东西

 var currentNode = treeElem.jstree('get_node', node, true); if (currentNode.hasClass("folder")) { // Delete the "delete" menu item delete items.deleteItem; } 

因为提供的node对象不是jQuery对象。