Use el menú desplegable de Bootstrap 3 como menú contextual

Usando Bootstrap 3, ¿cómo puedo colocar el menú desplegable en el cursor y abrirlo desde el código?

Necesito usarlo en una tabla como un menú contextual para sus filas.

Es posible. Te hice una demostración funcional para comenzar bien.

Demostración de trabajo (haga clic con el botón derecho en cualquier fila de la tabla para verla en acción)

Primero crea tu menú desplegable, escóndelo y cambia su position a absolute :

 #contextMenu { position: absolute; display:none; } 

A continuación, vincula un evento contextmenu a las filas de la tabla para que muestre el menú desplegable / contextual y contextmenu en el cursor:

 var $contextMenu = $("#contextMenu"); $("body").on("contextmenu", "table tr", function(e) { $contextMenu.css({ display: "block", left: e.pageX, top: e.pageY }); return false; }); 

Luego, cuando el usuario seleccione una opción ocultar menú desplegable / contexto:

 $contextMenu.on("click", "a", function() { $contextMenu.hide(); }); 

Solo quería mejorar letiagoalves, una gran respuesta con un par de sugerencias más.
Aquí hay un tutorial sobre cómo agregar un menú contextual a cualquier elemento html.

Comencemos con una demostración funcional en jsFiddle

Margen:

Primero, agreguemos un menú desde el control desplegable de arranque . Añádalo a cualquier parte de su HTML, preferiblemente en el nivel raíz del cuerpo. La clase .dropdown-menu establecerá display:none por lo que inicialmente es invisible.
Debe tener un aspecto como este:

  

Configuración de la extensión:

Para mantener nuestro diseño modular, agregaremos nuestro código JavaScript como una extensión jQuery llamada contextMenu .

