PageSourceSearch

https://pasvik-inari.net/js/menu-resizer.js?v=4.9.4

js pasvik-inari.net collected 2026-09-25 08:37:21 UTC 8,318 bytes, 222 lines download raw bytes

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.