Handling page loads
A lot of the code in WebApp Tabs is dedicated to redirecting loads such that any attempt to load a know webapp will open in a new tab (or an existing one) and any attempt to open other urls will open in the default browser. Unfortunately Gecko doesn't make this straightforward. Thunderbird contains some rudimentary code for this but it is entirely based on analysing the link in a click handler and so fails for JS or targetted loads.
WebApp Tabs uses a combination of three techniques working together to be able to control link opening fully:
When a link element it triggered the platform calls
nsIXULBrowserWindow.onBeforeLinkTraversal to allow the frontend to change the
named target of the link. It isn't possible to cancel the link load at this
point but it can be retargetted back to window that opened it to stop any
new tabs from being opened.
- Get the target window for the link from docshell.
- If the target window is an inner frame then leave the target the same, inner frames can load whatever they like.
- If the target window isn't a webapp then leave the target the same to avoid breaking other extensions.
- If the new link is the same webapp as the source window and if the link isn't targetted to a new window then retarget it to the top of the source window.
- Otherwise if the new link is the same webapp as the source window then just leave the target the same.
- If the new link is not to a webapp then leave the target the same, the content policy will take over the load later.
- Otherwise the link is to a new webapp, target it to the existing window to avoid opening a new tab. The content policy will cancel the load later. Open the new webapp.
When a page load requires a new tab/window, either because of a call to
window.open or because of a _blank link target then
is called to get a new window. Again there isn't a way to cancel the load from
here and also if an existing window is returned its content will be cleared
ready for the new page. Also the new URL isn't passed to this function but the
window performing the open is.
- If the opening window is a webapp then create a hidden browser element and pass that back to be used for the load, the content policy will redirect the load somewhere sensible.
- Otherwise just allow the default handler to run.
Content policies are called just before a page load begins and is the last chance to cleanly cancel the load. They generally get a lot of information, the source page and url and the target url and load type.
- If the load is for anything except a top-level document then just allow it.
- If the load is for anything except ftp, http or https then just allow it.
- If there isn't a page URL then allow the load.
- If the load came from a hidden browser created by openURI then delete the browser. If the URL is for a webapp then open it in Thunderbird otherwise open it externally.
- If the load didn't come from a webapp then allow it.
- If the load is for the same webapp then allow it.
- If the load is for a different webapp then deny it, onBeforeLinkTraversal will have opened a new tab for it.
- Otherwise open the link externally.