15

I want to write a bookmarklet that will modify any webpage so that when the JavaScript code on that page does something like document.location = 'http://site.tld' or document.location.href = 'http://site.tld' the page will open a new tab or window instead of changing location; same as if code was window.open('http://site.tld');

Can I modify the prototype somehow to achieve this goal? (I use this word carelessly because although I've read about modifying prototypes a few times, I've never actually done it.) Or is there some other way?

DG.
  • 3,417
  • 2
  • 23
  • 28

5 Answers5

8

You didn't say which browser you're using, but the only way I can think of to accomplish this is using Firefox's Object.watch.

document.watch('location', function(prop, oldval, newval) {
    window.open(newval);
    return '#';
});

This will intervene on any attempt to set document.location, open a window with the same argument instead, and then change the assignment to '#' instead (which will do nothing, usually).

In bookmarklet form, and expanded to cover both document.location and window.location:

javascript:(function(){var handle=function(prop, oldval, newval){window.open(newval); return '#';};document.watch('location',handle);window.watch('location',handle);})();

But even this won't work against assignment to document.location.href; the location object is some special thing that Object.watch refuses to work on.

If that's not enough, you could use onbeforeunload to prompt you when you try to navigate away and cancel it (if that's your goal here).

Best I've got, sorry!

Eevee
  • 47,412
  • 11
  • 95
  • 127
  • Not an ideal answer, but if no one else provides something better, you'll get the bounty. FYI, `onbeforeunload` isn't useful unless I could somehow know what URL to then open in new window. Simply stopping navigation isn't the goal. Forcing new tab is. But thanks for mentioning it anyway. – DG. Jan 18 '13 at 22:27
3

I was going to suggest using the ES5 Object.defineProperty, but as it should be, document.location is a "configurable: false" object, meaning that it can't be changed. For the curious, if you would be able to change it the code would be like this:

Object.defineProperty(document.location, 'href', {
     get: function() { return this.href },
     set: function(value) { this.href = value; window.open(value); return false} //Not sure about this part, but anyways...
});

Edit: Answering your question, i don't think that this is achievable via a bookmarlet.

Bruno
  • 1,368
  • 9
  • 11
  • Thanks for that. Nice to learn about anyway. In theory, if it was possible to do this, would it be possible to access the "original" document.location inside the new function? – DG. Jan 24 '13 at 07:12
  • In wich sense you mean the original? What would happend with the above code is that when location.href was setted (href = "http://google.com") the set function would trigger, setting the .href value to the one being defined and opening a new window. – Bruno Jan 25 '13 at 20:04
2

I tried different methods but it's almost impossible to trace the href of the target window.

Using

window.onbeforeunload = function(e) {
    window.open(document.location.href);
};

will open your current window in another tab and the target in current window. The problem is that onbeforeunload is triggered not only on changing the location of the window, even on closing window or refreshing it. Depends where you want to use it.

PS:

window.onunload = function() {
    document.location = document.location;
}

if you test this, when you change the page location, you will be able to see the new url in the address bar for a moment then you will be redirected to your current page. I didn't managed to get the new target. Good luck!

Gabriel Lupu
  • 1,599
  • 1
  • 12
  • 16
1

You could only do something with the prototype if it were a function call rather than an assignment. For example in the case of document.write

document.write = function(txt) {
   alert("txt");
};

document.write("test");   
Jeroen K
  • 10,258
  • 5
  • 41
  • 40
-1

FWIW: This works on the latest firefox to search for the selected text in a new tab:

javascript:Qr=document.getSelection();if(!Qr){void(Qr=prompt('Keywords...',''))};if(Qr)window.open("http://google.com/search?query="+escape(Qr));void(0)