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