EnVisageOnline/Main/Source/EnVisage/Scripts/Plugins/PopupMenu.js

336 lines
13 KiB
JavaScript

(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));