I'm looking to redirect new tabs in Safari to a certain URL, in essence changing the default new tab page. However, I do not want to redirect new tabs that are opened by following links.
The Windows and Tabs API describes tab "open" events, but these are fired when any new tab opens (including new tabs opened from links).
Is there a way to catch a new tab event for only those tabs that are created by clicking the new tab button?
Thanks in advance!
In your
open
event handler, first check if the event target is a tab. If it is, register an event handler for thebeforeNavigate
event on that tab. Also set a timeout to deregister the handler if thebeforeNavigate
event does not fire within, say, 50 milliseconds. For example:Now, there are three relevant possible outcomes for the
beforeNavigate
event following a tab open event.Case 1: The
beforeNavigate
event will not fire within the timeout. This usually means that the tab is empty. An empty tab cannot be the result of a link click, so we can put some code in the timeout function to do whatever we like with it:Case 2: The
beforeNavigate
event will fire, and itsurl
property will have a value ofnull
. This means that the tab will load either the Top Sites page or the Bookmarks page (two special Safari pages that are among the options for new tabs). Like an empty tab, such a tab cannot possibly be the result of a link click, so we can do what we like with the tab. For example:Case 3: The
beforeNavigate
will fire, and itsurl
value will be a non-empty string: that is, an actual URL. This is the tricky case, since the tab could have resulted from either a link click, the new-tab command (if the user has configured Safari to open new tabs to his home page), or the action of another app or extension. Let's call the case where the tab was the result of a link click Case 3A; the case where it was the result of the new-tab command, Case 3B; and the other-app case, Case 3C.I can't think of a way to distinguish between 3B and 3C. If there really isn't a way to distinguish these two cases, it could be very bad for your app, since you presumably don't want to redirect tabs that are opened by other apps.
If you don't care whether your app interferes with 3C tabs, there is at least one way to tell 3A tabs from 3B/3C tabs. This is the way that occurs to me:
Use an injected script in every page to listen for link clicks. When a link is clicked, relay the URL and the time of the click to the global page, which will remember them for future reference. For example:
In your
beforeNavigate
handler, test whether the event'surl
value is different from the URL of the last-clicked link. If it is, the new tab did not result from that link click, and thus it probably did not result from any link click. If the two URLs are the same, check whether more than, say, 100 milliseconds have elapsed since the last link click. If that's the case, it's probably just a coincidence that the URLs are the same, and so again you can infer that the new tab did not result from a link click. For example:Note that this detection method is not foolproof. There are probably a number of ways it could go wrong. Still, I hope this helps.