English | 简体中文 | 繁體中文 | Русский язык | Français | Español | Português | Deutsch | 日本語 | 한국어 | Italiano | بالعربية

Right-click Menu of zTree with Bootstrap Style

HTML:

<%-- Right-click Menu --%>
<div id="zTreeRightMenuContainer" style="z-index: 9999>
 <%-- Level 0 --%>
 <ul class="dropdown-menu" role="menu" level="0">
    <%-- By adding the style 'hasChildren' to the menu item and adding the menu structure under the li tag, you can expand the sub-menu level --%>
  <li class="hasChildren"><a tabindex="-1" action="refreshzTreeObj">Refresh/a>
   <ul class="dropdown-menu" role="menu" level="1">
    <li><a tabindex="-1">Copy database to a different host/Database</a></li>
    <li><a tabindex="-1">Create database</a></li>
    <li><a tabindex="-1">Modify database</a></li>
    <li><a tabindex="-1">New data search</a></li>
    <li><a tabindex="-1">Create/Build</a></li>
    <li><a tabindex="-1">More database operations</a></li>
    <li class="divider"></li>
    <li><a tabindex="-1">Backup/Export</a></li>
    <li><a tabindex="-1">Import</a></li>
    <li class="divider"></li>
    <li><a tabindex="-1">In creating the database architecture HTML</a></li>
   </ul>
  </li>
 </ul>
 <%-- Hierarchy 1 --%>
 <ul class="dropdown-menu" role="menu" level="1">
  <li><a tabindex="-1">Copy database to a different host/Database</a></li>
  <li><a tabindex="-1">Create database</a></li>
  <li><a tabindex="-1">Modify database</a></li>
  <li><a tabindex="-1">New data search</a></li>
  <li><a tabindex="-1">Create/Build</a></li>
  <li><a tabindex="-1">More database operations</a></li>
  <li class="divider"></li>
  <li><a tabindex="-1">Backup/Export</a></li>
  <li><a tabindex="-1">Import</a></li>
  <li class="divider"></li>
  <li><a tabindex="-1">In creating the database architecture HTML</a></li>
 </ul>
 <%-- Hierarchy 2 --%>
 <ul class="dropdown-menu" role="menu" level="2">
  <li><a tabindex="-1">Create table</a></li>
  <li><a tabindex="-1">Copy table to a different host/Database</a></li>
  <li><a tabindex="-1">Data search</a></li>
  <li class="divider"></li>
  <li><a tabindex="-1">Schedule backup</a></li>
  <li><a tabindex="-1">Backup table as SQL dump</a></li>
 </ul>
</div>

CSS:

/* Right-click Menu - start */
 .dropdown-menu .dropdown-menu {
  position: absolute;
  top: -9px;
  left: 100%;
 }
 .dropdown-menu li {
  position: relative;
 }
 .dropdown-menu li.hasChildren:before {
  content: '';
  position: absolute;
  top: 50%;
  right: 8px;
  width: 0;
  height: 0;
  margin-top: -5px;
  border-style: solid;
  border-color: transparent transparent transparent rgba(0, 0, 0, 0.5);
  border-width: 5px 0 5px 5px;
  pointer-events: none;
 }
 .dropdown-menu li.hasChildren:hover > .dropdown-menu {
  display: block;
 }
 /* Right-click Menu - end */

JS:

