author | Dave Townsend <dtownsend@oxymoronical.com> |
Tue, 02 Sep 2014 17:43:08 -0400 | |
changeset 203386 | 52b4f9600a14a5466d0374a187ba947fe061658d |
parent 203196 | 2dd9b2f2ef8fa99d631a4897027e0cf33f0e15e4 |
child 203387 | ee2ad2a64c1eeb79fe3286208a926941ade3d014 |
push id | 48665 |
push user | ryanvm@gmail.com |
push date | Wed, 03 Sep 2014 20:40:15 +0000 |
treeherder | mozilla-inbound@0da762e6868a [default view] [failures only] |
perfherder | [talos] [build metrics] [platform microbench] (compared to previous push) |
reviewers | smaug, felipe |
bugs | 961867 |
milestone | 35.0a1 |
first release with | nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
|
last release without | nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
|
--- a/browser/base/content/browser.js +++ b/browser/base/content/browser.js @@ -3556,52 +3556,21 @@ var XULBrowserWindow = { field.label = text; field.setAttribute("crop", type == "overLink" ? "center" : "end"); this.statusText = text; } }, // Called before links are navigated to to allow us to retarget them if needed. onBeforeLinkTraversal: function(originalTarget, linkURI, linkNode, isAppTab) { - let target = this._onBeforeLinkTraversal(originalTarget, linkURI, linkNode, isAppTab); + let target = BrowserUtils.onBeforeLinkTraversal(originalTarget, linkURI, linkNode, isAppTab); SocialUI.closeSocialPanelForLinkTraversal(target, linkNode); return target; }, - _onBeforeLinkTraversal: function(originalTarget, linkURI, linkNode, isAppTab) { - // Don't modify non-default targets or targets that aren't in top-level app - // tab docshells (isAppTab will be false for app tab subframes). - if (originalTarget != "" || !isAppTab) - return originalTarget; - - // External links from within app tabs should always open in new tabs - // instead of replacing the app tab's page (Bug 575561) - let linkHost; - let docHost; - try { - linkHost = linkURI.host; - docHost = linkNode.ownerDocument.documentURIObject.host; - } catch(e) { - // nsIURI.host can throw for non-nsStandardURL nsIURIs. - // If we fail to get either host, just return originalTarget. - return originalTarget; - } - - if (docHost == linkHost) - return originalTarget; - - // Special case: ignore "www" prefix if it is part of host string - let [longHost, shortHost] = - linkHost.length > docHost.length ? [linkHost, docHost] : [docHost, linkHost]; - if (longHost == "www." + shortHost) - return originalTarget; - - return "_blank"; - }, - onProgressChange: function (aWebProgress, aRequest, aCurSelfProgress, aMaxSelfProgress, aCurTotalProgress, aMaxTotalProgress) { // Do nothing. }, onProgressChange64: function (aWebProgress, aRequest, aCurSelfProgress, aMaxSelfProgress,
--- a/browser/base/content/content.js +++ b/browser/base/content/content.js @@ -628,8 +628,24 @@ let DOMFullscreenHandler = { this._fullscreenDoc = aEvent.target; sendAsyncMessage("MozEnteredDomFullscreen", { origin: this._fullscreenDoc.nodePrincipal.origin, }); } } }; DOMFullscreenHandler.init(); + +addMessageListener("Browser:AppTab", function(message) { + docShell.isAppTab = message.data.isAppTab; +}); + +let WebBrowserChrome = { + onBeforeLinkTraversal: function(originalTarget, linkURI, linkNode, isAppTab) { + return BrowserUtils.onBeforeLinkTraversal(originalTarget, linkURI, linkNode, isAppTab); + }, +}; + +if (Services.appinfo.processType == Services.appinfo.PROCESS_TYPE_CONTENT) { + let tabchild = docShell.QueryInterface(Ci.nsIInterfaceRequestor) + .getInterface(Ci.nsITabChild); + tabchild.webBrowserChrome = WebBrowserChrome; +}
--- a/browser/base/content/tabbrowser.xml +++ b/browser/base/content/tabbrowser.xml @@ -284,19 +284,17 @@ this.showTab(aTab); this.moveTabTo(aTab, this._numPinnedTabs); aTab.setAttribute("pinned", "true"); this.tabContainer._unlockTabSizing(); this.tabContainer._positionPinnedTabs(); this.tabContainer.adjustTabstrip(); - // Bug 961867 - [e10s] Implement the logic for app tabs - if (!gMultiProcessBrowser) - this.getBrowserForTab(aTab).docShell.isAppTab = true; + this.getBrowserForTab(aTab).messageManager.sendAsyncMessage("Browser:AppTab", { isAppTab: true }) if (aTab.selected) this._setCloseKeyState(false); let event = document.createEvent("Events"); event.initEvent("TabPinned", true, false); aTab.dispatchEvent(event); ]]></body> @@ -310,19 +308,17 @@ this.moveTabTo(aTab, this._numPinnedTabs - 1); aTab.removeAttribute("pinned"); aTab.style.MozMarginStart = ""; this.tabContainer._unlockTabSizing(); this.tabContainer._positionPinnedTabs(); this.tabContainer.adjustTabstrip(); - // Bug 961867 - [e10s] Implement the logic for app tabs - if (!gMultiProcessBrowser) - this.getBrowserForTab(aTab).docShell.isAppTab = false; + this.getBrowserForTab(aTab).messageManager.sendAsyncMessage("Browser:AppTab", { isAppTab: false }) if (aTab.selected) this._setCloseKeyState(true); let event = document.createEvent("Events"); event.initEvent("TabUnpinned", true, false); aTab.dispatchEvent(event); ]]></body>
--- a/browser/base/content/test/general/browser.ini +++ b/browser/base/content/test/general/browser.ini @@ -193,48 +193,41 @@ skip-if = e10s # Bug 691601 - no form su [browser_bug562649.js] skip-if = e10s # Bug 940195 - XULBrowserWindow.isBusy is false as a remote tab starts loading [browser_bug563588.js] [browser_bug565575.js] [browser_bug565667.js] run-if = toolkit == "cocoa" [browser_bug567306.js] [browser_bug575561.js] -skip-if = e10s # Bug 921905 - pinTab/unpinTab fail in e10s [browser_bug575830.js] skip-if = e10s # Bug 691614 - no e10s zoom support yet [browser_bug577121.js] -skip-if = e10s # Bug 921905 - pinTab/unpinTab fail in e10s [browser_bug578534.js] skip-if = e10s # Bug ?????? - test directly manipulates content [browser_bug579872.js] -skip-if = e10s # Bug 921905 - pinTab/unpinTab fail in e10s [browser_bug580638.js] -skip-if = e10s # Bug 921905 - pinTab/unpinTab fail in e10s [browser_bug580956.js] skip-if = e10s # Bug 516755 - SessionStore disabled for e10s [browser_bug581242.js] skip-if = e10s # Bug 930863 - pageshow issues ("TypeError: charset is undefined" in pageshow listener, as document is null) [browser_bug581253.js] skip-if = e10s # Bug 930863 - pageshow issues ("TypeError: charset is undefined" in pageshow listener, as document is null) [browser_bug581947.js] [browser_bug585558.js] -skip-if = e10s # Bug 921905 - pinTab/unpinTab fail in e10s [browser_bug585785.js] [browser_bug585830.js] [browser_bug590206.js] [browser_bug592338.js] skip-if = e10s # Bug 653065 - Make the lightweight theme web installer ready for e10s [browser_bug594131.js] -skip-if = e10s # Bug 921905 - pinTab/unpinTab fail in e10s [browser_bug595507.js] skip-if = e10s # Bug 691601 - no form submit observers [browser_bug596687.js] [browser_bug597218.js] -skip-if = e10s # Bug 921905 - pinTab/unpinTab fail in e10s [browser_bug609700.js] skip-if = e10s # Bug 516755 - SessionStore disabled for e10s (calls duplicateTabIn, which uses SessionStore) [browser_bug623155.js] skip-if = e10s # Bug ?????? - URLBar issues (apparently issues with redirection) [browser_bug623893.js] skip-if = e10s # Bug 916974 - Session history doesn't work in e10s [browser_bug624734.js] [browser_bug633691.js] @@ -331,41 +324,38 @@ skip-if = e10s # Bug 921952 - Content:Cl skip-if = e10s # Bug ?????? - test directly manipulates content (TypeError: gBrowser.docShell is null) [browser_mixedcontent_securityflags.js] skip-if = e10s # Bug ?????? - test directly manipulates content ("cannot ipc non-cpow object") [browser_notification_tab_switching.js] skip-if = buildapp == 'mulet' || e10s # Bug ?????? - uncaught exception - Error: cannot ipc non-cpow object at chrome://mochitests/content/browser/browser/base/content/test/general/browser_notification_tab_switching.js:32 [browser_offlineQuotaNotification.js] skip-if = buildapp == 'mulet' || e10s # Bug ?????? - test directly manipulates content (gBrowser.selectedBrowser.contentWindow.applicationCache.oncached = function() {...}) [browser_overflowScroll.js] -skip-if = e10s # Bug 921905 - pinTab/unpinTab fail in e10s [browser_pageInfo.js] skip-if = buildapp == 'mulet' || e10s # Bug 866413 - PageInfo doesn't work in e10s [browser_page_style_menu.js] skip-if = e10s # Bug ?????? - test directly manipulates content [browser_parsable_css.js] [browser_parsable_script.js] skip-if = debug || asan # Times out on debug/asan, and we are less picky about our JS there [browser_pinnedTabs.js] -skip-if = e10s # Bug 921905 - pinTab/unpinTab fail in e10s [browser_plainTextLinks.js] skip-if = e10s # Bug ?????? - test directly manipulates content (creates and fetches elements directly from content document) [browser_popupUI.js] skip-if = buildapp == 'mulet' || e10s # Bug ?????? - test directly manipulates content (tries to get a popup element directly from content) [browser_printpreview.js] skip-if = buildapp == 'mulet' || e10s # Bug ?????? - timeout after logging "Error: Channel closing: too late to send/recv, messages will be lost" [browser_private_browsing_window.js] skip-if = buildapp == 'mulet' [browser_private_no_prompt.js] skip-if = buildapp == 'mulet' [browser_relatedTabs.js] [browser_removeTabsToTheEnd.js] -skip-if = e10s # Bug 921905 - pinTab/unpinTab fail in e10s [browser_removeUnsafeProtocolsFromURLBarPaste.js] [browser_sanitize-download-history.js] skip-if = true # bug 432425 [browser_sanitize-passwordDisabledHosts.js] [browser_sanitize-sitepermissions.js] [browser_sanitize-timespans.js] skip-if = buildapp == 'mulet' [browser_sanitizeDialog.js] @@ -433,23 +423,20 @@ skip-if = e10s # Bug ????? - test calls [browser_urlbarTrimURLs.js] [browser_urlbar_search_healthreport.js] skip-if = e10s # Bug ?????? - FHR tests failing (either with "no data for today" or "2 records for today") [browser_utilityOverlay.js] [browser_visibleFindSelection.js] skip-if = e10s # Bug ?????? - test directly manipulates content [browser_visibleLabel.js] [browser_visibleTabs.js] -skip-if = e10s # Bug 921905 - pinTab/unpinTab fail in e10s [browser_visibleTabs_bookmarkAllPages.js] skip-if = true # Bug 1005420 - fails intermittently. also with e10s enabled: bizarre problem with hidden tab having _mouseenter called, via _setPositionalAttributes, and tab not being found resulting in 'candidate is undefined' [browser_visibleTabs_bookmarkAllTabs.js] -skip-if = e10s # Bug 921905 - pinTab/unpinTab fail in e10s [browser_visibleTabs_contextMenu.js] -skip-if = e10s # Bug 921905 - pinTab/unpinTab fail in e10s [browser_visibleTabs_tabPreview.js] skip-if = (os == "win" && !debug) || e10s # Bug 1007418 / Bug 698371 - thumbnail captures need e10s love (tabPreviews_capture fails with Argument 1 of CanvasRenderingContext2D.drawWindow does not implement interface Window.) [browser_web_channel.js] [browser_windowopen_reflows.js] skip-if = buildapp == 'mulet' [browser_wyciwyg_urlbarCopying.js] skip-if = e10s # Bug ?????? - test directly manipulates content (content.document.getElementById) [browser_zbug569342.js]
--- a/browser/base/content/test/general/browser_bug575561.js +++ b/browser/base/content/test/general/browser_bug575561.js @@ -38,36 +38,28 @@ function test() { }); } function testLink(aLinkIndex, pinTab, expectNewTab, nextTest, testSubFrame) { let appTab = gBrowser.addTab("http://example.com/browser/browser/base/content/test/general/app_bug575561.html", {skipAnimation: true}); if (pinTab) gBrowser.pinTab(appTab); gBrowser.selectedTab = appTab; - appTab.linkedBrowser.addEventListener("load", onLoad, true); - let loadCount = 0; - function onLoad() { - loadCount++; - if (loadCount < 2) - return; - - appTab.linkedBrowser.removeEventListener("load", onLoad, true); - + waitForDocLoadComplete(appTab.linkedBrowser).then(function() { let browser = gBrowser.getBrowserForTab(appTab); if (testSubFrame) browser = browser.contentDocument.getElementsByTagName("iframe")[0]; let links = browser.contentDocument.getElementsByTagName("a"); if (expectNewTab) gBrowser.tabContainer.addEventListener("TabOpen", onTabOpen, true); else - browser.addEventListener("load", onPageLoad, true); + waitForDocLoadComplete(appTab.linkedBrowser).then(onPageLoad); info("Clicking " + links[aLinkIndex].textContent); EventUtils.sendMouseEvent({type:"click"}, links[aLinkIndex], browser.contentWindow); let linkLocation = links[aLinkIndex].href; function onPageLoad() { browser.removeEventListener("load", onPageLoad, true); is(browser.contentDocument.location.href, linkLocation, "Link should not open in a new tab"); @@ -75,16 +67,18 @@ function testLink(aLinkIndex, pinTab, ex gBrowser.removeTab(appTab); nextTest(); }); } function onTabOpen(event) { gBrowser.tabContainer.removeEventListener("TabOpen", onTabOpen, true); ok(true, "Link should open a new tab"); - executeSoon(function(){ - gBrowser.removeTab(appTab); - gBrowser.removeCurrentTab(); - nextTest(); + waitForDocLoadComplete(event.target.linkedBrowser).then(function() { + executeSoon(function(){ + gBrowser.removeTab(appTab); + gBrowser.removeCurrentTab(); + nextTest(); + }); }); } - } + }); }
--- a/browser/base/content/test/general/head.js +++ b/browser/base/content/test/general/head.js @@ -412,16 +412,41 @@ function waitForDocLoadAndStopIt(aExpect } }, }; aBrowser.addProgressListener(progressListener); info("waitForDocLoadAndStopIt: Waiting for URL: " + aExpectedURL); return deferred.promise; } +/** + * Waits for the next load to complete in the current browser. + * + * @return promise + */ +function waitForDocLoadComplete(aBrowser=gBrowser) { + let deferred = Promise.defer(); + let progressListener = { + onStateChange: function (webProgress, req, flags, status) { + let docStart = Ci.nsIWebProgressListener.STATE_IS_NETWORK | + Ci.nsIWebProgressListener.STATE_STOP; + if ((flags & docStart) == docStart) { + aBrowser.removeProgressListener(progressListener); + info("Browser loaded"); + deferred.resolve(); + } + }, + QueryInterface: XPCOMUtils.generateQI([Ci.nsIWebProgressListener, + Ci.nsISupportsWeakReference]) + }; + aBrowser.addProgressListener(progressListener); + info("Waiting for browser load"); + return deferred.promise; +} + let FullZoomHelper = { selectTabAndWaitForLocationChange: function selectTabAndWaitForLocationChange(tab) { if (!tab) throw new Error("tab must be given."); if (gBrowser.selectedTab == tab) return Promise.resolve(); gBrowser.selectedTab = tab;
--- a/dom/interfaces/base/nsITabChild.idl +++ b/dom/interfaces/base/nsITabChild.idl @@ -1,16 +1,19 @@ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #include "domstubs.idl" interface nsIContentFrameMessageManager; +interface nsIWebBrowserChrome3; [scriptable, uuid(2eb3bc54-78bf-40f2-b301-a5b5b70f7da0)] interface nsITabChild : nsISupports { readonly attribute nsIContentFrameMessageManager messageManager; + attribute nsIWebBrowserChrome3 webBrowserChrome; + [notxpcom] void sendRequestFocus(in boolean canFocus); };
--- a/dom/ipc/TabChild.cpp +++ b/dom/ipc/TabChild.cpp @@ -75,16 +75,17 @@ #include "nsViewportInfo.h" #include "JavaScriptChild.h" #include "nsILoadContext.h" #include "ipc/nsGUIEventIPC.h" #include "mozilla/gfx/Matrix.h" #include "UnitTransforms.h" #include "ClientLayerManager.h" #include "LayersLogging.h" +#include "nsIWebBrowserChrome3.h" #include "nsColorPickerProxy.h" #define BROWSER_ELEMENT_CHILD_SCRIPT \ NS_LITERAL_STRING("chrome://global/content/BrowserElementChild.js") #define TABC_LOG(...) // #define TABC_LOG(...) printf_stderr("TABC: " __VA_ARGS__) @@ -200,22 +201,24 @@ TabChildBase::~TabChildBase() } NS_IMPL_CYCLE_COLLECTION_CLASS(TabChildBase) NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(TabChildBase) NS_IMPL_CYCLE_COLLECTION_UNLINK(mTabChildGlobal) NS_IMPL_CYCLE_COLLECTION_UNLINK(mGlobal) NS_IMPL_CYCLE_COLLECTION_UNLINK(mAnonymousGlobalScopes) + NS_IMPL_CYCLE_COLLECTION_UNLINK(mWebBrowserChrome) NS_IMPL_CYCLE_COLLECTION_UNLINK_END NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(TabChildBase) NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mTabChildGlobal) NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mGlobal) NS_IMPL_CYCLE_COLLECTION_TRAVERSE_SCRIPT_OBJECTS + NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mWebBrowserChrome) NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN(TabChildBase) for (uint32_t i = 0; i < tmp->mAnonymousGlobalScopes.Length(); ++i) { NS_IMPL_CYCLE_COLLECTION_TRACE_JS_MEMBER_CALLBACK(mAnonymousGlobalScopes[i]) } NS_IMPL_CYCLE_COLLECTION_TRACE_END @@ -1309,16 +1312,21 @@ TabChild::FocusPrevElement() { SendMoveFocus(false); return NS_OK; } NS_IMETHODIMP TabChild::GetInterface(const nsIID & aIID, void **aSink) { + if (aIID.Equals(NS_GET_IID(nsIWebBrowserChrome3))) { + NS_IF_ADDREF(((nsISupports *) (*aSink = mWebBrowserChrome))); + return NS_OK; + } + // XXXbz should we restrict the set of interfaces we hand out here? // See bug 537429 return QueryInterface(aIID, aSink); } NS_IMETHODIMP TabChild::ProvideWindow(nsIDOMWindow* aParent, uint32_t aChromeFlags, bool aCalledFromJS, @@ -2835,16 +2843,30 @@ TabChild::GetMessageManager(nsIContentFr if (mTabChildGlobal) { NS_ADDREF(*aResult = mTabChildGlobal); return NS_OK; } *aResult = nullptr; return NS_ERROR_FAILURE; } +NS_IMETHODIMP +TabChild::GetWebBrowserChrome(nsIWebBrowserChrome3** aWebBrowserChrome) +{ + NS_IF_ADDREF(*aWebBrowserChrome = mWebBrowserChrome); + return NS_OK; +} + +NS_IMETHODIMP +TabChild::SetWebBrowserChrome(nsIWebBrowserChrome3* aWebBrowserChrome) +{ + mWebBrowserChrome = aWebBrowserChrome; + return NS_OK; +} + void TabChild::SendRequestFocus(bool aCanFocus) { PBrowserChild::SendRequestFocus(aCanFocus); } PIndexedDBChild* TabChild::AllocPIndexedDBChild(
--- a/dom/ipc/TabChild.h +++ b/dom/ipc/TabChild.h @@ -28,16 +28,17 @@ #include "nsITabChild.h" #include "nsITooltipListener.h" #include "mozilla/Attributes.h" #include "mozilla/dom/TabContext.h" #include "mozilla/DOMEventTargetHelper.h" #include "mozilla/EventDispatcher.h" #include "mozilla/EventForwards.h" #include "mozilla/layers/CompositorTypes.h" +#include "nsIWebBrowserChrome3.h" class nsICachedFileDescriptorListener; class nsIDOMWindowUtils; namespace mozilla { namespace layout { class RenderFrameChild; } @@ -219,16 +220,17 @@ protected: protected: CSSSize mOldViewportSize; bool mContentDocumentIsDisplayed; nsRefPtr<TabChildGlobal> mTabChildGlobal; ScreenIntSize mInnerSize; mozilla::layers::FrameMetrics mLastRootMetrics; mozilla::layout::ScrollingBehavior mScrolling; + nsCOMPtr<nsIWebBrowserChrome3> mWebBrowserChrome; }; class TabChild MOZ_FINAL : public TabChildBase, public PBrowserChild, public nsIWebBrowserChrome2, public nsIEmbeddingSiteWindow, public nsIWebBrowserChromeFocus, public nsIInterfaceRequestor,
--- a/testing/mochitest/tests/SimpleTest/EventUtils.js +++ b/testing/mochitest/tests/SimpleTest/EventUtils.js @@ -49,17 +49,17 @@ function sendMouseEvent(aEvent, aTarget, if (['click', 'contextmenu', 'dblclick', 'mousedown', 'mouseup', 'mouseover', 'mouseout'].indexOf(aEvent.type) == -1) { throw new Error("sendMouseEvent doesn't know about event type '" + aEvent.type + "'"); } if (!aWindow) { aWindow = window; } - if (!(aTarget instanceof aWindow.Element)) { + if (typeof aTarget == "string") { aTarget = aWindow.document.getElementById(aTarget); } var event = aWindow.document.createEvent('MouseEvent'); var typeArg = aEvent.type; var canBubbleArg = true; var cancelableArg = true; @@ -969,18 +969,18 @@ function synthesizeText(aEvent, aWindow) compositionString.dispatchEvent(); } // Must be synchronized with nsIDOMWindowUtils. const QUERY_CONTENT_FLAG_USE_NATIVE_LINE_BREAK = 0x0000; const QUERY_CONTENT_FLAG_USE_XP_LINE_BREAK = 0x0001; -const SELECTION_SET_FLAG_USE_NATIVE_LINE_BREAK = 0x0000; -const SELECTION_SET_FLAG_USE_XP_LINE_BREAK = 0x0001; +const SELECTION_SET_FLAG_USE_NATIVE_LINE_BREAK = 0x0000; +const SELECTION_SET_FLAG_USE_XP_LINE_BREAK = 0x0001; const SELECTION_SET_FLAG_REVERSE = 0x0002; /** * Synthesize a query selected text event. * * @param aWindow Optional (If null, current |window| will be used) * @return An nsIQueryContentEventResult object. If this failed, * the result might be null.
--- a/toolkit/modules/BrowserUtils.jsm +++ b/toolkit/modules/BrowserUtils.jsm @@ -143,9 +143,40 @@ this.BrowserUtils = { } let win = null; if (element == aElement) win = aTopLevelWindow; else win = element.contentDocument.defaultView; return { targetWindow: win, offsetX: offsetX, offsetY: offsetY }; }, + + onBeforeLinkTraversal: function(originalTarget, linkURI, linkNode, isAppTab) { + // Don't modify non-default targets or targets that aren't in top-level app + // tab docshells (isAppTab will be false for app tab subframes). + if (originalTarget != "" || !isAppTab) + return originalTarget; + + // External links from within app tabs should always open in new tabs + // instead of replacing the app tab's page (Bug 575561) + let linkHost; + let docHost; + try { + linkHost = linkURI.host; + docHost = linkNode.ownerDocument.documentURIObject.host; + } catch(e) { + // nsIURI.host can throw for non-nsStandardURL nsIURIs. + // If we fail to get either host, just return originalTarget. + return originalTarget; + } + + if (docHost == linkHost) + return originalTarget; + + // Special case: ignore "www" prefix if it is part of host string + let [longHost, shortHost] = + linkHost.length > docHost.length ? [linkHost, docHost] : [docHost, linkHost]; + if (longHost == "www." + shortHost) + return originalTarget; + + return "_blank"; + }, };