jquery.drilldown.js 6.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165
  1. /**
  2. * Generic menu drilldown plugin for standard Drupal menu tree markup.
  3. * The plugin should be inited against a DOM element that *contains*
  4. * a Drupal ul.menu tree. Example:
  5. *
  6. * $('div.block-menu').drilldown('init', params);
  7. *
  8. * You must provide the following parameters as settings:
  9. *
  10. * var params = {
  11. * activePath : A drupal menu path that is currently active including the basePath e.g. "/mysite/node"
  12. * trail : A jquery selector to the DOM element that should act as the trail container, e.g. "div.my-menu-breadcrumb-trail"
  13. * rootTitle : The title to use for the root menu item if the menu does not already possess one. Optional.
  14. * }
  15. *
  16. */
  17. (function($) {
  18. $.fn.drilldown = function(method, settings) {
  19. var menu = this;
  20. var activePath;
  21. var rootTitle = settings.rootTitle || 'Home';
  22. switch (method) {
  23. case 'goTo':
  24. // If the passed link refers to the current page, don't follow through
  25. // the link.
  26. if (this.activePath && this.activePath === $(settings.activeLink).attr('href')) {
  27. return false;
  28. }
  29. return true;
  30. case 'setActive':
  31. var breadcrumb = [];
  32. var activeMenu;
  33. $(settings.activeLink).each(function() {
  34. // Traverse backwards through menu parents and build breadcrumb array.
  35. $(this).parents('ul.menu').each(function() {
  36. if ($(this).parents('ul.menu').size() > 0) {
  37. $(this).siblings('a').each(function() {
  38. breadcrumb.unshift($(this));
  39. });
  40. }
  41. // If this is a root menu with no root link to accompany it,
  42. // generate one such that the breadcrumb may reference it.
  43. else if ($(this).children('li').size() > 1) {
  44. var root;
  45. if ($(this).siblings('a.drilldown-root').size() > 0) {
  46. root = $(this).siblings('a.drilldown-root');
  47. }
  48. else {
  49. root = $('<a href="#" class="drilldown-root" style="display:none">'+rootTitle+'</a>');
  50. $(this).before(root);
  51. }
  52. breadcrumb.unshift(root);
  53. }
  54. });
  55. // If we have a child menu (actually a sibling in the DOM), use it
  56. // as the active menu. Otherwise treat our direct parent as the
  57. // active menu.
  58. if ($(this).next().is('ul.menu')) {
  59. activeMenu = $(this).next();
  60. breadcrumb.push($(this));
  61. }
  62. else {
  63. activeMenu = $(this).parents('ul.menu').eq(0);
  64. }
  65. if (activeMenu) {
  66. $('.drilldown-active-trail', menu).removeClass('drilldown-active-trail');
  67. $('ul.menu', menu).removeClass('drilldown-active-menu').removeClass('clearfix');
  68. $(activeMenu)
  69. .addClass('drilldown-active-menu').addClass('clearfix')
  70. .parents('li').addClass('drilldown-active-trail').show();
  71. }
  72. });
  73. // Render the breadcrumb to the target DOM object
  74. if (breadcrumb.length > 0) {
  75. var trail = $(settings.trail);
  76. trail.empty();
  77. for (var key in breadcrumb) {
  78. if (breadcrumb[key]) {
  79. // We don't use the $().clone() method here because of an
  80. // IE & jQuery 1.2 bug.
  81. var clone = $('<a></a>')
  82. .attr('href', $(breadcrumb[key]).attr('href'))
  83. .attr('class', $(breadcrumb[key]).attr('class'))
  84. .html($(breadcrumb[key]).html())
  85. .addClass('depth-'+key)
  86. .appendTo(trail);
  87. // We add a reference to the original link and a click handler
  88. // that traces back to that instance to set as the active link.
  89. $('a.depth-'+key, trail)
  90. .data('original', $(breadcrumb[key]))
  91. .click(function() {
  92. settings.activeLink = $(this).data('original');
  93. // If the clicked link does not reference the current
  94. // active menu, set it to be active.
  95. if (settings.activeLink.siblings('ul.drilldown-active-menu').size() === 0) {
  96. menu.drilldown('setActive', settings);
  97. return false;
  98. }
  99. // Otherwise, pass-through and allow the link to be clicked.
  100. return menu.drilldown('goTo', settings);
  101. });
  102. }
  103. }
  104. }
  105. // Event in case others need to update themselves when a new active
  106. // link is set.
  107. $(menu).trigger('refresh.drilldown');
  108. break;
  109. case 'init':
  110. if ($('ul.menu ul.menu', menu).size() > 0) {
  111. $(menu).addClass('drilldown');
  112. $(settings.trail).addClass('drilldown-trail');
  113. // Set initial active menu state.
  114. var activeLink;
  115. $('ul.menu a', menu).removeClass('active');
  116. if (settings.activePath && $('ul.menu a[href="'+settings.activePath+'"]', menu).size() > 0) {
  117. this.activePath = settings.activePath;
  118. activeLink = $('ul.menu a[href="'+settings.activePath+'"]', menu).addClass('active');
  119. }
  120. if (!activeLink) {
  121. activeLink = $('ul.menu a.active', menu).size() ? $('ul.menu a.active', menu) : $('ul.menu > li > a', menu);
  122. }
  123. if (activeLink) {
  124. menu.drilldown('setActive', {
  125. activeLink: $(activeLink[0]),
  126. trail: settings.trail,
  127. rootTitle: rootTitle
  128. });
  129. }
  130. // Attach click handlers to menu items
  131. $('ul.menu li:has(ul.menu)', this).click(function() {
  132. if ($(this).parent().is('.drilldown-active-menu')) {
  133. if (menu.data('disableMenu')) {
  134. return true;
  135. }
  136. else {
  137. var url = $(this).children('a').attr('href');
  138. var activeLink = $('ul.menu a[href="'+url+'"]', menu);
  139. menu.drilldown('setActive', {
  140. activeLink: activeLink,
  141. trail: settings.trail,
  142. rootTitle: rootTitle
  143. });
  144. return false;
  145. }
  146. }
  147. });
  148. $('ul.menu li:has(ul.menu) a', menu).click(function() {
  149. menu.data('disableMenu', true);
  150. });
  151. }
  152. break;
  153. }
  154. return this;
  155. };
  156. })(jQuery);