Translated using Weblate (German)
[phpmyadmin.git] / js / src / menu_resizer.js
blob116f506c2c9b67673df2306f81c0e33587ddd98c
1 /**
2  * Handles the resizing of a menu according to the available screen width
3  *
4  * Uses themes/original/css/resizable-menu.css.php
5  *
6  * To initialize:
7  * $('#myMenu').menuResizer(function () {
8  *     // This function will be called to find out how much
9  *     // available horizontal space there is for the menu
10  *     return $('body').width() - 5; // Some extra margin for good measure
11  * });
12  *
13  * To trigger a resize operation:
14  * $('#myMenu').menuResizer('resize'); // Bind this to $(window).resize()
15  *
16  * To restore the menu to a state like before it was initialized:
17  * $('#myMenu').menuResizer('destroy');
18  *
19  * @package PhpMyAdmin
20  */
21 (function ($) {
22     function MenuResizer ($container, widthCalculator) {
23         var self = this;
24         self.$container = $container;
25         self.widthCalculator = widthCalculator;
26         var windowWidth = $(window).width();
28         if (windowWidth < 768) {
29             $('#pma_navigation_resizer').css({ 'width': '0px' });
30         }
32         // create submenu container
33         var link = $('<a></a>', {
34             'href': '#',
35             'class': 'nav-link dropdown-toggle',
36             'id': 'navbarDropdown',
37             'role': 'button',
38             'data-bs-toggle': 'dropdown',
39             'aria-haspopup': 'true',
40             'aria-expanded': 'false'
41         }).text(Messages.strMore);
43         var img = $container.find('li img');
44         if (img.length) {
45             $(Functions.getImage('b_more').toString()).prependTo(link);
46         }
47         var $submenu = $('<li></li>', { 'class': 'nav-item dropdown d-none' })
48             .append(link)
49             .append($('<ul></ul>', {
50                 'class': 'dropdown-menu dropdown-menu-end',
51                 'aria-labelledby': 'navbarDropdown'
52             }));
53         $container.append($submenu);
54         setTimeout(function () {
55             self.resize();
56         }, 4);
57     }
58     MenuResizer.prototype.resize = function () {
59         var wmax = this.widthCalculator.call(this.$container);
60         var windowWidth = $(window).width();
61         var $submenu = this.$container.find('.nav-item.dropdown').last();
62         var submenuW = $submenu.outerWidth(true);
63         var $submenuUl = $submenu.find('.dropdown-menu');
64         var $li = this.$container.find('> li');
65         var $li2 = $submenuUl.find('.dropdown-item');
66         var moreShown = $li2.length > 0;
67         // Calculate the total width used by all the shown tabs
68         var totalLen = moreShown ? submenuW : 0;
69         var l = $li.length - 1;
70         var i;
71         for (i = 0; i < l; i++) {
72             totalLen += $($li[i]).outerWidth(true);
73         }
75         // eslint-disable-next-line compat/compat
76         var hasVScroll = document.body.scrollHeight > document.body.clientHeight;
77         if (hasVScroll) {
78             windowWidth += 15;
79         }
80         if (windowWidth < 768) {
81             wmax = 2000;
82         }
84         // Now hide menu elements that don't fit into the menubar
85         var hidden = false; // Whether we have hidden any tabs
86         while (totalLen >= wmax && --l >= 0) { // Process the tabs backwards
87             hidden = true;
88             var el = $($li[l]);
89             el.removeClass('nav-item').addClass('dropdown-item');
90             var elWidth = el.outerWidth(true);
91             el.data('width', elWidth);
92             if (! moreShown) {
93                 totalLen -= elWidth;
94                 el.prependTo($submenuUl);
95                 totalLen += submenuW;
96                 moreShown = true;
97             } else {
98                 totalLen -= elWidth;
99                 el.prependTo($submenuUl);
100             }
101         }
102         // If we didn't hide any tabs, then there might be some space to show some
103         if (! hidden) {
104             // Show menu elements that do fit into the menubar
105             for (i = 0, l = $li2.length; i < l; i++) {
106                 totalLen += $($li2[i]).data('width');
107                 // item fits or (it is the last item
108                 // and it would fit if More got removed)
109                 if (totalLen < wmax ||
110                     (i === $li2.length - 1 && totalLen - submenuW < wmax)
111                 ) {
112                     $($li2[i]).removeClass('dropdown-item').addClass('nav-item');
113                     $($li2[i]).insertBefore($submenu);
114                 } else {
115                     break;
116                 }
117             }
118         }
119         // Show/hide the "More" tab as needed
120         if (windowWidth < 768) {
121             $('.navbar-collapse').css({ 'width': windowWidth - 80 - $('#pma_navigation').width() });
122             $submenu.addClass('d-none');
123             $('.navbar-collapse').css({ 'overflow': 'hidden' });
124         } else {
125             $('.navbar-collapse').css({ 'width': 'auto' });
126             $('.navbar-collapse').css({ 'overflow': 'visible' });
127             if ($submenuUl.find('li').length > 0) {
128                 $submenu.removeClass('d-none');
129             } else {
130                 $submenu.addClass('d-none');
131             }
132         }
133     };
134     MenuResizer.prototype.destroy = function () {
135         var $submenu = this.$container.find('.nav-item.dropdown').removeData();
136         $submenu.find('li').appendTo(this.$container);
137         $submenu.remove();
138     };
140     /** Public API */
141     var methods = {
142         init: function (widthCalculator) {
143             return this.each(function () {
144                 var $this = $(this);
145                 if (! $this.data('menuResizer')) {
146                     $this.data(
147                         'menuResizer',
148                         new MenuResizer($this, widthCalculator)
149                     );
150                 }
151             });
152         },
153         resize: function () {
154             return this.each(function () {
155                 var self = $(this).data('menuResizer');
156                 if (self) {
157                     self.resize();
158                 }
159             });
160         },
161         destroy: function () {
162             return this.each(function () {
163                 var self = $(this).data('menuResizer');
164                 if (self) {
165                     self.destroy();
166                 }
167             });
168         }
169     };
171     /**
172      * Extend jQuery
173      *
174      * @param {string} method
175      *
176      * @return {any}
177      */
178     $.fn.menuResizer = function (method) {
179         if (methods[method]) {
180             return methods[method].call(this);
181         } else if (typeof method === 'function') {
182             return methods.init.apply(this, [method]);
183         } else {
184             $.error('Method ' +  method + ' does not exist on jQuery.menuResizer');
185         }
186     };
187 }(jQuery));