Many web pages force the link to open in a new window (or a new tab, collectively referred to as a new window below). Some people find this approach convenient, as it preserves the original page. But I don’t like this approach. Because I use Firefox, if I open a web page in a new window or tab, I can’t use the touchpad to swipe back to the previous page. Today, I’ll share with you the method to force the link to open in the current window or web page.
Before we share the method, let’s see what are the ways to make the browser open tabs in a new window.
The easiest way is to add the target="_blank"
attribute to all hyperlinks <a>
. This is also the most common way.
Adding target
to every <a>
tag is a bit wasteful, inconvenient to modify, and increases the size of the HTML file. One optimization is to add a target
attribute to the <base>
tag. Modifying the <base>
tag will affect all relative links. This means that this method only works for internal links.
The third option is to use JavaScript to dynamically modify the behavior of hyperlinks.
The easiest thing is to assign onclick
callback function to each <a>
tag and call window.open(url, '_blank')
in the function to open the new page.
A slightly more optimized solution would be to register a click'
event handler for document
, extract the href
attribute of the <a>
tag based on the target
of the event, and then call the open()
function to open the new page. This solution requires the click event to bubble
to the document
node to work.
All of the above is done by changing the behavior of the <a>
tag to open a new page, and the href
attribute of the <a>
tag is the target link. However, some content platforms do not write the target URL to the href
attribute, but write the URL as a link shaped like https://example.com?target=real-url
. When users click on it, they will jump to an intermediate page first and then click twice to jump to the target page, which is very inconvenient.
I wanted a unified way to deal with several of these types of issues. The first thing I did was to use a Chrome plugin called Death To _blank. This plugin does a very simple job of removing the target
attribute from the a
tag. But it didn’t cover the remaining cases. Then I migrated to Firefox and couldn’t find a similar extension. I ended up using Tampermonkey script to achieve the full functionality.
The script framework is as follows.
@run-at document-end
means that the script is run after the page is loaded, and @match *://*/*
means that the script is executed for all pages.
Then comes the real processing logic. The first step is to clear the target
attribute of the <base>
tag.
Not all pages will have <base>
tags, so you need to determine that.
The next step is to clean up the target
attribute on each <a>
tag. But there may be a lot of hyperlinks on the page, and only a few of them will actually be clicked, or not opened at all. It would be a waste to iterate through all the links and clean up the target
attribute right away. For this reason, I use a delayed processing approach. Simply put, we listen to the mousedown
event of the document
and determine if the current node is an <a>
tag when the event is triggered. Some web pages embed images, in-line code and other tags in the <a>
tag, so the target
of the mousedown
event is not necessarily the <a>
tag. For this reason, we have to iterate through the parent nodes of the current node to see if there is an <a>
tag.
The complete check logic is as follows.
|
|
If only the target
property is set, we can just clear it.
|
|
If the onclick
callback is set or if the document
listens for all <a>
clicks, we can clear the callback and disable the click
bubble.
|
|
Be careful though, some pages may use <a>
as a button, usually its href
will be #
, so you need to skip this. There are also a few pages that do intercept <a>
jumps via JavaScript, there is no way to identify this and you can only exclude specific domains via the plugin’s blacklist.
For those links with intermediate page jumps, we need to extract the target link and update the href
attribute.
Combine all functions to get the complete code.
|
|