嗨,我正在使用jQuery上下文菜单插件。但是刚才,我们注意到它在第一次右键单击时不起作用。它仅在第二次右键单击时响应。有人可以指出我正确的方向以解决此问题吗?
这是插件上下文菜单的代码
/*!
* jQuery ContextMenu
* http://www.userdot.net/#!/jquery
*
* Copyright 2011, UserDot www.userdot.net
* Licensed under the GPL Version 3 license.
* Version 1.0.0
*
*/
(function($) {
var classes = {
popupDiv : 'uctxMenu',
separator : 'separator',
hover : 'hover',
disabled : 'disabled'
},
defaults = {
menu : null,
mouseButton : 'left',
isMenu : true,
minWidth : 120,
maxWidth : 0,
delay : 500,
keyboard : true,
hoverIntent : true,
onSelect : function(item) {},
onLoad : function() {alert("click")},
onShow : function() {},
onHide : function() {}
},
menus = [],
methods = {
init : function(options) {
options = $.extend({}, defaults, options);
if (!options.menu) {
return false;
}
var $menu;
if ((typeof(options.menu) === 'object') && (options.menu.constructor.toString().match(/array/i) !== null || options.menu.length)) {
$menu = $('<div/>').append(buildMenu(options.menu));
$('body').append($menu);
$menu.data('uctxDynamic', true);
}
else {
$menu = $(document.getElementById(options.menu));
$menu.data('uctxDynamic', false);
$menu.data('uctxOriginal', $menu.clone());
}
return this.each(function() {
var $this = $(this),
eventNamespace;
if (!$this.data('uctxMenu')) {
eventNamespace = "uctxContext-" + (new Date().getTime());
$this.data('uctxEventNamespace', eventNamespace)
.data('uctxOptions', options)
.data('uctxMenu', $menu)
.data('uctxEnable', true);
$menu.data('isMenu', options.isMenu);
if (! $menu.data('uctxOwners')) {
$menu.data('uctxOwners', []);
}
$menu.data('uctxOwners').push($this);
menus.push($menu);
if (options.isMenu) {
methods.refresh.call($this);
}
else {
$menu.hide();
$menu.css({
'position' : 'absolute',
'z-index' : 99999
});
}
$this.bind((((options.mouseButton === 'right') ? 'contextmenu' : 'click') + '.' + eventNamespace), function(e){
if (! $this.data('uctxEnable')) {
return true;
}
methods.show.apply($this, [e.pageX, e.pageY, options.showAnimation]);
if (options.isMenu && options.keyboard) {
$(window).bind('keydown.' + eventNamespace, function(even){
var $currentItem;
switch (event.keyCode) {
case 27:
$(document).trigger('click.' + eventNamespace);
break;
case 40:
if ($menu.find('li.' + classes.hover).length === 0) {
$menu.find('li:not(.disabled):first').addClass(classes.hover);
}
else {
$currentItem = $menu.find('li.' + classes.hover + ':last');
$currentItem.parent().find('li.' + classes.hover).removeClass(classes.hover).nextAll('li:not(.disabled)').eq(0).addClass(classes.hover);
if ($currentItem.parent().find('li.' + classes.hover).length === 0) {
$currentItem.parent().find('li:not(.disabled):first').addClass(classes.hover);
}
}
return false;
case 38:
if ($menu.find('li.' + classes.hover).length === 0) {
$menu.find('li:not(.disabled):first').nextAll().eq(-1).addClass(classes.hover);
}
else {
$currentItem = $menu.find('li.' + classes.hover + ':last');
$currentItem.parent().find('li.' + classes.hover).removeClass(classes.hover).prevAll('LI:not(.disabled)').eq(0).addClass(classes.hover);
if ($currentItem.parent().find('li.' + classes.hover).length === 0) {
$currentItem.parent().find('li:first').nextAll().eq(-1).addClass(classes.hover);
}
}
return false;
case 39:
if ($menu.find('li.' + classes.hover + ' ul').length > 0) {
$menu.find('li.' + classes.hover + ':last').find('ul:first').show().offset(forceViewport({
top: $menu.find('li.' + classes.hover + ':last').offset().top
}, $menu.find('li.' + classes.hover + ':last').find('ul:first')));
$menu.find('li.' + classes.hover + ':last ul:first li:not(.disabled):first').addClass(classes.hover);
}
return false;
case 37:
if (!$menu.find('li.' + classes.hover + ':last').parent().parent().hasClass(classes.popupDiv)) {
$menu.find('li.' + classes.hover + ':last').removeClass(classes.hover).parent().hide();
}
return false;
}
return true;
});
}
else {
if (options.keyboard) {
$(window).bind('keydown.' + eventNamespace, function(even){
if (event.keyCode === 27) {
$(document).trigger('click.' + eventNamespace);
}
});
}
}
$('li', $menu).each(function() {
$(this).click(function() {
if (!$(this).hasClass(classes.disabled)) {
options.onSelect.call(this, {
id : $(this).attr('id'),
action : $('a:first', this).attr('href').substr(1)
});
}
});
});
$(document).bind('click.' + eventNamespace, function(e){
$(window).unbind('keydown.' + eventNamespace);
$(document).unbind('click.' + eventNamespace);
$('li', $menu).unbind('click');
methods.hide.call();
});
options.onShow.call(this);
return false;
});
}
options.onLoad.call(this);
});
},
refresh : function(options) {
var opts;
return this.each(function() {
var $this = $(this),
$menu = $this.data('uctxMenu'),
calculatedWidth,
$widthTest;
if ($this.data('uctxMenu').data('isMenu')) {
opts = $.extend($this.data('uctxOptions'), options);
if (opts.hoverIntent && ! $.fn.hoverIntent) {
opts.hoverIntent = false;
}
$menu.removeClass(classes.popupDiv);
$('li', $menu).removeClass(classes.hover);
$('span', $menu).remove();
$menu.addClass(classes.popupDiv);
$widthTest = $('<div/>').addClass(classes.popupDiv).appendTo('body');
$('ul', $menu).each(function() {
$widthTest.html('');
calculatedWidth = 0;
$widthTest.html($(this).html());
calculatedWidth = $widthTest.width() + 16;
if (calculatedWidth < opts.minWidth) {
calculatedWidth = opts.minWidth;
}
if (calculatedWidth > opts.maxWidth && opts.maxWidth > 0){
calculatedWidth = opts.maxWidth;
}
$(this).width(calculatedWidth);
$(this).children('li').children('ul').css('left', calculatedWidth);
});
$widthTest.remove();
$('li:has(ul)', $menu).each(function(){
if (! $(this).hasClass(classes.disabled)) {
$('a:first', this).append($('<span/>'));
if (opts.hoverIntent) {
$(this).hoverIntent({
over : function() {
$('ul:first', this).show().offset(forceViewport({
top: $(this).offset().top
}, $('ul:first',this)));
},
out : function() {
$('ul:first', this).hide();
},
timeout : opts.delay
});
}
else {
$(this).hover(function() {
$('ul:first', this).show().offset(forceViewport({
top: $(this).offset().top
}, $(this).find('ul:first')));
}, function() {
$('ul:first', this).hide();
});
}
}
});
$('li', $menu).each(function() {
$(this).click(function() {
if ($('ul', this).length < 1) {
$('li', $menu).unbind('click');
$menu.hide();
}
return false;
});
$(this).hover(function() {
$(this).parent().find('li.' + classes.hover).removeClass(classes.hover);
$(this).addClass(classes.hover);
}, function() {
$(this).removeClass(classes.hover);
});
});
}
});
},
restore : function() {
return this.each(function() {
var $this = $(this),
$menu = $this.data('uctxMenu');
$this.unbind('.' + $this.data('uctxEventNamespace'));
$(window).unbind('keydown.' + $this.data('uctxEventNamespace'));
$(document).unbind('click.' + $this.data('uctxEventNamespace'));
$.each($menu.data('uctxOwners'), function(index) {
if ($this[0] === this) {
$menu.data('uctxOwners').splice(index, 1);
}
});
if ($menu.data('uctxOwners').length < 1) {
$.each(menus, function(index) {
if ($menu[0] === this) {
menus.splice(index, 1);
}
});
if ($menu.data('uctxDynamic')) {
$menu.remove();
}
else {
$menu.removeClass(classes.popupDiv);
$menu.replaceWith($menu.data('uctxOriginal'));
}
}
$this.removeData('uctxEventNamespace');
$this.removeData('uctxMenu');
$this.removeData('uctxOptions');
$this.removeData('uctxEnable');
});
},
show : function(x, y) {
if (!x || !y) {
$.error('The position for the menu has not been specified');
return false;
}
var $menu = $(this).first().data('uctxMenu');
methods.hide.apply(this);
$menu.show();
$menu.data('uctxMenu', $(this));
$menu.offset(forceViewport({
top : y,
left: x
}, $menu, true));
return this;
},
hide : function() {
$.each(menus, function() {
$('.' + classes.hover, this).removeClass(classes.hover);
$('ul:first ul', this).hide();
if ($(this).data('uctxMenu')) {
$(this).data('uctxMenu').data('uctxOptions').onHide.call($(this).data('uctxMenu'));
$(this).removeData('uctxMenu');
}
$(this).hide();
});
return this;
},
disable : function(item) {
if (item) {
var $menu = $(this).data('uctxMenu');
if (item.charAt(0) === '#') {
$('li' + item.replace(/ /g,'_'), $menu).addClass(classes.disabled);
}
else {
$('a[href="' + item + '"]', $menu).parent().addClass(classes.disabled);
}
}
else {
$(this).data('uctxEnable', false);
}
return this;
},
enable : function(item) {
if (item) {
var $menu = $(this).data('uctxMenu');
if (item.charAt(0) === '#') {
$('li' + item.replace(/ /g,'_'), $menu).removeClass(classes.disabled);
}
else {
$('a[href="' + item + '"]', $menu).parent().removeClass(classes.disabled);
}
}
else {
$(this).data('uctxEnable', true);
$('li', this).each(function() {
$(this).removeClass(classes.disabled);
});
}
return this;
}
},
forceViewport = function(position, o, mouse) {
if (position.top) {
if ((position.top + o.height() - $(window).scrollTop()) > $(window).height()) {
if (mouse) {
position.top = position.top - o.height();
}
else {
position.top = $(window).height() + $(window).scrollTop() - o.height();
}
}
if (position.top < $(window).scrollTop()) {
position.top = $(window).scrollTop();
}
}
if (position.left) {
if ((position.left + o.width() - $(window).scrollLeft() > $(window).width())) {
position.left = $(window).width() - o.width() + $(window).scrollLeft();
}
if (position.left < $(window).scrollLeft()) {
position.left = $(window).scrollLeft();
}
}
return position;
},
buildMenu = function(children) {
var ul = $('<ul/>'), entry, item, li;
if (children) {
for (entry in children) {
item = children[entry];
li = $('<li/>').attr('id' , item.id.replace(/ /g,'_')).append($('<a/>').attr('href', item.action?('#' + item.action):'#').text(item.text));
if (item.image) {
li.prepend($('<img/>').attr('src', item.image));
}
if (item.separator) {
li.addClass(classes.separator);
}
ul.append( li );
if (item.children) {
li.append(buildMenu(item.children));
}
}
}
return ul;
};
$.fn.contextMenu = function(method) {
if (methods[method]) {
return methods[ method ].apply(this, Array.prototype.slice.call(arguments, 1));
}
else if (typeof method === 'object' || ! method) {
return methods.init.apply(this, arguments);
}
else {
$.error('Method ' + method + ' does not exist on jQuery.contextmenu');
return this;
}
};
})(jQuery);
这就是我实现的方式
<g:itemLink id="itemsearch_${cmItemInstance.id}_${i}" itemId="${cmItemInstance.id}" > ${clientDisplayName}</g:itemLink>
<ul id="myMenu_${cmItemInstance.id}_${i}" class="contextMenu">
<li class="open"><g:itemLink id="openclaim_${cmItemInstance.id}_${i}" itemId="${cmItemInstance.id}" itemDataTip="false">Open Claim</g:itemLink></li>
<li class="transfer"><g:link action="transferItem" params="${[cm_item: cmItemInstance.id ] }" >Transfer Claim</g:link></li>
<li class="delete"><g:link action="deleteItem" params="${[cm_item: cmItemInstance.id ] }" >Delete Item</g:link></li>
</ul>
<g:javascript>
$("#VSO_Item_itemsearch_${cmItemInstance.id}_${i}").parent().contextMenu({ menu: 'myMenu_${cmItemInstance.id}_${i}' } );
</g:javascript>
最佳答案
我的队友设法解决了。显然,它不会检测到第一次单击时的操作。他改为这样:
<li class="open" ><a href="#" onclick="<g:itemLink asFunctionCall="true" id="openclaim_${cmItemInstance.id}_${i}" itemId="${cmItemInstance.id}" itemDataTip="false" />"> Open Claim </a></li>
<li class="transfer"><g:link onclick="window.open( this.href, '_self')" action="transferItem" params="${[cm_item: cmItemInstance.id ] }" >Transfer Claim</g:link></li>
<li class="delete"><g:link onclick="window.open( this.href, '_self')" action="deleteItem" params="${[cm_item: cmItemInstance.id ] }" >Delete Item</g:link></li>