contextmenu
Плагин уже имеет поддержку для этого. Из документации, на которую вы ссылаетесь:
items
: Ожидает объект или функцию, которая должна вернуть объект . Если функция используется, она запускается в контексте дерева и получает один аргумент - узел, который был нажат правой кнопкой мыши.
Поэтому вместо того, чтобы давать contextmenu
жестко запрограммированный объект для работы, вы можете предоставить следующую функцию. Он проверяет элемент, который был выбран для класса с именем «папка», и удаляет пункт меню «удалить», удаляя его из объекта:
function customMenu(node) {
var items = {
renameItem: {
label: "Rename",
action: function () {...}
},
deleteItem: {
label: "Delete",
action: function () {...}
}
};
if ($(node).hasClass("folder")) {
delete items.deleteItem;
}
return items;
}
Обратите внимание, что приведенное выше полностью скроет параметр удаления, но плагин также позволяет отображать элемент при отключении его поведения, добавляя _disabled: true
к соответствующему элементу. В этом случае вы можете использовать вместо этого items.deleteItem._disabled = true
внутри if
инструкции.
Это должно быть очевидно, но не забудьте инициализировать плагин с customMenu
функцией вместо того, что было раньше:
$("#tree").jstree({plugins: ["contextmenu"], contextmenu: {items: customMenu}});
// ^
// ___________________________________________________________________|
Изменить: если вы не хотите, чтобы меню воссоздавалось при каждом щелчке правой кнопкой мыши, вы можете поместить логику в обработчик действий для самого пункта меню удаления.
"label": "Delete",
"action": function (obj) {
if ($(this._get_node(obj)).hasClass("folder") return;
}
Снова отредактируйте: посмотрев исходный код jsTree, похоже, что контекстное меню создается заново каждый раз, когда оно все равно отображается (см. show()
Иparse()
функции), так что я не вижу проблемы с моим первым решением.
Однако мне нравятся предлагаемые вами обозначения с функцией в качестве значения _disabled
. Потенциальный путь для изучения - обернуть их parse()
функцию вашей собственной, которая оценивает функцию disabled: function () {...}
и сохраняет результат _disabled
перед вызовом оригинала parse()
.
Также не составит труда модифицировать их исходный код напрямую. Строка 2867 версии 1.0-rc1 является соответствующей:
str += "<li class='" + (val._class || "") + (val._disabled ? " jstree-contextmenu-disabled " : "") + "'><ins "
Вы можете просто добавить строку перед проверяющей $.isFunction(val._disabled)
, и если да, то val._disabled = val._disabled()
. Тогда отправьте его создателям как патч :)
var items
за пределы функции, чтобы она создавалась только один раз, и возвращать выбранные элементы из функции, например,return {renameItem: items.renameItem};
илиreturn {renameItem: items.renameItem, deleteItem: items.deleteItem};
<a>
элемент хранится в$.vakata.context.tgt
. Так что попробуйте поискать$.vakata.context.tgt.attr("rel")
.if ($(node).hasClass("folder"))
не сработало. но это произошло:if (node.children.length > 0) { items.deleteItem._disabled = true; }
Реализовано с разными типами узлов:
$('#jstree').jstree({ 'contextmenu' : { 'items' : customMenu }, 'plugins' : ['contextmenu', 'types'], 'types' : { '#' : { /* options */ }, 'level_1' : { /* options */ }, 'level_2' : { /* options */ } // etc... } });
И функция customMenu:
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; }
Красиво работает.
источник
type
атрибут, а не на класс CSS, полученный с помощью jQuery.'action': function () { /* action */ }
во второй фрагмент? Что если вы хотите использовать «обычные» функции и пункты меню, но просто удалить один из них (например, удалить «Удалить», но оставить «Переименовать» и «Создать»)? На мой взгляд, это действительно то, о чем спрашивал ОП. Конечно, вам не нужно переписывать функции для таких вещей, как Rename и Create, если вы удалите другой элемент, такой как Delete?items
списке объектов, а затемnode.type
в концеcustomMenu
функции указываете, какие из этих элементов следует удалить для данной функции. Когда пользователь щелкает узел из заданногоtype
, в контекстном меню будут перечислены все элементы за вычетом любых удаленных в условном выражении в концеcustomMenu
функции. Вы не переписываете какие-либо функции (если jstree не изменился с момента этого ответа три года назад, и в этом случае он может больше не иметь значения).Чтобы все очистить.
Вместо этого:
$("#xxx").jstree({ 'plugins' : 'contextmenu', 'contextmenu' : { 'items' : { ... bla bla bla ...} } });
Использовать этот:
$("#xxx").jstree({ 'plugins' : 'contextmenu', 'contextmenu' : { 'items' : customMenu } });
источник
Предлагаемое решение для работы с типами я адаптировал немного иначе, возможно, это поможет кому-то другому:
Где # {$ id_arr [$ k]} - это ссылка на контейнер div ... в моем случае я использую много деревьев, поэтому весь этот код будет выводиться в браузер, но вы поняли идею .. В основном я хочу все параметры контекстного меню, но только «Создать» и «Вставить» в узле «Диск». Очевидно, с правильными привязками к этим операциям позже:
<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},
источник
Кстати: если вы просто хотите удалить параметры из существующего контекстного меню - это сработало для меня:
function customMenu(node) { var items = $.jstree.defaults.contextmenu.items(node); if (node.type === 'root') { delete items.create; delete items.rename; delete items.remove; delete items.ccp; } return items; }
источник
Вы можете изменить код @ Box9 в соответствии с вашим требованием динамического отключения контекстного меню следующим образом:
function customMenu(node) { ............ ................ // Disable the "delete" menu item // Original // delete items.deleteItem; if ( node[0].attributes.yyz.value == 'notdelete' ) { items.deleteItem._disabled = true; } }
Вам нужно добавить один атрибут "xyz" в ваши данные XML или JSOn.
источник
с 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.источник
Ответ Дэвида кажется прекрасным и эффективным. Я нашел еще один вариант решения, в котором вы можете использовать атрибут a_attr, чтобы различать разные узлы, и на основе этого вы можете создавать другое контекстное меню.
В приведенном ниже примере я использовал два типа узлов: Папка и Файлы. Я также использовал разные значки, используя глификон. Для узла типа файла вы можете получить только контекстное меню для переименования и удаления. Для папки есть все параметры: создать файл, создать папку, переименовать, удалить.
Полный фрагмент кода можно найти на странице https://everyething.com/Example-of-jsTree-with-different-context-menu-for-different-node-type.
$('#SimpleJSTree').jstree({ "core": { "check_callback": true, 'data': jsondata }, "plugins": ["contextmenu"], "contextmenu": { "items": function ($node) { var tree = $("#SimpleJSTree").jstree(true); if($node.a_attr.type === 'file') return getFileContextMenu($node, tree); else return getFolderContextMenu($node, tree); } } });
Исходные данные json приведены ниже, где тип узла указан в a_attr.
var jsondata = [ { "id": "ajson1", "parent": "#", "text": "Simple root node", icon: 'glyphicon glyphicon-folder-open', "a_attr": {type:'folder'} }, { "id": "ajson2", "parent": "#", "text": "Root node 2", icon: 'glyphicon glyphicon-folder-open', "a_attr": {type:'folder'} }, { "id": "ajson3", "parent": "ajson2", "text": "Child 1", icon: 'glyphicon glyphicon-folder-open', "a_attr": {type:'folder'} }, { "id": "ajson4", "parent": "ajson2", "text": "Child 2", icon: 'glyphicon glyphicon-folder-open', "a_attr": {type:'folder'} }, ];
В рамках пункта контекстного меню для создания файла и папки используйте аналогичный код ниже, как действие с файлом.
action: function (obj) { $node = tree.create_node($node, { text: 'New File', icon: 'glyphicon glyphicon-file', a_attr:{type:'file'} }); tree.deselect_all(); tree.select_node($node); }
как действие с папкой:
action: function (obj) { $node = tree.create_node($node, { text: 'New Folder', icon:'glyphicon glyphicon-folder-open', a_attr:{type:'folder'} }); tree.deselect_all(); tree.select_node($node); }
источник