How to hook into the contextmenu event of a browser
I keep getting puzzled, can't find a contextmenu that will work for me. Maybe someone can help?
Here's to what I need contextMenu to be added to:
<ul id="list_{id}" class="list">
<li id="Item_{id}"><a ondblclick=""><span>{title}</span></a></li>
</ul>
This is dynamic list, so it will add many more of them on the page and differ them by giving different ID's. So I need a contextMenu which will be added to every list but for each list an unique contextMenu. Basically different instances of contextMenu in every list, by adding 开发者_StackOverflow中文版dynamic {id} tag to the ID of contextMenu or something like that.
Thanks
It's kind of hard to tell what you're asking, but if you want to hook into the "context menu" event of a browser, you hook the contextmenu
event and then do whatever you're going to do (which could include creating a div
, for instance, with options on it — e.g., your own context menu). You can either do that on the lists themselves, individually, via getElementById
as you indicated in your question, or you can do it by hooking the event on some container that holds all of the lists, and then figuring out when the event is triggered which list it was triggered on ("event delegation").
See the end of this answer for the event delegation approach. But assuming you have a way of knowing the actual IDs used and you want to hook each list specifically for some reason:
HTML:
<ul id='list_1'>
<li>List 1 item 1</li>
<li>List 1 item 2</li>
</ul>
<ul id='list_2'>
<li>List 2 item 1</li>
<li>List 2 item 2</li>
</ul>
JavaScript:
hookEvent(document.getElementById('list_1'), 'contextmenu', function(event) {
event = event || window.event;
if (event.preventDefault) {
event.preventDefault();
}
display("List 1 context menu");
return false;
});
hookEvent(document.getElementById('list_2'), 'contextmenu', function(event) {
event = event || window.event;
if (event.preventDefault) {
event.preventDefault();
}
display("List 2 context menu");
return false;
});
function hookEvent(element, event, handler) {
if (element.addEventListener) {
element.addEventListener( event, handler, false);
}
else if (element.attachEvent) {
element.attachEvent('on' + event, handler);
}
else {
element['on' + event] = handler;
}
}
Live example
Note that only some (most) browsers let you cancel the default context menu.
Update: Re your "but what if the ID is bindable?" question below: I'm afraid I don't know what you mean by "bindable" — none of the tags on your question indicates a specific templating technology. You haven't even mentioned whether the templating is happening server-side or client-side, which makes it hard to help. But basically, by the time the JavaScript is running, there will be real IDs on real elements in the document. You'll have to know what those IDs are in order to use getElementById
.
Server-side templating:
If those IDs are going to be completely dynamic and the template is being handled on the server, you can include a small bit of script that passes those IDs on to JavaScript. For instance, near the top of your document you might have:
<script type='text/javascript'>
var mySpecialListIDs = [];
</script>
...and then update your template to add a small script
tag each time it's expanded:
<ul id="list_{id}" class="list">
<li id="Item_{id}"><a ondblclick=""><span>{title}</span></a></li>
</ul>
<script type='text/javascript'>
mySpecialListIDs.push("{id}");
</script>
Then your client-side code can loop through mySpecialLitIDs
and use each ID when hooking up the handler.
Client-side templating:
If the templating is being done client-side, this gets a bit simpler: Just set up your mySpecialListIDs
list at some convenient place in your client-side script, and the append to it each time you call the templating engine.
Event Delegation: Whether you're doing server- or client-side templating, if you're going to have dynamic lists like this, sometimes event delegation is the best way to handle it. The contextmenu
event (like most, but not all, events) bubbles up the DOM. So if you hook it on an ancestor element (something that contains all of your lists, like the document body itself or some such), you can then see which actual list was clicked by examining the event object. Like this:
HTML:
<div id='list_container'>
<ul id='list_1'>
<li>List 1 item 1</li>
<li>List 1 item 2</li>
</ul>
<ul id='list_2'>
<li>List 2 item 1</li>
<li>List 2 item 2</li>
</ul>
</div>
JavaScript (using the hookEvent
function from above):
// Hook up the contextmenu event on the container, not
// on each list:
hookEvent(document.getElementById('list_container'),
'contextmenu',
handleListContextMenu);
// Our handler function
function handleListContextMenu(event) {
var target;
// Handle IE-vs-the-world difference
event = event || window.event;
// Find out what the actual target element clicked was
target = event.target || event.srcElement;
// See if it or an ancestor of it is one of our lists
while (target &&
(target.tagName !== "UL" || !target.id || target.id.substring(0, 5) !== "list_")) {
target = target.parentNode;
}
// Did we find a list?
if (target) {
// Yes, handle this.
if (event.preventDefault) {
event.preventDefault();
}
display("List '" + target.id + "' context menu");
return false;
}
}
Live example
精彩评论