jquery.menuResizer-1.0.js 6.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181
  1. /* vim: set expandtab sw=4 ts=4 sts=4: */
  2. /**
  3. * Handles the resizing of a menu according to the available screen width
  4. *
  5. * Uses themes/original/css/resizable-menu.css.php
  6. *
  7. * To initialise:
  8. * $('#myMenu').menuResizer(function () {
  9. * // This function will be called to find out how much
  10. * // available horizontal space there is for the menu
  11. * return $('body').width() - 5; // Some extra margin for good measure
  12. * });
  13. *
  14. * To trigger a resize operation:
  15. * $('#myMenu').menuResizer('resize'); // Bind this to $(window).resize()
  16. *
  17. * To restore the menu to a state like before it was initialized:
  18. * $('#myMenu').menuResizer('destroy');
  19. *
  20. * @package PhpMyAdmin
  21. */
  22. (function ($) {
  23. function MenuResizer($container, widthCalculator) {
  24. var self = this;
  25. self.$container = $container;
  26. self.widthCalculator = widthCalculator;
  27. // create submenu container
  28. var link = $('<a />', {href: '#', 'class': 'tab nowrap'})
  29. .text(PMA_messages['strMore'])
  30. .bind('click', false); // same as event.preventDefault()
  31. var img = $container.find('li img');
  32. if (img.length) {
  33. $(PMA_getImage('b_more.png').toString()).prependTo(link);
  34. }
  35. var $submenu = $('<li />', {'class': 'submenu'})
  36. .append(link)
  37. .append($('<ul />'))
  38. .mouseenter(function() {
  39. if ($(this).find('ul .tabactive').length == 0) {
  40. $(this)
  41. .addClass('submenuhover')
  42. .find('> a')
  43. .addClass('tabactive');
  44. }
  45. })
  46. .mouseleave(function() {
  47. if ($(this).find('ul .tabactive').length == 0) {
  48. $(this)
  49. .removeClass('submenuhover')
  50. .find('> a')
  51. .removeClass('tabactive');
  52. }
  53. });
  54. $container.children('.clearfloat').before($submenu);
  55. setTimeout(function () {
  56. self.resize();
  57. }, 4);
  58. }
  59. MenuResizer.prototype.resize = function () {
  60. var wmax = this.widthCalculator.call(this.$container);
  61. var $submenu = this.$container.find('.submenu:last');
  62. var submenu_w = $submenu.outerWidth(true);
  63. var $submenu_ul = $submenu.find('ul');
  64. var $li = this.$container.find('> li');
  65. var $li2 = $submenu_ul.find('li');
  66. var more_shown = $li2.length > 0;
  67. // Calculate the total width used by all the shown tabs
  68. var total_len = more_shown ? submenu_w : 0;
  69. var l = $li.length - 1;
  70. for (var i = 0; i < l; i++) {
  71. total_len += $($li[i]).outerWidth(true);
  72. }
  73. // Now hide menu elements that don't fit into the menubar
  74. var hidden = false; // Whether we have hidden any tabs
  75. while (total_len >= wmax && --l >= 0) { // Process the tabs backwards
  76. hidden = true;
  77. var el = $($li[l]);
  78. var el_width = el.outerWidth(true);
  79. el.data('width', el_width);
  80. if (! more_shown) {
  81. total_len -= el_width;
  82. el.prependTo($submenu_ul);
  83. total_len += submenu_w;
  84. more_shown = true;
  85. } else {
  86. total_len -= el_width;
  87. el.prependTo($submenu_ul);
  88. }
  89. }
  90. // If we didn't hide any tabs, then there might be some space to show some
  91. if (! hidden) {
  92. // Show menu elements that do fit into the menubar
  93. for (var i = 0, l = $li2.length; i < l; i++) {
  94. total_len += $($li2[i]).data('width');
  95. // item fits or (it is the last item
  96. // and it would fit if More got removed)
  97. if (total_len < wmax
  98. || (i == $li2.length - 1 && total_len - submenu_w < wmax)
  99. ) {
  100. $($li2[i]).insertBefore($submenu);
  101. } else {
  102. break;
  103. }
  104. }
  105. }
  106. // Show/hide the "More" tab as needed
  107. if ($submenu_ul.find('li').length > 0) {
  108. $submenu.addClass('shown');
  109. } else {
  110. $submenu.removeClass('shown');
  111. }
  112. if (this.$container.find('> li').length == 1) {
  113. // If there is only the "More" tab left, then we need
  114. // to align the submenu to the left edge of the tab
  115. $submenu_ul.removeClass().addClass('only');
  116. } else {
  117. // Otherwise we align the submenu to the right edge of the tab
  118. $submenu_ul.removeClass().addClass('notonly');
  119. }
  120. if ($submenu.find('.tabactive').length) {
  121. $submenu
  122. .addClass('active')
  123. .find('> a')
  124. .removeClass('tab')
  125. .addClass('tabactive');
  126. } else {
  127. $submenu
  128. .removeClass('active')
  129. .find('> a')
  130. .addClass('tab')
  131. .removeClass('tabactive');
  132. }
  133. };
  134. MenuResizer.prototype.destroy = function () {
  135. var $submenu = this.$container.find('li.submenu').removeData();
  136. $submenu.find('li').appendTo(this.$container);
  137. $submenu.remove();
  138. };
  139. /** Public API */
  140. var methods = {
  141. init: function(widthCalculator) {
  142. return this.each(function () {
  143. var $this = $(this);
  144. if (! $this.data('menuResizer')) {
  145. $this.data(
  146. 'menuResizer',
  147. new MenuResizer($this, widthCalculator)
  148. );
  149. }
  150. });
  151. },
  152. resize: function () {
  153. return this.each(function () {
  154. var self = $(this).data('menuResizer');
  155. if (self) {
  156. self.resize();
  157. }
  158. });
  159. },
  160. destroy: function () {
  161. return this.each(function () {
  162. var self = $(this).data('menuResizer');
  163. if (self) {
  164. self.destroy();
  165. }
  166. });
  167. }
  168. };
  169. /** Extend jQuery */
  170. $.fn.menuResizer = function(method) {
  171. if (methods[method]) {
  172. return methods[method].call(this);
  173. } else if (typeof method === 'function') {
  174. return methods.init.apply(this, [method]);
  175. } else {
  176. $.error('Method ' + method + ' does not exist on jQuery.menuResizer');
  177. }
  178. };
  179. })(jQuery);