| Server IP : 127.0.1.1 / Your IP : 216.73.216.83 Web Server : Apache/2.4.58 (Ubuntu) System : Linux nepub 6.8.0-88-generic #89-Ubuntu SMP PREEMPT_DYNAMIC Sat Oct 11 01:02:46 UTC 2025 x86_64 User : root ( 0) PHP Version : 8.2.30 Disable Function : NONE MySQL : OFF | cURL : ON | WGET : ON | Perl : ON | Python : OFF | Sudo : ON | Pkexec : OFF Directory : /var/www/html/public_html/lib/pkp/js/controllers/ |
Upload File : |
/**
* @file js/controllers/MenuHandler.js
*
* Copyright (c) 2014-2021 Simon Fraser University
* Copyright (c) 2000-2021 John Willinsky
* Distributed under the GNU GPL v3. For full terms see the file docs/COPYING.
*
* @class MenuHandler
* @ingroup js_controllers
*
* @brief A basic handler for a hierarchical list of navigation items.
*
* Attach this handler to a <ul> with nested <li> and <ul> elements.
* <li> elements with submenu should have aria properties:
* <li aria-haspopup="true" aria-expanded="false">
*
* <li> elements wiith a submenu that opens below the parent item should add a
* submenuOpensBelow class to support scrolling in long lists when necessary.
* <li class="submenuOpensBelow"
* aria-haspopup="true" aria-expanded="false"></li>
*/
(function($) {
/**
* @constructor
*
* @extends $.pkp.classes.Handler
*
* @param {jQueryObject} $menu The outer <ul> element
* @param {Object} options Handler options.
*/
$.pkp.controllers.MenuHandler = function($menu, options) {
this.parent($menu, options);
// Fix dropdown menus that may go off-screen and recalculate whenever
// the browser window is resized
// 1ms delay allows dom insertion to complete
var self = this;
setTimeout(function() {
self.callbackWrapper( /** @type {Function} */ (
self.setDropdownAlignment()));
}, 1);
$(window).resize(this.callbackWrapper(this.onResize));
// Show/hide dropdown menus using WCAG-compliant aria attributes
this.getHtmlElement().on('focus mouseenter', '[aria-haspopup="true"]',
function(e) {
$(e.currentTarget).attr('aria-expanded', 'true');
});
this.getHtmlElement().on('blur mouseleave', '[aria-haspopup="true"]',
function(e) {
$(e.currentTarget).attr('aria-expanded', 'false');
});
};
$.pkp.classes.Helper.inherits(
$.pkp.controllers.MenuHandler, $.pkp.classes.Handler);
//
// Public methods
//
/**
* Check if submenus are straying off-screen and adjust as needed
*/
$.pkp.controllers.MenuHandler.prototype.setDropdownAlignment = function() {
var $this = $(this),
width = Math.max(
document.documentElement.clientWidth, window.innerWidth || 0),
height = Math.max(
document.documentElement.clientHeight, window.innerHeight || 0);
this.getHtmlElement().find('[aria-haspopup="true"]').each(function() {
var $parent = $(this),
$submenus = $parent.children('ul'),
right, pos_top, min_top, pos_btm, offset_top, new_top;
// Width
right = $parent.offset().left + $submenus.outerWidth();
if (right > width) {
$parent.addClass('align_right');
} else {
$parent.removeClass('align_right');
}
// Height
$submenus.attr('style', ''); // reset
pos_top = $parent.offset().top;
min_top = 0;
if ($parent.hasClass('submenuOpensBelow')) {
min_top = pos_top + $parent.outerHeight();
}
pos_btm = pos_top + $submenus.outerHeight();
if (pos_btm > height) {
offset_top = pos_btm - height;
new_top = pos_top - offset_top;
if (new_top < min_top) {
if (min_top > 0) {
offset_top = min_top;
} else {
offset_top = -Math.abs(offset_top) - new_top;
}
$submenus.css('overflow-y', 'scroll');
$submenus.css('bottom',
-Math.abs(height - pos_top - $parent.outerHeight()) + 'px');
}
$submenus.css('top', offset_top + 'px');
}
});
};
/**
* Throttle the dropdown alignment check during resize events. During
* browser resizing this will fire off every single frame, causing lag
* during the resize. So this just throttles the actual alignment check
* function by only firing when resizing has stopped.
*/
$.pkp.controllers.MenuHandler.prototype.onResize = function() {
clearTimeout(this.resize_check);
this.resize_check = setTimeout(
this.callbackWrapper(this.setDropdownAlignment), 1000);
};
}(jQuery));