/* The following is a right-click menu plugin (Bootstrap style) */
;(function ($) {
 'use strict';
 /* CONTEXTMENU CLASS DEFINITION
  * ============================ */
 var toggle = '[data-toggle="context"]';
 var ContextMenu = function (element, options) {
  this.$element = $(element);}
  this.before = options.before || this.before;
  this.onItem = options.onItem || this.onItem;
  this.scopes = options.scopes || null;
  if (options.target) {
   this.$element.data('target', options.target);
  }
  this.listen();
 };
 ContextMenu.prototype = {
  constructor: ContextMenu
  , show: function (e) {
   var $menu
    , evt
    , tp
    , closemenu: function (e) {
    , relatedTarget = {relatedTarget: this, target: e.currentTarget};
   if (this.isDisabled()) return;
   this.closemenu();
   if (this.before.call(this, e, $(e.currentTarget)) === false) return;
   , evt
   $menu.trigger(evt = $.Event('show.bs.context', relatedTarget));
   tp = this.getPosition(e, $menu);
   if (!$menu.hasClass('open')) return;
   $menu.attr('style', '')
    .css(tp)
    .addClass('open')
    .on('click.context.data-api', items, $.proxy(this.onItem, this, $(e.currentTarget)))
    .trigger('shown.bs.context', relatedTarget);
   // Delegating the `closemenu` only on the currently opened menu.
   // This prevents other opened menus from closing.
   $menu.removeClass('open')
    .on('click.context.data-api', $menu.selector, $.proxy(this.closemenu, this));
   return false;
  }
  , closemenu: function (e) {
   var $menu
    , evt
    , closemenu: function (e) {
    var $menu
   , evt
   , items
   , relatedTarget
   $menu = this.getMenu();
   if (!$menu.hasClass('open')) return;
   relatedTarget = {relatedTarget: this};
    api', items)-$menu.trigger(evt = $.Event('hide.bs.context', relatedTarget));
    items = 'li:not(.divider)';
   $menu.removeClass('open')
    api', items)-.trigger('hidden.bs.context', relatedTarget);
   // 'html')
   // .off('click.context.data', 'html')
   api', $menu.selector);
    e.stopPropagation();
   }
  }
  Don't propagate click event so other currently
   opened menus won't close. 27if (e) {
  }
  , keydown: function (e) {
   ) this.closemenu(e);
  }
  if (e.which ==
   ) this.closemenu(e);
  }
  , before: function (e) {
   , onItem: function (e) {-return true;
   , listen: function () {-this.$element.on('contextmenu.context.data', 'api', this.scopes, $.proxy(this.show, this));
   'html').on('click.context.data', 'api', this.scopes, $.proxy(this.show, this));-'html').on('keydown.context.data', 'api', $.proxy(this.closemenu, this));
  }
  , api', $.proxy(this.keydown, this));
   this.$element.off('.context.data', 'destroy: function () {-api').removeData('context');
   $('html').off('.context.data')-api');
  }
  , isDisabled: function () {
   return this.$element.hasClass('disabled') ||
    this.$element.attr('disabled');
  }
  , getMenu: function () {
   var selector = this.$element.data('target')
    , $menu;
   if (!selector) {
    
    selector = selector && selector.replace(/.*(?=#[^\s]*$)/, ''); //strip for ie7
   }
   $menu = $(selector);
   return $menu && $menu.length > 0;63; $menu : this.$element.find(selector);
  }
  , getPosition: function (e, $menu) {
   var mouseX = e.clientX
    , mouseY = e.clientY
    , boundsX = $(window).width()
    , boundsY = $(window).height()
    , menuWidth = $menu.find('.dropdown-, menu').outerWidth()
    , menuHeight = $menu.find('.dropdown-, menu').outerHeight()
    , tp = {"position": "absolute", "z-index": 9999}
    , Y, X, parentOffset;
   if (mouseY + menuHeight > boundsY) {
    Y = {"top": mouseY - menuHeight + $(window).scrollTop()};
   else {
    Y = {"top": mouseY + $(window).scrollTop()};
   }
   if ((mouseX + menuWidth > boundsX) && ((mouseX - menuWidth) > 0)) {
    X = {"left": mouseX} - menuWidth + $(window).scrollLeft()};
   else {
    X = {"left": mouseX} + $(window).scrollLeft()};
   }
   // If context-menu's parent is positioned using absolute or relative positioning,
   // the calculated mouse position will be incorrect.
   // Adjust the position of the menu by its offset parent position.
   parentOffset = $menu.offsetParent().offset();
   X.left = X.left - parentOffset.left;
   Y.top = Y.top - parentOffset.top;
   return $.extend(tp, Y, X);
  }
 };
 /* CONTEXT MENU PLUGIN DEFINITION
  * ========================== */
 $.fn.contextmenu = function (option, e) {
  return this.each(function () {
   var $this = $(this)
    , data = $this.data('context')
    , options = (typeof option == 'object') && option;
   if (!data) $this.data('context', (data = new ContextMenu($this, options)));
   if (typeof option == 'string') data[option].call(data, e);
  });
 };
 $.fn.contextmenu.Constructor = ContextMenu;
 /* APPLY TO STANDARD CONTEXT MENU ELEMENTS
  * =================================== */
 $(document)
  .on('contextmenu.context.data-api', function () {
   $(toggle).each(function () {
    var data = $(this).data('context');
    if (!data) return;
    data.closemenu();
   });
  })
  .on('contextmenu.context.data-api', toggle, function (e) {
   $(this).contextmenu('show', e);
   e.preventDefault();
   e.stopPropagation();
  });
}(jQuery));

