jquery.jdMenu.js 4.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171
  1. /*
  2. * jdMenu 1.4.1 (2008-03-31)
  3. *
  4. * Copyright (c) 2006,2007 Jonathan Sharp (http://jdsharp.us)
  5. * Dual licensed under the MIT (MIT-LICENSE.txt)
  6. * and GPL (GPL-LICENSE.txt) licenses.
  7. *
  8. * http://jdsharp.us/
  9. *
  10. * Built upon jQuery 1.2.1 (http://jquery.com)
  11. * This also requires the jQuery dimensions >= 1.2 plugin
  12. */
  13. // This initializes the menu
  14. $(function() {
  15. $('ul.jd_menu').jdMenu();
  16. });
  17. (function($){
  18. function addEvents(ul) {
  19. var settings = $.data( $(ul).parents().andSelf().filter('ul.jd_menu')[0], 'jdMenuSettings' );
  20. $('> li', ul)
  21. .bind('mouseenter.jdmenu mouseleave.jdmenu', function(evt) {
  22. $(this).toggleClass('jdm_hover');
  23. var ul = $('> ul', this);
  24. if ( ul.length == 1 ) {
  25. clearTimeout( this.$jdTimer );
  26. var enter = ( evt.type == 'mouseenter' );
  27. var fn = ( enter ? showMenu : hideMenu );
  28. this.$jdTimer = setTimeout(function() {
  29. fn( ul[0], settings.onAnimate, settings.isVertical );
  30. }, enter ? settings.showDelay : settings.hideDelay );
  31. }
  32. })
  33. .bind('click.jdmenu', function(evt) {
  34. var ul = $('> ul', this);
  35. if ( ul.length == 1 &&
  36. ( settings.disableLinks == true || $(this).hasClass('accessible') ) ) {
  37. showMenu( ul, settings.onAnimate, settings.isVertical );
  38. return false;
  39. }
  40. // The user clicked the li and we need to trigger a click for the a
  41. if ( evt.target == this ) {
  42. var link = $('> a', evt.target).not('.accessible');
  43. if ( link.length > 0 ) {
  44. var a = link[0];
  45. if ( !a.onclick ) {
  46. window.open( a.href, a.target || '_self' );
  47. } else {
  48. $(a).trigger('click');
  49. }
  50. }
  51. }
  52. if ( settings.disableLinks ||
  53. ( !settings.disableLinks && !$(this).parent().hasClass('jd_menu') ) ) {
  54. $(this).parent().jdMenuHide();
  55. evt.stopPropagation();
  56. }
  57. })
  58. .find('> a')
  59. .bind('focus.jdmenu blur.jdmenu', function(evt) {
  60. var p = $(this).parents('li:eq(0)');
  61. if ( evt.type == 'focus' ) {
  62. p.addClass('jdm_hover');
  63. } else {
  64. p.removeClass('jdm_hover');
  65. }
  66. })
  67. .filter('.accessible')
  68. .bind('click.jdmenu', function(evt) {
  69. evt.preventDefault();
  70. });
  71. }
  72. function showMenu(ul, animate, vertical) {
  73. var ul = $(ul);
  74. if ( ul.is(':visible') ) {
  75. return;
  76. }
  77. ul.bgiframe();
  78. var li = ul.parent();
  79. ul .trigger('jdMenuShow')
  80. .positionBy({ target: li[0],
  81. targetPos: ( vertical === true || !li.parent().hasClass('jd_menu') ? 1 : 3 ),
  82. elementPos: 0,
  83. hideAfterPosition: true
  84. });
  85. if ( !ul.hasClass('jdm_events') ) {
  86. ul.addClass('jdm_events');
  87. addEvents(ul);
  88. }
  89. li .addClass('jdm_active')
  90. // Hide any adjacent menus
  91. .siblings('li').find('> ul:eq(0):visible')
  92. .each(function(){
  93. hideMenu( this );
  94. });
  95. if ( animate === undefined ) {
  96. ul.show();
  97. } else {
  98. animate.apply( ul[0], [true] );
  99. }
  100. }
  101. function hideMenu(ul, animate) {
  102. var ul = $(ul);
  103. $('.bgiframe', ul).remove();
  104. ul .filter(':not(.jd_menu)')
  105. .find('> li > ul:eq(0):visible')
  106. .each(function() {
  107. hideMenu( this );
  108. })
  109. .end();
  110. if ( animate === undefined ) {
  111. ul.hide()
  112. } else {
  113. animate.apply( ul[0], [false] );
  114. }
  115. ul .trigger('jdMenuHide')
  116. .parents('li:eq(0)')
  117. .removeClass('jdm_active jdm_hover')
  118. .end()
  119. .find('> li')
  120. .removeClass('jdm_active jdm_hover');
  121. }
  122. // Public methods
  123. $.fn.jdMenu = function(settings) {
  124. // Future settings: activateDelay
  125. var settings = $.extend({ // Time in ms before menu shows
  126. showDelay: 200,
  127. // Time in ms before menu hides
  128. hideDelay: 500,
  129. // Should items that contain submenus not
  130. // respond to clicks
  131. disableLinks: true
  132. // This callback allows for you to animate menus
  133. //onAnimate: null
  134. }, settings);
  135. if ( !$.isFunction( settings.onAnimate ) ) {
  136. settings.onAnimate = undefined;
  137. }
  138. return this.filter('ul.jd_menu').each(function() {
  139. $.data( this,
  140. 'jdMenuSettings',
  141. $.extend({ isVertical: $(this).hasClass('jd_menu_vertical') }, settings)
  142. );
  143. addEvents(this);
  144. });
  145. };
  146. $.fn.jdMenuUnbind = function() {
  147. $('ul.jdm_events', this)
  148. .unbind('.jdmenu')
  149. .find('> a').unbind('.jdmenu');
  150. };
  151. $.fn.jdMenuHide = function() {
  152. return this.filter('ul').each(function(){
  153. hideMenu( this );
  154. });
  155. };
  156. // Private methods and logic
  157. $(window)
  158. // Bind a click event to hide all visible menus when the document is clicked
  159. .bind('click.jdmenu', function(){
  160. $('ul.jd_menu ul:visible').jdMenuHide();
  161. });
  162. })(jQuery);