(function ($) { var settings = { scrollTimeout: 0, // milliseconds rowHeight: 30, hidePopoversContainer: null }; var createMarkup = function ($this) { if (!$this) { throw '$this does not exist'; } // if markup is already created if ($this.data('popupMenu')) { return; } var dropdownContainer = $this.find('.dropdown-menu').on('click', dropDownInsideClick); var chevron = $this.find('.dropdown-toggle').on('click', function () { if (!$this.hasClass('open') && !$this.data('popovers-inited')) { $this.data('popovers-inited', true); $this.find('.popover-warning').each(function () { var $item = $(this); initPopover($item); }); } setDropDownPosition($this, $(this), dropdownContainer); }); $this.data('popupMenu', true); return $this; }; var setupWindow = function ($this) { if (!$this) { throw '$this does not exist'; } if (!settings.hidePopoversContainer || settings.hidePopoversContainer.length <= 0) { return; } var popoverContainer = $('.' + settings.hidePopoversContainer); var menuClass = popoverContainer.data('menuclass'); if (popoverContainer.length > 0) { var data = $(window).data('pm.scroll.src'); if (!data) data = {}; // add container if it is not specified yet if (!data[settings.hidePopoversContainer]) data[settings.hidePopoversContainer] = {}; // add menu class to scrolling container to identify which popovers to close data[settings.hidePopoversContainer][menuClass] = true; // store updated list of containers in data $(window).data('pm.scroll.src', data); } return $this; }; var setupContainer = function ($this) { if (!$this) { throw '$this does not exist'; } if (!settings.hidePopoversContainer || settings.hidePopoversContainer.length <= 0) { return; } var popoverContainer = $('.' + settings.hidePopoversContainer); var scrollContainerClass = popoverContainer.data('scrollcontainerclass'); var menuClass = popoverContainer.data('menuclass'); if (scrollContainerClass) { var scrollContainer = $('.' + scrollContainerClass); // store containers whose popups should be hidden on scrollContainer.scroll scrollContainer.each(function (i, obj) { var data = $(obj).data('pm.scroll.src'); if (!data) data = {}; // add container if it is not specified yet if (!data[settings.hidePopoversContainer]) data[settings.hidePopoversContainer] = {}; // add menu class to scrolling container to identify which popovers to close data[settings.hidePopoversContainer][menuClass] = true; // store updated list of containers in data $(obj).data('pm.scroll.src', data); }); setupScrollEvent(scrollContainer); } // gather menuCssClasses var menuClasses = $(document).data('pm.click.menu') || {}; menuClasses[menuClass] = true; $(document).data('pm.click.menu', menuClasses); // gather popupmenu containers var containers = $(document).data('pm.click.container') || {}; containers[settings.hidePopoversContainer] = true; $(document).data('pm.click.container', containers); return $this; }; var setupWindowEvents = function () { setupScrollEvent(window); setupClickEvent(document); }; function setupScrollEvent(obj) { $(obj).off('scroll.pm').on('scroll.pm', function () { if (settings.scrollTimeout > 0) { if ($(obj).data('scroll.pm.timeout')) { clearTimeout($(obj).data('scroll.pm.timeout')); } $(obj).data('scroll.pm.timeout', setTimeout(onScroll, settings.scrollTimeout, obj)); } else onScroll(obj); }); }; function setupClickEvent(obj) { $(obj).off('click.pm').on('click.pm', function () { onClick(obj); }); $(document).off('hidden.bs.dropdown.pm').on('hidden.bs.dropdown.pm', function (e, obj) { $(e.target).find('a.popover-warning:data(bs.popover)').popover('destroy'); }); }; var initPopover = function ($item) { if ($item.data('checklock-table') && $item.data('checklock-id') && $item.data('checklock-url')) { $item.on('click', function () { var tbl = $item.data('checklock-table'); var id = $item.data('checklock-id'); var url = $item.data('checklock-url'); var openInNewTab = ($item.data('in-newtab') !== undefined); var backName = $item.data('checklock-backname'); var query = $item.data('checklock-query'); if (!URI) throw 'Cannot find URI component declared in URIjs.js'; if (CheckLock($item, tbl, id)) { var currentUrl = document.location.pathname + document.location.search; var navigateToUrl = URI(url); if (url && url.length > 0) { var urlId = navigateToUrl.query(true).id; if (!urlId || urlId.length <= 0) navigateToUrl = navigateToUrl.setQuery('id', id); } else throw 'Cannot set target navigation URL'; navigateToUrl = navigateToUrl.setQuery('backUrl', currentUrl); if (backName && (backName.length > 0)) navigateToUrl = navigateToUrl.setQuery("backName", encodeURIComponent(backName)); if (query && query.length > 0) navigateToUrl = navigateToUrl.toString() + '&' + query; if (openInNewTab) { window.open(navigateToUrl, '_blank'); } else { document.location.href = navigateToUrl; } } }); } }; var onChevronClick = function ($this) { $this.find('.modal').modal('show'); }; var setDropDownPosition = function (popupMenu, button, dropdown) { calcProps(button, dropdown, settings.rowHeight); var popoverContainer = popupMenu.closest('.' + settings.hidePopoversContainer); hideRedundantPopovers(popoverContainer, null); } function calcProps(button, dropdown, liHeight) { var rows = dropdown.find("li").length; if (rows > 3) rows = rows - 1; var menumax = rows * liHeight; if (rows >= 2) menumax = menumax + 25; dropdown.css('overflow', 'hidden'); var curmaxheight = 300; var totalMaxheight = 400; var menumax_keep = menumax; var y = $(window.top).height(); var bOffset = button.offset().top - window.pageYOffset; var y1 = bOffset + button.outerHeight(); var dropDownLeft = button.offset().left - window.pageXOffset; var dropDownTop = bOffset + button.outerHeight(); var sc1 = y - y1; if (curmaxheight + dropDownTop > window.innerHeight) sc1 = bOffset; if (menumax > sc1) menumax = (sc1 - 50); if (menumax > totalMaxheight) menumax = totalMaxheight; var direction = 'bottom'; if (menumax + dropDownTop > window.innerHeight) { if (menumax_keep < menumax) dropDownTop = (bOffset - menumax_keep); else dropDownTop = (bOffset - menumax); direction = 'top' } if (menumax < menumax_keep) { var delta = menumax_keep - menumax if (delta > 25) dropdown.css('overflow', 'auto'); if (curmaxheight > menumax) { menumax = curmaxheight; } } if (direction === 'top') { dropdown.css('max-height', menumax + "px"); if (menumax < curmaxheight) menumaxdph = $(dropdown).outerHeight(); dropDownTop = (bOffset - menumax); } else { dropdown.css('max-height', menumax + "px"); } dropdown.css('position', 'fixed'); dropdown.css('top', dropDownTop + "px"); dropdown.css('left', dropDownLeft + "px"); dropdown.css('z-index', '499'); setDropDownHorizontalPosition(button, dropdown) } function setDropDownHorizontalPosition(button, dropdown) { var rows = dropdown.find("li").length; if (rows > 0) { var l = button.offset().left + $(button).parent().width(); var w = $(dropdown).innerWidth(); var docW = window.innerWidth; var isEntirelyVisible = (l + w <= docW); if (!isEntirelyVisible) { var totheright = l - w; dropdown.css('left', totheright + 'px'); } else { } } } function dropDownInsideClick(event) { if (!event) event = window.event; var container = null, button = null; if ($(event.target).hasClass('dropdown-menu')) container = $(event.target); else { button = $(event.target); container = button.closest('.dropdown-menu'); } hideRedundantPopovers(container, button); if (event.stopPropagation) event.stopPropagation(); else window.event.cancelBubble = true; } function hideRedundantPopovers(container, currentBtn) { if (!container) { return; } var btn = null; if (currentBtn) { if (currentBtn.is('[data-toggle="popover"]')) btn = currentBtn; else btn = currentBtn.closest('[data-toggle="popover"]'); } container.find('a.popover-warning:data(bs.popover)').not(btn).popover('destroy'); } function onScroll(obj) { //var startDate = new Date().getTime(); // get a list of containers to handle for the specified scrolling container var data = $(obj).data('pm.scroll.src'); //console.log('window scroll.pm. data = ' + data); if (data) { $.each(data, function (key, item) { //console.log('window scroll.pm. data.each = ' + key + '; item.length' + item.length); var container = $('.' + key); if (item) { $.each(item, function (menuClassKey, menuClassElem) { //console.log('window scroll.pm. item.each = ' + menuClassKey); container.find('.' + menuClassKey).removeClass('open'); }); } hideRedundantPopovers(container, null); }); } //var endDate = new Date().getTime(); //console.log('hiding popup menus and popovers took: ' + (endDate - startDate) + ' ms'); } function onClick(obj) { //var startDate = new Date().getTime(); // get a list of containers to handle for the specified dom element var menus = $(obj).data('pm.click.menu'); var containers = $(obj).data('pm.click.container'); if (menus) { $.each(menus, function (key, item) { var menuItem = $('.' + key).removeClass('open'); }); } if (containers) { $.each(containers, function (key, item) { hideRedundantPopovers($('.' + key), null); }); } //var endDate = new Date().getTime(); //console.log('PM. document click took: ' + (endDate - startDate) + ' ms'); } var methods = { init: function (options) { settings = $.extend(true, settings, options); this.each(function () { var $this = $(this); createMarkup($this); setupContainer($this); setupWindow($this); }); setupWindowEvents(); } }; $.fn.popupMenu = function (options) { if (typeof options === 'string' && typeof methods[options] === 'function') { return methods[options].apply(this, Array.prototype.slice.call(arguments, 1)); } else if (typeof options === 'object' || !options) { return methods.init.apply(this, arguments); } }; }(jQuery));