hover_dropdown.min.js 6.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150
  1. /**
  2. * @preserve
  3. * Project: Bootstrap Hover Dropdown
  4. * Author: Cameron Spear
  5. * Version: v2.2.1
  6. * Contributors: Mattia Larentis
  7. * Dependencies: Bootstrap's Dropdown plugin, jQuery
  8. * Description: A simple plugin to enable Bootstrap dropdowns to active on hover and provide a nice user experience.
  9. * License: MIT
  10. * Homepage: http://cameronspear.com/blog/bootstrap-dropdown-on-hover-plugin/
  11. */
  12. ;(function ($, window, undefined) {
  13. // outside the scope of the jQuery plugin to
  14. // keep track of all dropdowns
  15. var $allDropdowns = $();
  16. // if instantlyCloseOthers is true, then it will instantly
  17. // shut other nav items when a new one is hovered over
  18. $.fn.dropdownHover = function (options) {
  19. // don't do anything if touch is supported
  20. // (plugin causes some issues on mobile)
  21. if('ontouchstart' in document) return this; // don't want to affect chaining
  22. // the element we really care about
  23. // is the dropdown-toggle's parent
  24. $allDropdowns = $allDropdowns.add(this.parent()).add(this.parent().children('.dropdown-menu'));
  25. return this.each(function () {
  26. var $this = $(this),
  27. $parent = $this.parent(),
  28. defaults = {
  29. delay: 500,
  30. hoverDelay: 0,
  31. instantlyCloseOthers: true
  32. },
  33. data = {
  34. delay: $(this).data('delay'),
  35. hoverDelay: $(this).data('hover-delay'),
  36. instantlyCloseOthers: $(this).data('close-others')
  37. },
  38. showEvent = 'show.bs.dropdown',
  39. hideEvent = 'hide.bs.dropdown',
  40. // shownEvent = 'shown.bs.dropdown',
  41. // hiddenEvent = 'hidden.bs.dropdown',
  42. settings = $.extend(true, {}, defaults, options, data),
  43. timeout, timeoutHover;
  44. $parent.hover(function (event) {
  45. // so a neighbor can't open the dropdown
  46. if(!$parent.hasClass('show') && !$this.is(event.target)) {
  47. // stop this event, stop executing any code
  48. // in this callback but continue to propagate
  49. return true;
  50. }
  51. openDropdown(event);
  52. }, function () {
  53. if($this.parents(".navbar").find(".navbar-toggler").is(":visible")) {
  54. // If we're inside a navbar, don't do anything when the
  55. // navbar is collapsed, as it makes the navbar pretty unusable.
  56. return;
  57. }
  58. // clear timer for hover event
  59. window.clearTimeout(timeoutHover)
  60. timeout = window.setTimeout(function () {
  61. $this.attr('aria-expanded', 'false');
  62. $parent.removeClass('show');
  63. $parent.children('.dropdown-menu').removeClass('show');
  64. $this.trigger(hideEvent);
  65. }, settings.delay);
  66. });
  67. // this helps with button groups!
  68. $this.hover(function (event) {
  69. // this helps prevent a double event from firing.
  70. // see https://github.com/CWSpear/bootstrap-hover-dropdown/issues/55
  71. if(!$parent.hasClass('show') && !$parent.is(event.target)) {
  72. // stop this event, stop executing any code
  73. // in this callback but continue to propagate
  74. return true;
  75. }
  76. openDropdown(event);
  77. });
  78. // handle submenus
  79. $parent.find('.dropdown-submenu').each(function (){
  80. var $this = $(this);
  81. var subTimeout;
  82. if($this.parents(".navbar").find(".navbar-toggler").is(":visible")) {
  83. // If we're inside a navbar, don't do anything when the
  84. // navbar is collapsed, as it makes the navbar pretty unusable.
  85. return;
  86. }
  87. $this.hover(function () {
  88. window.clearTimeout(subTimeout);
  89. $this.addClass('show');
  90. $this.children('.dropdown-menu').addClass('show');
  91. // always close submenu siblings instantly
  92. $this.siblings().children('.dropdown-menu').removeClass('show');
  93. }, function () {
  94. var $submenu = $this.children('.dropdown-menu'),
  95. // $parent = $this.parent('dropdown-submenu');
  96. subTimeout = window.setTimeout(function () {
  97. $submenu.removeClass('show');
  98. $this.removeClass('show');
  99. }, settings.delay);
  100. });
  101. });
  102. function openDropdown(event) {
  103. if($this.parents(".navbar").find(".navbar-toggler").is(":visible")) {
  104. // If we're inside a navbar, don't do anything when the
  105. // navbar is collapsed, as it makes the navbar pretty unusable.
  106. return;
  107. }
  108. // clear dropdown timeout here so it doesnt close before it should
  109. window.clearTimeout(timeout);
  110. // restart hover timer
  111. window.clearTimeout(timeoutHover);
  112. // delay for hover event.
  113. timeoutHover = window.setTimeout(function () {
  114. $allDropdowns.find(':focus').blur();
  115. if(settings.instantlyCloseOthers === true) {
  116. $allDropdowns.removeClass('show');
  117. // $allDropdowns.children('.dropdown-menu').removeClass('show');
  118. }
  119. // clear timer for hover event
  120. window.clearTimeout(timeoutHover);
  121. $this.attr('aria-expanded', 'true');
  122. $parent.addClass('show');
  123. $parent.children('.dropdown-menu').addClass('show');
  124. $this.trigger(showEvent);
  125. }, settings.hoverDelay);
  126. }
  127. });
  128. };
  129. $(document).ready(function () {
  130. // apply dropdownHover to all elements with the data-hover="dropdown" attribute
  131. $('[data-hover="dropdown"]').dropdownHover();
  132. });
  133. })(jQuery, window);