example jquery contextmenu jstree

jquery - example - Configurando jstree menú contextual contextual para diferentes tipos de nodos



jstree example (6)

El complemento contextmenu ya tiene soporte para esto. De la documentación a la que vinculó:

items : Espera un objeto o una función, que debería devolver un objeto . Si se usa una función, se dispara en el contexto del árbol y recibe un argumento: el nodo al que se hizo clic con el botón derecho.

Entonces, en lugar de dar contextmenu un objeto codificado con el que trabajar, puede proporcionar la siguiente función. Comprueba el elemento al que se hizo clic para una clase llamada "carpeta" y elimina el elemento de menú "eliminar" al eliminarlo del objeto:

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

Tenga en cuenta que lo anterior ocultará la opción de eliminar por completo, pero el complemento también le permite mostrar un elemento mientras deshabilita su comportamiento, al agregar _disabled: true al elemento relevante. En este caso, puede usar items.deleteItem._disabled = true dentro de la sentencia if .

Debería ser obvio, pero recuerde inicializar el complemento con la función de customMenu lugar de lo que tenía anteriormente:

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

Editar: si no desea que se vuelva a crear el menú en cada clic con el botón derecho, puede poner la lógica en el controlador de acción para el elemento de menú eliminar.

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

Editar nuevamente: después de mirar el código fuente jsTree, parece que el menú contextual se está recreando cada vez que se muestra de todos modos (vea las funciones show() y parse() ), así que no veo ningún problema con mi primera solución.

Sin embargo, me gusta la notación que está sugiriendo, con una función como el valor de _disabled . Una ruta potencial para explorar es ajustar su función parse() con la suya que evalúa la función en disabled: function () {...} y almacena el resultado en _disabled , antes de llamar al parse() original parse() .

No será difícil modificar su código fuente directamente. La línea 2867 de la versión 1.0-rc1 es la relevante:

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

Simplemente puede agregar una línea antes de esta que comprueba $.isFunction(val._disabled) , y si es así, val._disabled = val._disabled() . A continuación, envíalo a los creadores como un parche :)

He visto un ejemplo en algún lugar en línea que muestra cómo personalizar la apariencia del menú contextual del botón derecho de jstree (usando el complemento contextmenu).

Por ejemplo, permita a mis usuarios eliminar "documentos" pero no "carpetas" (ocultando la opción "eliminar" del menú contextual para las carpetas).

Ahora no puedo encontrar ese ejemplo. ¿Alguien puede señalarme en la dirección correcta? La documentation oficial realmente no ayudó.

Editar:

Como quiero el menú contextual predeterminado con solo uno o dos cambios menores, prefiero no recrear todo el menú (aunque, por supuesto, lo haré si es el único). Lo que me gustaría hacer es algo como esto:

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

pero no funciona: el elemento de creación simplemente está deshabilitado (la alerta nunca aparece).


Implementado con diferentes tipos de nodos:

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

Y la función de menú personalizado:

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

Funciona maravillosamente


Para limpiar todo

En lugar de esto:

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

Utilizar esta:

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


Puede modificar el código de @ Box9 para adaptarlo a su requerimiento de desactivación dinámica del menú contextual como:

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

Necesita agregar un atributo "xyz" en sus datos XML o JSOn


Sin embargo, he adaptado la solución sugerida para trabajar con tipos un poco diferente, tal vez puede ayudar a alguien más:

Donde # {$ id_arr [$ k]} es la referencia al contenedor div ... en mi caso utilizo muchos árboles para que todo este código sea el resultado para el navegador, pero entiendes la idea ... Básicamente quiero todo las opciones del menú contextual, pero solo ''Crear'' y ''Pegar'' en el nodo de Drive. Obviamente con los enlaces correctos a esas operaciones más adelante:

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


a partir de jsTree 3.0.9 que necesitaba usar algo como

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

porque el objeto node que se proporciona no es un objeto jQuery.