Use the Bootstrap 3 drop-down menu as the context menu

Using Bootstrap 3, how can I put a drop-down menu in the cursor and open it from the code?

I need to use it in a table as a context menu for its rows.

+58
jquery twitter-bootstrap twitter-bootstrap-3
Sep 06 '13 at 21:06 on
source share
4 answers

It is possible. I made you a working demo to get you started.

Working demo (right-click on any row of the table to see it in action)

First create a drop-down menu, hide it and change its position to absolute :

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

Then bind the contextmenu event to your table rows so that it displays a drop-down menu / context menu and positions it under the cursor:

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

Then, when the user selects the hide dropdown / context menu option:

 $contextMenu.on("click", "a", function() { $contextMenu.hide(); }); 
+80
Sep 06 '13 at 21:41
source share

I just wanted to improve letiagoalves excellent answer with a few more suggestions.
Here you will find a step-by-step guide on how to add a context menu to any html element.

Let the working demo begin in jsFiddle

Markup:

First, add the menu from the bootstrap drop-down list . Add it anywhere in your HTML, preferably at the root level of the body. The .dropdown-menu class sets display:none , so it is initially invisible.
It should look like this:

 <ul id="contextMenu" class="dropdown-menu" role="menu"> <li><a tabindex="-1" href="#">Action</a></li> <li><a tabindex="-1" href="#">Another action</a></li> <li><a tabindex="-1" href="#">Something else here</a></li> <li class="divider"></li> <li><a tabindex="-1" href="#">Separated link</a></li> </ul> 

Extension Settings:

To preserve the modular design, we will add our JavaScript code as a jQuery extension called contextMenu .

When we call $.contextMenu , we will pass a settings object with two properties:

  • menuSelector accepts the jQuery menu selector that we created earlier in HTML.
  • menuSelected will be called when you click on the action of the context menu.
 $("#myTable").contextMenu({ menuSelector: "#contextMenu", menuSelected: function (invokedOn, selectedMenu) { // context menu clicked }); }); 

Plugin Template:

Based on the jQuery template plugin template , we will use the Immediately-Invoked Function Expression so that we do not confuse the global namespace. Since we have jQuery dependencies and need access to the window, we will pass them as variables so that we can survive while minimizing. It will look like this:

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

Well, no more plumbing. Here's the meat function:

Handle events with the right mouse button:

We will handle the mouse event of the contextMenu object, which is called an extension. When the event fires, we take the drop-down menu that we added at the beginning. We will find it using the selector string passed by the parameters when initializing this function. We will change the menu by following these steps:

  • We e.target property and save it as a data attribute called invokedOn , so we can later identify the item that raised the context menu.
  • We will switch the menu display to visible using .show()
  • We will place the element using .css() .
    • We need to make sure that this position parameter is set to absolute .
    • Then we will set the left and top location using the pageX and pageY event.
  • Finally, to prevent right-clicking on the opening of our own menu, we return false to stop javascript from working with anything else.

It will look like this:

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

Correction of the boundary conditions of the menu:

This will open the menu at the bottom right of the cursor that opened it. However, if the cursor is to the right of the screen , the menu should open to the left. Similarly, if the cursor is at the bottom, the menu should open at the top. It is also important to distinguish between the bottom of the window , which contains the physical frame, and the bottom of the document , which represents the entire html DOM, and can scroll far past the window.

To do this, we will set the location using the following functions:

We will call them as follows:

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

This function will call this function to return the corresponding position:

 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 } 

Bind events to a menu item:

After displaying the context menu, we need to add an event handler to listen for click events on it. We will remove any other bindings that might be added so that we do not fire the same event twice. They can occur at any time when the menu was opened, but nothing was selected due to a click. Then we can add a new binding to the click event, where we look at the logic in the next section.

As valepu noted , we don’t want to register clicks on anything other than menu items, so we configure the delegated handler by passing a selector to the on function, which will "filter the descendants of the selected elements that trigger the event."

So far, the function should look like this:

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

Mouse click

As soon as we find out that a click has occurred in the menu, we will do the following: we will hide the menu from the .hide() screen. Then we want to save the item from which the menu was called, as well as the selection from the current menu. Finally, we run the option of the function that was passed to the extension using .call() on the property and pass it to the targets as arguments.

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

Hide on click:

Finally, as in most context menus, we want to close the menu when the user clicks on it. To do this, we will listen to any click events on the body and close the context menu if it is open as follows:

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

Note : Thanks to Sadhir's comment , Firefox linux fires the click event on document during a right-click, so you need to set the listener to body .

Example Syntax:

The extension will return with the original object that raised the context menu and the menu item that was clicked. You may have to cross dom with jQuery to find something meaningful from the targets, but this should provide a good level of basic functionality.

Here is an example of returning information for the selected item and action:

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

Screenshot:

Context Menu Screenshot

Update Note:

This answer has been substantially updated by porting it to the jQuery extension method. If you want to see my original, you can view the message history, but I believe that this final version uses much better coding methods.

Bonus Function :

If you want to add some useful functions for powerusers or on your own in the development of functions, you can bypass the context menu based on any key combinations that are held when you right-click. For example, if you want to allow the context menu of the source browser to be displayed while holding Ctrl , you can add this as the first line of the contextMenu handler:

 // return native menu if pressing control if (e.ctrlKey) return; 
+118
Sep 06 '13 at 22:10
source share

Added some changes to the KyleMit code:

  • moved the "click document" handler from "foreach"
  • removed "foreach", just add the event to the selector
  • hide the menu in the document context menu
  • event transmission

     $("#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/

+4
Jul 08 '15 at 23:04 on
source share

I found this simple and working context menu. I am using this library http://swisnl.imtqy.com/jQuery-contextMenu/index.html . Hope this helps.

Table:

 <table id="ppmpsupplies" class="table table-bordered table-hover" cellspacing="0" width="100%"> <thead> <tr> <th>Code</th> <th>General Description</th> <th>Unit</th> <th>Quantity</th> <th>Estimated Budget</th> <th>Mode of Procurement</th> </tr> </thead> <tbody> <?php foreach($items as $item){?> <tr> <td><?php echo $item->id;?></td> <td><?php echo $item->description;?></td> <td><?php echo $item->unit;?></td> <td><?php echo $item->quantity;?></td> <td><?php echo $item->budget;?></td> <td><?php echo $item->mode;?></td> </tr> <?php }?> </tbody> <tfoot> <td colspan="3"></td> <td>Total</td> <td></td> </tfoot> </table> 

ContextMenu:

  "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; } }, 
-one
Jun 18 '17 at 6:10
source share



All Articles