18

I have the below JQuery eventhandler. I want to stop all navigations on a web page.

$(document).click(function(event) {
            event.stopPropagation();
            event.preventDefault();
            event.cancelBubble = true;
            event.stopImmediatePropagation();
            $(document).css('border-color','');
            $(document).css('background-color',''); 
            $(event.target).css('border-color','yellow');
            $(event.target).css('background-color','#6BFF70');
            return false;
    });

When I use this on Facebook Login page, it stops all navigations. But in Google home page, "I'm Feeling Lucky" button still navigates to next page. How do I avoid it?

I'm using JavaFX browser by the way. It is similar to Safari browser.

Kyle Trauberman
  • 25,414
  • 13
  • 85
  • 121
NaveenBharadwaj
  • 1,212
  • 5
  • 19
  • 42
  • I tried using $('*'). Still same behaviour. – NaveenBharadwaj Jul 21 '15 at 10:00
  • If you just want to prevent any user input, I would add a div that cover all the body – Hacketo Jul 21 '15 at 13:15
  • @Hacketo, I have to do this on any website that I load in the browser. I dont have a HTML of my own. – NaveenBharadwaj Jul 22 '15 at 09:29
  • Propagation of events is between elements; if the user clicks an element directly with a handler directly attached to it, stopping the propagation of the click event won't stop that event from firing. See this fiddle: http://jsfiddle.net/ejreseuu/. There is no way to stop 'click2' from being logged when clicking the sub-element; the propagation is correctly cancelled before it can trigger the 'click1' event, but there is no way to catch the event and stop it before the 'click2' event triggers. – Tahsis Claus Jul 27 '15 at 19:28

8 Answers8

28

If I load the Google search page, and execute this at the console:

document.body.addEventListener(
  "click", 
  function (ev) { ev.stopPropagation(); ev.preventDefault(); },
  true);

then I cannot click the "I'm Feeling Lucky" button anymore. The key is to use the third parameter and set it to true. Here is what MDN [says] about it:

useCapture Optional

If true, useCapture indicates that the user wishes to initiate capture. After initiating capture, all events of the specified type will be dispatched to the registered listener before being dispatched to any EventTarget beneath it in the DOM tree.

(Emphasis added.)

What you tried to do does not work because your event handler is on document, and thus will be called after any event handlers on the children of the document. So your handler cannot prevent anything.

With useCapture set to true, you can operate on the event before it gets a chance to be passed to the child element. I do not know of a way to have jQuery's event handlers work in the way you get with useCapture. Barmar's answer here says you can't use jQuery to set such handler. I'm inclined to believe him.

Community
  • 1
  • 1
Louis
  • 146,715
  • 28
  • 274
  • 320
  • Definitely the best vanilla javascript for click in a inner element of a parent div, without propagation click on parent div. It works just perfect! Thanks – Rafa Jul 12 '17 at 10:23
  • useCapture didn't make a difference for me but adding ev.preventDefault() finally stopped the bubbling – Fakeer Apr 23 '18 at 20:16
5

99.99% of webpages won't be able to have their navigation stopped by stopping event propagation for the reason I commented (you can't stop the event before it triggers all handlers for the initial target of the event). If preventing navigation is all you are interested in, I recommend using the window.onbeforeunload event, which is made for this exact situation.

Here is an example: http://jsfiddle.net/ejreseuu/

HTML:

<a href="google.com">google</a>

JS:

window.onbeforeunload = function() {
    return "Are you sure?"
}

There is no way to not have a confirmation box that I know of, as code that locks the user out of navigating away no matter what they do is generally malicious.

Ahmad Baktash Hayeri
  • 5,802
  • 4
  • 30
  • 43
Tahsis Claus
  • 1,879
  • 1
  • 15
  • 27
2

preventDefault() should not work in this case, cause Google relied on custom event listeners to handle click events on this button. While preventDefault() prevents browser's default behavior.

For example, if this button was of type="submit", preventing default on click event would prevent browser's default behavior, which is submitting a form. But in this case click is handled by eventListeners added to the button itself. preventDefault() won't affect catching an event by them. Nor stopPropagation(), because it stops propagation of event to higher levels of DOM, while other eventListeners on the same level (button in our case) still get the event. stopImmediatePropagation() could work in theory, but only if your eventListener was added before google's.

So the easiest way to stop propagation is to stop an event before it reaches button node, and that's on capture phase, because button is the lowest element in the hierarchy. This can be done by passing true argument while adding eventListener

document.body.addEventListener("click", function (event) { 
  event.stopPropagation();
}, true);

This way event will be stopped before bubble phase, and so before it reaches eventListeners added to the button. More on capture and bubble phases here

Note that preventDefault() is not needed in this case. Actually, this button's event listeners are to prevent default themselves. Here are those eventListeners, for click and keyup respectively:

d = function(a) {
 c.Xa.search(c.yc(), b);
 return s_1vb(a)
}

function(a) {
 13 != a.keyCode && 32 != a.keyCode || d(a)
}

note call to s_1vb, here is its sourse:

s_1vb.toString();
/*"function (a){
     a&&(a.preventDefault&&a.preventDefault(),a.returnValue=!1);
     return!1
  }"*/

Basically its a function that take an event and do everything possible to prevent browser's default behavior

By the way, default behavior can be canceled on any stage of event flow (se Events Specification), including the very last stage, when it reached document. Only after it passed "through" all eventListeners uncanceled, browser should execute its default behavior. So attaching your listener to document was not the reason preventDefault() didn't work, it was because it was the wrong guy for the job :)

Pavlo D
  • 346
  • 2
  • 8
1

Try this:

$('body').click(function(event) {
            event.stopPropagation();
            event.preventDefault();
            event.cancelBubble = true;
            event.stopImmediatePropagation();
            $(document).css('border-color','');
            $(document).css('background-color',''); 
            $(event.target).css('border-color','yellow');
            $(event.target).css('background-color','#6BFF70');
            return false;
    });
kimwz.kr
  • 298
  • 1
  • 9
0

Try to bind not only to click event, but as well on mousedown event.

Catalin
  • 11,503
  • 19
  • 74
  • 147
0

Try this css:

 body * {
    pointer-events: none;
 }

or in jQuery:

 $("body *").css("pointer-events", "none");
tnt-rox
  • 5,400
  • 2
  • 38
  • 52
0

Try declaring a new window event and then stopping the propagation from there:

var e = window.event;
e.cancelBubble = true;
if (e.stopPropagation)
{
   e.stopPropagation();
}
Skytiger
  • 1,745
  • 4
  • 26
  • 53
0

Note that Google uses jsaction="..." instead of onclick="...". Try to use it's unbind method on the specified button.

Also you can use dynamic attachment, like:

$(document).on('click', '*', function

Or throw new Error()(just as a dirty hack)

ScorpioT1000
  • 319
  • 2
  • 7