2012-02-17 09:49:26 +04:00
|
|
|
(function($) {
|
2012-02-24 03:12:29 +04:00
|
|
|
var ContextMenuClass = function(el, options) {
|
|
|
|
var element = el;
|
|
|
|
var opts = options;
|
|
|
|
var observingContextMenuClick;
|
2012-05-19 02:57:03 +04:00
|
|
|
var observingToggleAllClick;
|
2012-02-24 03:12:29 +04:00
|
|
|
var lastSelected = null;
|
|
|
|
var menu;
|
|
|
|
var menuId = 'context-menu';
|
|
|
|
var selectorName = 'hascontextmenu';
|
|
|
|
var contextMenuSelectionClass = 'context-menu-selection';
|
|
|
|
var reverseXClass = 'reverse-x';
|
|
|
|
var reverseYClass = 'reverse-y';
|
|
|
|
|
|
|
|
var methods = {
|
|
|
|
createMenu: function() {
|
|
|
|
if(!menu) {
|
|
|
|
$('#wrapper').append('<div id="' + menuId + '" style="display:none"></div>');
|
|
|
|
menu = $('#' + menuId);
|
|
|
|
}
|
|
|
|
},
|
|
|
|
click: function(e) {
|
|
|
|
var target = $(e.target);
|
2012-02-17 09:49:26 +04:00
|
|
|
|
2012-02-24 03:12:29 +04:00
|
|
|
if(target.is('a')) {
|
2012-02-17 09:49:26 +04:00
|
|
|
return;
|
|
|
|
}
|
2012-02-24 03:12:29 +04:00
|
|
|
|
|
|
|
switch(e.which) {
|
|
|
|
case 1:
|
|
|
|
if(e.type === 'click') {
|
|
|
|
methods.hideMenu();
|
|
|
|
methods.leftClick(e);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
case 3:
|
|
|
|
if(e.type === 'contextmenu') {
|
|
|
|
methods.hideMenu();
|
|
|
|
methods.rightClick(e);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
default:
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
},
|
|
|
|
leftClick: function(e) {
|
|
|
|
var target = $(e.target);
|
|
|
|
var tr = target.parents('tr');
|
|
|
|
if((tr.size() > 0) && tr.hasClass(selectorName))
|
2012-02-17 09:49:26 +04:00
|
|
|
{
|
2012-02-24 03:12:29 +04:00
|
|
|
// a row was clicked, check if the click was on checkbox
|
|
|
|
if(target.is('input'))
|
2012-02-17 09:49:26 +04:00
|
|
|
{
|
2012-02-24 03:12:29 +04:00
|
|
|
// a checkbox may be clicked
|
|
|
|
if (target.is(':checked')) {
|
|
|
|
tr.addClass(contextMenuSelectionClass);
|
|
|
|
} else {
|
|
|
|
tr.removeClass(contextMenuSelectionClass);
|
|
|
|
}
|
2012-02-17 09:49:26 +04:00
|
|
|
}
|
2012-02-24 03:12:29 +04:00
|
|
|
else
|
2012-02-17 09:49:26 +04:00
|
|
|
{
|
2012-02-24 03:12:29 +04:00
|
|
|
if (e.ctrlKey || e.metaKey)
|
2012-02-17 09:49:26 +04:00
|
|
|
{
|
2012-02-24 03:12:29 +04:00
|
|
|
methods.toggleSelection(tr);
|
|
|
|
}
|
|
|
|
else if (e.shiftKey)
|
|
|
|
{
|
|
|
|
if (lastSelected !== null)
|
2012-02-17 09:49:26 +04:00
|
|
|
{
|
2012-02-24 03:12:29 +04:00
|
|
|
var toggling = false;
|
|
|
|
var rows = $(selectorName);
|
|
|
|
for (i = 0; i < rows.length; i++)
|
2012-02-17 09:49:26 +04:00
|
|
|
{
|
2012-02-24 03:12:29 +04:00
|
|
|
if (toggling || rows[i] == tr)
|
|
|
|
{
|
|
|
|
methods.addSelection(rows[i]);
|
|
|
|
}
|
|
|
|
if (rows[i] == tr || rows[i] == lastSelected)
|
|
|
|
{
|
|
|
|
toggling = !toggling;
|
|
|
|
}
|
2012-02-17 09:49:26 +04:00
|
|
|
}
|
2012-02-24 03:12:29 +04:00
|
|
|
} else {
|
|
|
|
methods.addSelection(tr);
|
2012-02-17 09:49:26 +04:00
|
|
|
}
|
|
|
|
} else {
|
2012-02-24 03:12:29 +04:00
|
|
|
methods.unselectAll();
|
2012-02-17 09:49:26 +04:00
|
|
|
methods.addSelection(tr);
|
|
|
|
}
|
2012-02-24 03:12:29 +04:00
|
|
|
lastSelected = tr;
|
2012-02-17 09:49:26 +04:00
|
|
|
}
|
|
|
|
}
|
2012-02-24 03:12:29 +04:00
|
|
|
else
|
|
|
|
{
|
|
|
|
// click is outside the rows
|
|
|
|
if (target.is('a') === false) {
|
|
|
|
this.unselectAll();
|
|
|
|
} else {
|
|
|
|
if (target.hasClass('disabled') || target.hasClass('submenu')) {
|
|
|
|
e.preventDefault();
|
|
|
|
}
|
2012-02-17 09:49:26 +04:00
|
|
|
}
|
|
|
|
}
|
2012-02-24 03:12:29 +04:00
|
|
|
},
|
|
|
|
rightClick: function(e) {
|
|
|
|
var target = $(e.target);
|
|
|
|
var tr = target.parents('tr');
|
2012-02-17 09:49:26 +04:00
|
|
|
|
2012-02-24 03:12:29 +04:00
|
|
|
if((tr.size() === 0) || !(tr.hasClass(selectorName))) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
e.preventDefault();
|
2012-02-17 09:49:26 +04:00
|
|
|
|
2012-02-24 03:12:29 +04:00
|
|
|
if(!methods.isSelected(tr)) {
|
|
|
|
methods.unselectAll();
|
|
|
|
methods.addSelection(tr);
|
|
|
|
lastSelected = tr;
|
|
|
|
}
|
|
|
|
methods.showMenu(e);
|
|
|
|
},
|
|
|
|
unselectAll: function() {
|
|
|
|
var rows = $('.' + contextMenuSelectionClass);
|
|
|
|
rows.each(function() {
|
|
|
|
methods.removeSelection($(this));
|
|
|
|
});
|
|
|
|
},
|
|
|
|
hideMenu: function() {
|
|
|
|
menu.hide();
|
|
|
|
},
|
|
|
|
showMenu: function(e) {
|
|
|
|
var target = $(e.target);
|
|
|
|
var params = target.parents('form').serialize();
|
|
|
|
|
|
|
|
var mouseX = e.pageX;
|
|
|
|
var mouseY = e.pageY;
|
|
|
|
var renderX = mouseX;
|
|
|
|
var renderY = mouseY;
|
|
|
|
|
|
|
|
$.ajax({
|
|
|
|
url: opts.url,
|
|
|
|
data: params,
|
|
|
|
success: function(response, success) {
|
|
|
|
menu.html(response);
|
|
|
|
|
|
|
|
var maxWidth = mouseX + (2 * menu.width());
|
|
|
|
var maxHeight = mouseY + menu.height();
|
|
|
|
|
|
|
|
if(maxWidth > $(window).width()) {
|
|
|
|
renderX -= menu.width();
|
|
|
|
menu.addClass(reverseXClass);
|
|
|
|
} else {
|
|
|
|
menu.removeClass(reverseXClass);
|
|
|
|
}
|
2012-02-17 09:49:26 +04:00
|
|
|
|
2012-02-24 03:12:29 +04:00
|
|
|
if(maxHeight > $(window).height()) {
|
|
|
|
renderY =+ menu.height();
|
|
|
|
menu.addClass(reverseYClass);
|
|
|
|
} else {
|
|
|
|
menu.removeClass(reverseYClass);
|
|
|
|
}
|
2012-02-17 09:49:26 +04:00
|
|
|
|
2012-02-24 03:12:29 +04:00
|
|
|
if(renderX <= 0) {
|
|
|
|
renderX = 1;
|
|
|
|
}
|
|
|
|
if(renderY <= 0) {
|
|
|
|
renderY = 1;
|
|
|
|
}
|
2012-02-17 09:49:26 +04:00
|
|
|
|
2012-02-24 03:12:29 +04:00
|
|
|
menu.css('top', renderY).css('left', renderX);
|
|
|
|
menu.show();
|
|
|
|
}
|
|
|
|
});
|
|
|
|
},
|
|
|
|
addSelection: function(element) {
|
|
|
|
element.addClass(contextMenuSelectionClass);
|
|
|
|
methods.checkSelectionBox(element, true);
|
|
|
|
},
|
|
|
|
isSelected: function(element) {
|
|
|
|
return element.hasClass(contextMenuSelectionClass);
|
|
|
|
},
|
|
|
|
toggleSelection: function(element) {
|
|
|
|
if(methods.isSelected(element)) {
|
|
|
|
methods.removeSelection(element);
|
|
|
|
} else {
|
|
|
|
methods.addSelection(element);
|
2012-02-17 09:49:26 +04:00
|
|
|
}
|
2012-02-24 03:12:29 +04:00
|
|
|
},
|
|
|
|
removeSelection: function(element) {
|
|
|
|
element.removeClass(contextMenuSelectionClass);
|
|
|
|
methods.checkSelectionBox(element, false);
|
|
|
|
},
|
|
|
|
checkSelectionBox: function(element, checked) {
|
|
|
|
var inputs = element.find('input');
|
|
|
|
inputs.each(function() {
|
|
|
|
inputs.attr('checked', checked ? 'checked' : false);
|
|
|
|
});
|
2012-05-19 02:57:03 +04:00
|
|
|
},
|
|
|
|
toggleIssuesSelection: function(e) {
|
|
|
|
e.preventDefault();
|
|
|
|
e.stopPropagation();
|
|
|
|
var issues = $(this).parents('form').find('tr.issue');
|
|
|
|
var checked = methods.isSelected(issues.eq(0));
|
|
|
|
issues.each(function() {
|
|
|
|
var self = $(this);
|
|
|
|
if(checked) {
|
|
|
|
methods.removeSelection(self)
|
|
|
|
} else {
|
|
|
|
methods.addSelection(self);
|
|
|
|
}
|
|
|
|
});
|
2012-02-17 09:49:26 +04:00
|
|
|
}
|
2012-02-24 03:12:29 +04:00
|
|
|
};
|
2012-02-17 09:49:26 +04:00
|
|
|
|
|
|
|
methods.createMenu();
|
|
|
|
|
|
|
|
if(!observingContextMenuClick) {
|
2012-02-24 03:12:29 +04:00
|
|
|
element.bind('click.contextMenu', methods.click);
|
|
|
|
element.bind('contextmenu.contextMenu', methods.click);
|
2012-02-17 09:49:26 +04:00
|
|
|
observingContextMenuClick = true;
|
|
|
|
}
|
|
|
|
|
2012-05-19 02:57:03 +04:00
|
|
|
if(!observingToggleAllClick) {
|
|
|
|
element.find('.issues img[alt="Toggle_check"]').bind('click', methods.toggleIssuesSelection);
|
|
|
|
observingToggleAllClick = true;
|
|
|
|
}
|
|
|
|
|
2012-02-17 09:49:26 +04:00
|
|
|
methods.unselectAll();
|
2012-02-24 03:12:29 +04:00
|
|
|
};
|
|
|
|
|
|
|
|
$.fn.ContextMenu = function(u) {
|
|
|
|
return this.each(function() {
|
|
|
|
new ContextMenuClass($(this), {url: u});
|
|
|
|
});
|
2012-02-17 09:49:26 +04:00
|
|
|
};
|
|
|
|
})(jQuery);
|
2012-02-24 03:08:47 +04:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Wrapper function to support the old way of creating aa context menu.
|
|
|
|
*/
|
|
|
|
function ContextMenu() {
|
|
|
|
jQuery(document).ContextMenu(arguments);
|
|
|
|
}
|