Updates the plugin so that it can support multiple instances.

Multiple instances need to be applied to different elements in the DOM
otherwise multiple menus will be called for each click/right click.

e.g.

jQuery(document).ContextMenu(url);

would work for any form on a page. Using this would mean that multiple
instances couldn't be used though

jQuery('#content form').eq(0).ContextMenu(url);
jQuery('#content form').eq(3).ContextMenu(url);

Using the above 2 menus will be created for the first and 4th forms on
the page. Any of forms won't response to menu clicks.

jQuery(docuemnt).ContextMenu(url);
jQuery('#content form').eq(0).ContextMenu(url);

With the above any form on the page will respond to menu clicks but the
first form will send 2 requests for the context menu.
This commit is contained in:
Andrew Smith 2012-02-24 09:12:29 +10:00 committed by Felix Schäfer
parent 2b640f76ec
commit a510f0a85f
1 changed files with 190 additions and 185 deletions

View File

@ -1,212 +1,217 @@
(function($) {
var observingContextMenuClick;
var url;
var lastSelected;
var menu;
var menuId = 'context-menu';
var selectorName = 'hascontextmenu';
var contextMenuSelectionClass = 'context-menu-selection';
var reverseXClass = 'reverse-x';
var reverseYClass = 'reverse-y';
var ContextMenuClass = function(el, options) {
var element = el;
var opts = options;
var observingContextMenuClick;
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);
var methods = {
createMenu: function() {
if(!menu) {
$('#wrapper').append('<div id="' + menuId + '" style="display:none"></div>');
menu = $('#' + menuId);
}
},
click: function(e) {
var target = $(e.target);
if(target.is('a')) {
return;
}
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:
if(target.is('a')) {
return;
}
},
leftClick: function(e) {
var target = $(e.target);
var tr = target.parents('tr');
if((tr.size() > 0) && tr.hasClass(selectorName))
{
// a row was clicked, check if the click was on checkbox
if(target.is('input'))
}
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))
{
// a checkbox may be clicked
if (target.is(':checked')) {
tr.addClass(contextMenuSelectionClass);
} else {
tr.removeClass(contextMenuSelectionClass);
// a row was clicked, check if the click was on checkbox
if(target.is('input'))
{
// a checkbox may be clicked
if (target.is(':checked')) {
tr.addClass(contextMenuSelectionClass);
} else {
tr.removeClass(contextMenuSelectionClass);
}
}
else
{
if (e.ctrlKey || e.metaKey)
{
methods.toggleSelection(tr);
}
else if (e.shiftKey)
{
if (lastSelected !== null)
{
var toggling = false;
var rows = $(selectorName);
for (i = 0; i < rows.length; i++)
{
if (toggling || rows[i] == tr)
{
methods.addSelection(rows[i]);
}
if (rows[i] == tr || rows[i] == lastSelected)
{
toggling = !toggling;
}
}
} else {
methods.addSelection(tr);
}
} else {
methods.unselectAll();
methods.addSelection(tr);
}
lastSelected = tr;
}
}
else
{
if (e.ctrlKey || e.metaKey)
{
methods.toggleSelection(tr);
}
else if (e.shiftKey)
{
if (lastSelected !== null)
{
var toggling = false;
var rows = $(selectorName);
for (i = 0; i < rows.length; i++)
{
if (toggling || rows[i] == tr)
{
methods.addSelection(rows[i]);
}
if (rows[i] == tr || rows[i] == lastSelected)
{
toggling = !toggling;
}
}
} else {
methods.addSelection(tr);
}
// click is outside the rows
if (target.is('a') === false) {
this.unselectAll();
} else {
methods.unselectAll();
methods.addSelection(tr);
if (target.hasClass('disabled') || target.hasClass('submenu')) {
e.preventDefault();
}
}
}
},
rightClick: function(e) {
var target = $(e.target);
var tr = target.parents('tr');
if((tr.size() === 0) || !(tr.hasClass(selectorName))) {
return;
}
e.preventDefault();
if(!methods.isSelected(tr)) {
methods.unselectAll();
methods.addSelection(tr);
lastSelected = tr;
}
}
else
{
// click is outside the rows
if (target.is('a') === false) {
this.unselectAll();
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);
}
if(maxHeight > $(window).height()) {
renderY =+ menu.height();
menu.addClass(reverseYClass);
} else {
menu.removeClass(reverseYClass);
}
if(renderX <= 0) {
renderX = 1;
}
if(renderY <= 0) {
renderY = 1;
}
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 {
if (target.hasClass('disabled') || target.hasClass('submenu')) {
e.preventDefault();
}
methods.addSelection(element);
}
},
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);
});
}
},
rightClick: function(e) {
var target = $(e.target);
var tr = target.parents('tr');
};
if((tr.size() === 0) || !(tr.hasClass(selectorName))) {
return;
}
e.preventDefault();
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: 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);
}
if(maxHeight > $(window).height()) {
renderY =+ menu.height();
menu.addClass(reverseYClass);
} else {
menu.removeClass(reverseYClass);
}
if(renderX <= 0) {
renderX = 1;
}
if(renderY <= 0) {
renderY = 1;
}
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);
}
},
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);
});
}
};
$.fn.ContextMenu = function(u) {
url = u;
methods.createMenu();
if(!observingContextMenuClick) {
$(document).bind('click.contextMenu', methods.click);
$(document).bind('contextmenu.contextMenu', methods.click);
element.bind('click.contextMenu', methods.click);
element.bind('contextmenu.contextMenu', methods.click);
observingContextMenuClick = true;
}
methods.unselectAll();
lastSelected = null;
};
$.fn.ContextMenu = function(u) {
return this.each(function() {
new ContextMenuClass($(this), {url: u});
});
};
})(jQuery);