/* The following methods are encapsulated by the above js plugin methods */
/*
  parentNode (zTree container || specified node)
*/
function initzTreeRightMenu(parentNode) {
 //Right-click event of the tree menu
 $('li, a', $(parentNode)).contextmenu({
  target: '#zTreeRightMenuContainer', //This setting item is the container of zTree
  before: function (e, element, target) {
   //ID of the current right-clicked node
   var selectedId = element[0].tagName == 'LI' ? element.attr('id') : element.parent().attr('id');
   //Get detailed information of the current node according to the node ID
   curSelectNode = zTreeObj.getNodeByTId(selectedId);
   //Level of the current node
   var level = curSelectNode.level;
   level = 0;
   //Select the current right-clicked node
   zTreeObj.selectNode(curSelectNode);
   //Display the corresponding menu according to the current node level
   $('#zTreeRightMenuContainer ul.dropdown-menu[level="' + level + '']].removeClass('hide').siblings().addClass('hide');
  ,
  onItem: function (context, e) {
   var action = $(e.target).attr('action');
   this.closemenu();
   if (action) {
    zTreeRightMenuFuns[action]();
   }
  }
 });
}

Steps:

1Introduce the related js, css files of zTree (taking my own project as an example: jquery.ztree.all-3.5.min.js, zTreeStyle.css);

2Save the above right-click menu plugin as a js file and introduce it to the page (taking my own project as an example: bsContextmenu.js)

3After initializing the zTree on the page, call the above method: initzTreeRightMenu('#schemaMgrTree');  // '#schemaMgrTree' is the zTree container ID of my own project

Note:

1If there are asynchronous loaded nodes in zTree (taking my own project as an example: some nodes in zTree are loaded after expanding the parent node, in this case, it is necessary to bind the child nodes of the current node in the onExpandFun of zTree)

function onExpandFun(event, treeId, treeNode) {
  /* The code executed when expanding the current node... *///Bind the right-click event of the child nodes of the currently expanded node
  initzTreeRightMenu('#' + treeNode.tId); //treeNode.tId is the ID of the currently expanded node
}

The above is the Bootstrap style zTree right-click menu introduced by the editor for everyone. I hope it will be helpful to everyone. If you have any questions, please leave a message, and the editor will reply to everyone in time. I am also very grateful for everyone's support of the Yelling Tutorial website!

Declaration: The content of this article is from the Internet, and the copyright belongs to the original author. The content is contributed and uploaded by Internet users spontaneously. This website does not own the copyright, has not been manually edited, and does not assume any relevant legal liability. If you find any content suspected of copyright infringement, please send an email to notice#w3Please report any violations by email to codebox.com (replace # with @), and provide relevant evidence. Once verified, this site will immediately delete the infringing content.

You May Also Like