menu-resizer.js 6.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183
  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').remove();
  55. $container.append($submenu).append("<div class='clearfloat'></div>");
  56. setTimeout(function () {
  57. self.resize();
  58. }, 4);
  59. }
  60. MenuResizer.prototype.resize = function () {
  61. var wmax = this.widthCalculator.call(this.$container);
  62. var $submenu = this.$container.find('.submenu:last');
  63. var submenu_w = $submenu.outerWidth(true);
  64. var $submenu_ul = $submenu.find('ul');
  65. var $li = this.$container.find('> li');
  66. var $li2 = $submenu_ul.find('li');
  67. var more_shown = $li2.length > 0;
  68. // Calculate the total width used by all the shown tabs
  69. var total_len = more_shown ? submenu_w : 0;
  70. var l = $li.length - 1;
  71. var i;
  72. for (i = 0; i < l; i++) {
  73. total_len += $($li[i]).outerWidth(true);
  74. }
  75. // Now hide menu elements that don't fit into the menubar
  76. var hidden = false; // Whether we have hidden any tabs
  77. while (total_len >= wmax && --l >= 0) { // Process the tabs backwards
  78. hidden = true;
  79. var el = $($li[l]);
  80. var el_width = el.outerWidth(true);
  81. el.data('width', el_width);
  82. if (! more_shown) {
  83. total_len -= el_width;
  84. el.prependTo($submenu_ul);
  85. total_len += submenu_w;
  86. more_shown = true;
  87. } else {
  88. total_len -= el_width;
  89. el.prependTo($submenu_ul);
  90. }
  91. }
  92. // If we didn't hide any tabs, then there might be some space to show some
  93. if (! hidden) {
  94. // Show menu elements that do fit into the menubar
  95. for (i = 0, l = $li2.length; i < l; i++) {
  96. total_len += $($li2[i]).data('width');
  97. // item fits or (it is the last item
  98. // and it would fit if More got removed)
  99. if (total_len < wmax ||
  100. (i == $li2.length - 1 && total_len - submenu_w < wmax)
  101. ) {
  102. $($li2[i]).insertBefore($submenu);
  103. } else {
  104. break;
  105. }
  106. }
  107. }
  108. // Show/hide the "More" tab as needed
  109. if ($submenu_ul.find('li').length > 0) {
  110. $submenu.addClass('shown');
  111. } else {
  112. $submenu.removeClass('shown');
  113. }
  114. if (this.$container.find('> li').length == 1) {
  115. // If there is only the "More" tab left, then we need
  116. // to align the submenu to the left edge of the tab
  117. $submenu_ul.removeClass().addClass('only');
  118. } else {
  119. // Otherwise we align the submenu to the right edge of the tab
  120. $submenu_ul.removeClass().addClass('notonly');
  121. }
  122. if ($submenu.find('.tabactive').length) {
  123. $submenu
  124. .addClass('active')
  125. .find('> a')
  126. .removeClass('tab')
  127. .addClass('tabactive');
  128. } else {
  129. $submenu
  130. .removeClass('active')
  131. .find('> a')
  132. .addClass('tab')
  133. .removeClass('tabactive');
  134. }
  135. };
  136. MenuResizer.prototype.destroy = function () {
  137. var $submenu = this.$container.find('li.submenu').removeData();
  138. $submenu.find('li').appendTo(this.$container);
  139. $submenu.remove();
  140. };
  141. /** Public API */
  142. var methods = {
  143. init: function(widthCalculator) {
  144. return this.each(function () {
  145. var $this = $(this);
  146. if (! $this.data('menuResizer')) {
  147. $this.data(
  148. 'menuResizer',
  149. new MenuResizer($this, widthCalculator)
  150. );
  151. }
  152. });
  153. },
  154. resize: function () {
  155. return this.each(function () {
  156. var self = $(this).data('menuResizer');
  157. if (self) {
  158. self.resize();
  159. }
  160. });
  161. },
  162. destroy: function () {
  163. return this.each(function () {
  164. var self = $(this).data('menuResizer');
  165. if (self) {
  166. self.destroy();
  167. }
  168. });
  169. }
  170. };
  171. /** Extend jQuery */
  172. $.fn.menuResizer = function(method) {
  173. if (methods[method]) {
  174. return methods[method].call(this);
  175. } else if (typeof method === 'function') {
  176. return methods.init.apply(this, [method]);
  177. } else {
  178. $.error('Method ' + method + ' does not exist on jQuery.menuResizer');
  179. }
  180. };
  181. })(jQuery);