My goal is to disable right-click everywhere except <kbd>
and <textarea>
tags. I am using *:not(kbd,textarea)
to exclude disabling right-click - .on('contextmenu', function(e){ e.preventDefault(); });
. It is supposed that I can right click on <kbd>
and <textarea>
tags but I cannot. It is werid.
$(document).ready(function(){
$('*:not(kbd,textarea)').on('contextmenu', function(e){
e.preventDefault();
});
});
div {
width: 170px;
height: 170px;
background-color: green;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div>
<kbd>right click me</kbd>
<textarea>right click me</textarea>
can't right click me
</div>
To be clear: *:not(kbd,textarea)
works just fine. The problem has to do with how events are processed in browsers.
Most events bubble up, contextmenu
does as well. Since the <kbd>
and <textarea>
elements are inside the <div>
, the event handler bound to the <div>
will always cancel the contextmenu
event.
Depending on your exact use case, you could simply check whether the event originated on the element itself and only prevent it in that case:
$(document).ready(function(){
$('*:not(kbd,textarea)').on('contextmenu', function(e){
if (this === e.target) {
e.preventDefault();
}
});
});
div {
width: 170px;
height: 170px;
background-color: green;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div>
<kbd>right click me</kbd>
<textarea>right click me</textarea>
can't right click me
</div>
However, instead of binding the handler to every element, use event delegation. Bind the handler to the root of the document and check where the event originates from:
$(document).ready(function(){
$('body').on('contextmenu', function(e){
if (!$(e.target).is('kbd,textarea')) {
e.preventDefault();
}
});
});
div {
width: 170px;
height: 170px;
background-color: green;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div>
<kbd>right click me</kbd>
<textarea>right click me</textarea>
can't right click me
</div>