menu-resizer.js 8.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222
  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. var windowWidth = $(window).width();
  28. if (windowWidth < 768) {
  29. $('#pma_navigation_resizer').css({ 'width': '0px' });
  30. }
  31. // Sets the image for the left and right scroll indicator
  32. $('.scrollindicator--left').html($(PMA_getImage('b_left').toString()));
  33. $('.scrollindicator--right').html($(PMA_getImage('b_right').toString()));
  34. // Set the width of the navigation bar without scroll indicator
  35. $('.navigationbar').css({ 'width': widthCalculator.call($container) - 60 });
  36. // Scroll the navigation bar on click
  37. $('.scrollindicator--right').on('click', function () {
  38. $('.navigationbar').scrollLeft($('.navigationbar').scrollLeft() + 70);
  39. });
  40. $('.scrollindicator--left').on('click', function () {
  41. $('.navigationbar').scrollLeft($('.navigationbar').scrollLeft() - 70);
  42. });
  43. // create submenu container
  44. var link = $('<a />', { href: '#', 'class': 'tab nowrap' })
  45. .text(PMA_messages.strMore)
  46. .on('click', false); // same as event.preventDefault()
  47. var img = $container.find('li img');
  48. if (img.length) {
  49. $(PMA_getImage('b_more').toString()).prependTo(link);
  50. }
  51. var $submenu = $('<li />', { 'class': 'submenu' })
  52. .append(link)
  53. .append($('<ul />'))
  54. .on('mouseenter', function () {
  55. if ($(this).find('ul .tabactive').length === 0) {
  56. $(this)
  57. .addClass('submenuhover')
  58. .find('> a')
  59. .addClass('tabactive');
  60. }
  61. })
  62. .on('mouseleave', function () {
  63. if ($(this).find('ul .tabactive').length === 0) {
  64. $(this)
  65. .removeClass('submenuhover')
  66. .find('> a')
  67. .removeClass('tabactive');
  68. }
  69. });
  70. $container.children('.clearfloat').remove();
  71. $container.append($submenu).append('<div class=\'clearfloat\'></div>');
  72. setTimeout(function () {
  73. self.resize();
  74. }, 4);
  75. }
  76. MenuResizer.prototype.resize = function () {
  77. var wmax = this.widthCalculator.call(this.$container);
  78. var windowWidth = $(window).width();
  79. var $submenu = this.$container.find('.submenu:last');
  80. var submenu_w = $submenu.outerWidth(true);
  81. var $submenu_ul = $submenu.find('ul');
  82. var $li = this.$container.find('> li');
  83. var $li2 = $submenu_ul.find('li');
  84. var more_shown = $li2.length > 0;
  85. // Calculate the total width used by all the shown tabs
  86. var total_len = more_shown ? submenu_w : 0;
  87. var l = $li.length - 1;
  88. var i;
  89. for (i = 0; i < l; i++) {
  90. total_len += $($li[i]).outerWidth(true);
  91. }
  92. var hasVScroll = document.body.scrollHeight > document.body.clientHeight;
  93. if (hasVScroll) {
  94. windowWidth += 15;
  95. }
  96. var navigationwidth = wmax;
  97. if (windowWidth < 768) {
  98. wmax = 2000;
  99. }
  100. // Now hide menu elements that don't fit into the menubar
  101. var hidden = false; // Whether we have hidden any tabs
  102. while (total_len >= wmax && --l >= 0) { // Process the tabs backwards
  103. hidden = true;
  104. var el = $($li[l]);
  105. var el_width = el.outerWidth(true);
  106. el.data('width', el_width);
  107. if (! more_shown) {
  108. total_len -= el_width;
  109. el.prependTo($submenu_ul);
  110. total_len += submenu_w;
  111. more_shown = true;
  112. } else {
  113. total_len -= el_width;
  114. el.prependTo($submenu_ul);
  115. }
  116. }
  117. // If we didn't hide any tabs, then there might be some space to show some
  118. if (! hidden) {
  119. // Show menu elements that do fit into the menubar
  120. for (i = 0, l = $li2.length; i < l; i++) {
  121. total_len += $($li2[i]).data('width');
  122. // item fits or (it is the last item
  123. // and it would fit if More got removed)
  124. if (total_len < wmax ||
  125. (i === $li2.length - 1 && total_len - submenu_w < wmax)
  126. ) {
  127. $($li2[i]).insertBefore($submenu);
  128. } else {
  129. break;
  130. }
  131. }
  132. }
  133. // Show/hide the "More" tab as needed
  134. if (windowWidth < 768) {
  135. $('.navigationbar').css({ 'width': windowWidth - 80 - $('#pma_navigation').width() });
  136. $submenu.removeClass('shown');
  137. $('.navigationbar').css({ 'overflow': 'hidden' });
  138. } else {
  139. $('.navigationbar').css({ 'width': 'auto' });
  140. $('.navigationbar').css({ 'overflow': 'visible' });
  141. if ($submenu_ul.find('li').length > 0) {
  142. $submenu.addClass('shown');
  143. } else {
  144. $submenu.removeClass('shown');
  145. }
  146. }
  147. if (this.$container.find('> li').length === 1) {
  148. // If there is only the "More" tab left, then we need
  149. // to align the submenu to the left edge of the tab
  150. $submenu_ul.removeClass().addClass('only');
  151. } else {
  152. // Otherwise we align the submenu to the right edge of the tab
  153. $submenu_ul.removeClass().addClass('notonly');
  154. }
  155. if ($submenu.find('.tabactive').length) {
  156. $submenu
  157. .addClass('active')
  158. .find('> a')
  159. .removeClass('tab')
  160. .addClass('tabactive');
  161. } else {
  162. $submenu
  163. .removeClass('active')
  164. .find('> a')
  165. .addClass('tab')
  166. .removeClass('tabactive');
  167. }
  168. };
  169. MenuResizer.prototype.destroy = function () {
  170. var $submenu = this.$container.find('li.submenu').removeData();
  171. $submenu.find('li').appendTo(this.$container);
  172. $submenu.remove();
  173. };
  174. /** Public API */
  175. var methods = {
  176. init: function (widthCalculator) {
  177. return this.each(function () {
  178. var $this = $(this);
  179. if (! $this.data('menuResizer')) {
  180. $this.data(
  181. 'menuResizer',
  182. new MenuResizer($this, widthCalculator)
  183. );
  184. }
  185. });
  186. },
  187. resize: function () {
  188. return this.each(function () {
  189. var self = $(this).data('menuResizer');
  190. if (self) {
  191. self.resize();
  192. }
  193. });
  194. },
  195. destroy: function () {
  196. return this.each(function () {
  197. var self = $(this).data('menuResizer');
  198. if (self) {
  199. self.destroy();
  200. }
  201. });
  202. }
  203. };
  204. /** Extend jQuery */
  205. $.fn.menuResizer = function (method) {
  206. if (methods[method]) {
  207. return methods[method].call(this);
  208. } else if (typeof method === 'function') {
  209. return methods.init.apply(this, [method]);
  210. } else {
  211. $.error('Method ' + method + ' does not exist on jQuery.menuResizer');
  212. }
  213. };
  214. }(jQuery));