javascript - Safari extension: Event for a completely new tab? - Stack Overflow

I'm looking to redirect new tabs in Safari to a certain URL, in essence changing the default new t

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?

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?

Share Improve this question edited Apr 4, 2020 at 13:37 Brian Tompsett - 汤莱恩 5,89372 gold badges61 silver badges133 bronze badges asked Apr 13, 2012 at 21:43 KevinKevin 6821 gold badge10 silver badges18 bronze badges
Add a ment  | 

1 Answer 1

Reset to default 8

In your open event handler, first check if the event target is a tab. If it is, register an event handler for the beforeNavigate event on that tab. Also set a timeout to deregister the handler if the beforeNavigate event does not fire within, say, 50 milliseconds. For example:

function handleOpen(e) {
    if (e.target instanceof SafariBrowserTab) {
        e.target.addEventListener('beforeNavigate', handleBeforeNavigate, false);
        setTimeout(function () {
            e.target.removeEventListener('beforeNavigate', handleBeforeNavigate, false);
        }, 50);
    }
}

Now, there are three relevant possible outes 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:

function handleOpen(e) {
    if (e.target instanceof SafariBrowserTab) {
        e.target.addEventListener('beforeNavigate', handleBeforeNavigate, false);
        setTimeout(function () {
            e.target.removeEventListener('beforeNavigate', handleBeforeNavigate, false);
            takeOverTab();
        }, 50);
    }
}

Case 2: The beforeNavigate event will fire, and its url property will have a value of null. 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:

function handleBeforeNavigate(e) {
    e.target.removeEventListener('beforeNavigate', handleBeforeNavigate, false);
    if (e.url === null) {
        takeOverTab();
    }
}

Case 3: The beforeNavigate will fire, and its url 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 mand (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 mand, 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:

    function handleMessage(e) {
        if (e.name === 'linkClicked') {
            lastClickedLinkUrl = e.message.url;
            lastLinkClickTime = e.message.clickTime;
        }
    }
    
  • In your beforeNavigate handler, test whether the event's url 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:

    function handleBeforeNavigate(e) {
        e.target.removeEventListener('beforeNavigate', handleBeforeNavigate, false);
        if (e.url === null) {
            takeOverTab();
        } else if (e.url !== lastClickedLinkUrl || (new Date) - lastLinkClickTime > 100) {
            takeOverTab();
        }
    }
    

Note that this detection method is not foolproof. There are probably a number of ways it could go wrong. Still, I hope this helps.

发布者:admin,转转请注明出处:http://www.yc00.com/questions/1744785378a4593590.html

相关推荐

发表回复

评论列表(0条)

  • 暂无评论

联系我们

400-800-8888

在线咨询: QQ交谈

邮件:admin@example.com

工作时间:周一至周五,9:30-18:30,节假日休息

关注微信