Cuando llamamos $.contextMenu , pasaremos un objeto de configuración con 2 propiedades:

  1. menuSelector toma el selector jQuery del menú que creamos anteriormente en HTML.
  2. Se llamará al menú seleccionado cuando se haga clic en la acción del menú contextual.
 $("#myTable").contextMenu({ menuSelector: "#contextMenu", menuSelected: function (invokedOn, selectedMenu) { // context menu clicked }); }); 

Plantilla de complemento:

Basándonos en la plantilla del complemento repetitivo jQuery , usaremos una Expresión de Función Invocada Inmediatamente para no confundir el espacio de nombres global. Como tenemos dependencias en jQuery y necesitamos acceso a la ventana, las pasaremos como variables para que podamos sobrevivir a la minificación. Se verá así:

 (function($, window){ $.fn. contextMenu = function(settings) { return this.each(function() { // Code Goes Here } }; })(jQuery, window); 

De acuerdo, no más plomería. Aquí está la carne de la función:

Gestionar eventos de clic derecho:

contextmenu el evento del mouse contextmenu en el objeto que llamó a la extensión. Cuando se desate el evento, seleccionaremos el menú desplegable que agregamos al principio. Lo localizaremos usando la cadena de selector pasada por la configuración cuando inicializamos la función. Modificaremos el menú haciendo lo siguiente:

  • e.target propiedad e.target y la almacenaremos como un atributo de datos llamado invokedOn , para luego poder identificar el elemento que generó el menú contextual.
  • Alternaremos la visualización del menú a visible usando .show()
  • Posicionaremos el elemento usando .css() .
    • Necesitamos asegurarnos de que su position esté establecida en absolute .
    • A continuación, estableceremos la ubicación izquierda y superior con las propiedades pageX y pageY del evento.
  • Finalmente, para evitar que la acción de clic derecho abra su propio menú, return false para evitar que javascript maneje cualquier otra cosa.

Se verá así:

 $(this).on("contextmenu", function (e) { $(settings.menuSelector) .data("invokedOn", $(e.target)) .show() .css({ position: "absolute", left: e.pageX, top: e.pageY }); return false; }); 

Arreglar casos de borde de menú:

Esto abrirá el menú en la parte inferior derecha del cursor que lo abrió. Sin embargo, si el cursor está en el extremo derecho de la pantalla , el menú debería abrirse hacia la izquierda. Del mismo modo, si el cursor está en la parte inferior, el menú debería abrirse hacia arriba. También es importante diferenciar entre la parte inferior de la window , que contiene el marco físico, y la parte inferior del document que representa todo el html DOM y puede desplazarse más allá de la ventana.

Para lograr esto, estableceremos la ubicación usando las siguientes funciones:

Los llamaremos así:

 .css({ left: getMenuPosition(e.clientX, 'width', 'scrollLeft'), top: getMenuPosition(e.clientY, 'height', 'scrollTop') }); 

Que llamará a esta función para devolver la posición adecuada:

 function getMenuPosition(mouse, direction, scrollDir) { var win = $(window)[direction](), scroll = $(window)[scrollDir](), menu = $(settings.menuSelector)[direction](), position = mouse + scroll; // opening menu would pass the side of the page if (mouse + menu > win && menu < mouse) position -= menu; return position } 

Enlazar eventos de clic en el elemento del menú:

Después de mostrar el menú contextual, necesitamos agregar un controlador de eventos para escuchar eventos de clics en él. Eliminaremos cualquier otro enlace que ya se haya agregado para que no activemos el mismo evento dos veces. Esto puede ocurrir cada vez que se abre el menú, pero no se seleccionó nada debido a un clic apagado. Luego, podemos agregar un nuevo enlace en el evento click donde gestionaremos la lógica en la siguiente sección.

Como valepu señaló , no queremos registrar los clics en ningún elemento que no sea el menú, por lo que configuramos un controlador delegado pasando un selector a la función on que "filtrará los descendientes de los elementos seleccionados que activan el evento".

Hasta ahora, la función debería verse así:

 $(settings.menuSelector) .off('click') .on( 'click', "a", function (e) { //CODE IN NEXT SECTION GOES HERE }); 

Manejar clics del menú

Una vez que sepamos que se ha producido un clic en el menú, haremos lo siguiente: .hide() el menú de la pantalla con .hide() . A continuación, queremos guardar el elemento en el que se invocó originalmente el menú, así como la selección del menú actual. Finalmente, .call() la opción de función que se pasó a la extensión utilizando .call() en la propiedad y pasando los objectives del evento como argumentos.

 $menu.hide(); var $invokedOn = $menu.data("invokedOn"); var $selectedMenu = $(e.target); settings.menuSelected.call($(this), $invokedOn, $selectedMenu); 

Ocultar cuando se hace clic en Off:

Finalmente, como con la mayoría de los menús contextuales, queremos cerrar el menú cuando un usuario también hace clic fuera de él. Para hacerlo, escucharemos cualquier evento de clic en el cuerpo y cerraremos el menú contextual si está abierto así:

 $('body').click(function () { $(settings.menuSelector).hide(); }); 

Nota : Gracias al comentario de Sadhir , Firefox Linux activa el evento click en el document durante un clic derecho, por lo que debe configurar el oyente en el body .

Ejemplo de syntax:

La extensión volverá con el objeto original que generó el menú contextual y el elemento de menú en el que se hizo clic. Puede que tenga que atravesar el dominio usando jQuery para encontrar algo significativo a partir de los objectives del evento, pero esto debería proporcionar una buena capa de funcionalidad básica.

Aquí hay un ejemplo para devolver información para el artículo y la acción seleccionada:

 $("#myTable").contextMenu({ menuSelector: "#contextMenu", menuSelected: function (invokedOn, selectedMenu) { var msg = "You selected the menu item '" + selectedMenu.text() + "' on the value '" + invokedOn.text() + "'"; alert(msg); } }); 

Captura de pantalla:

Captura de pantalla del menú contextual

Nota de actualización:

Esta respuesta se ha actualizado sustancialmente envolviéndola en un método de extensión jQuery. Si desea ver mi original, puede ver el historial de publicaciones, pero creo que esta versión final utiliza prácticas de encoding mucho mejores.

Característica de bonificación :

Si desea agregar algunas buenas funcionalidades para usuarios avanzados o para usted mismo en el desarrollo de funciones, puede omitir el menú contextual en función de las combinaciones de teclas que se lleven a cabo cuando haga clic con el botón derecho. Por ejemplo, si desea permitir que se muestre el menú contextual del navegador original al mantener presionada la tecla Ctrl , puede agregar esto como la primera línea del controlador contextMenu:

 // return native menu if pressing control if (e.ctrlKey) return; 

Se agregaron algunas modificaciones al código de KyleMit :

  • movió el controlador “al hacer clic en el documento” de “foreach”
  • eliminado “foreach”, simplemente agrega evento al selector
  • ocultar el menú en “menú contextual del documento”
  • eventos de paso

     $("#myTable tbody td").contextMenu({ menuSelector: "#contextMenu", menuSelected: function (invokedOn, selectedMenu) { var msg = "You selected the menu item '" + selectedMenu.text() + "' on the value '" + invokedOn.text() + "'"; alert(msg); }, onMenuShow: function(invokedOn) { var tr = invokedOn.closest("tr"); $(tr).addClass("warning"); }, onMenuHide: function(invokedOn) { var tr = invokedOn.closest("tr"); $(tr).removeClass("warning"); } }); 

http://jsfiddle.net/dmitry_far/cgqft4k3/

Encontré este menú contextual simple y funcional. Estoy usando esta biblioteca http://swisnl.github.io/jQuery-contextMenu/index.html . Espero eso ayude

mesa:

  < ?php foreach($items as $item){?>  < ?php }?> 
Code General Description Unit Quantity Estimated Budget Mode of Procurement
< ?php echo $item->id;?> < ?php echo $item->description;?> < ?php echo $item->unit;?> < ?php echo $item->quantity;?> < ?php echo $item->budget;?> < ?php echo $item->mode;?>
Total

Menú de contexto:

  "edit": { name: "Edit", icon: "fa-pencil-square-o", callback: function(item, id) { return true; } }, "delete": { name: "Delete", icon: "fa-trash-o", callback: function(item, id) { return true; } },