6

Is there a clean way for a Google Chrome extension to set a non-local webpage as the new tab page while also keeping the omnibox cleared or highlighted?

The chrome_url_overrides.newtab option in the extension manifest only allows local HTML pages.

Right now, I see two options:

  1. iframe the webpage in the local extension page. However, many websites won't work properly when iframed.
  2. Redirect the local new tab page to the webpage. However, this does not reliably highlight the omnibox, so users have to manually set focus to the omnibox before typing, which is a poor user experience.

The ideal solution would keep the webpage be the top frame of the new tab page, and the omnibox would be either cleared or highlighted.

Additional info:

  • There's an ongoing, unsolved thread on this topic here for the Chrome extension New Tab Redirect.
  • Using chrome.tabs.update to redirect the new tab page has historically highlighted the URL. However, this appears to be undocumented and unreliable. The highlighting broke in Chrome 34 and appears to be broken now in Chrome 61 (a bug I just reported).
Kevin
  • 682
  • 1
  • 9
  • 18
  • You can force sites to work in an iframe by [stripping X-Frame-Options](https://stackoverflow.com/a/15534822) header + inject a content script into the iframe that spoofs `window.parent` and `window.top` via Object.defineProperties to point to `window` – wOxxOm Sep 18 '17 at 08:32
  • I don't think the `window` modification would work. Content scripts cannot "use variables or functions defined by web pages or by other content scripts" https://developer.chrome.com/extensions/content_scripts – Kevin Sep 18 '17 at 19:17
  • You can simply [Insert code into the page context using a content script](//stackoverflow.com/a/9517879) – wOxxOm Sep 18 '17 at 19:17
  • Sure, but `window.top` and `window.parent` are read-only. This solution is ok if you own the website you're iframing (I actually currently do this for an extension) but it isn't easily generalizable. – Kevin Sep 18 '17 at 19:52
  • 1
    Are you sure that `Object.defineProperty` works? The `top` property is non-configurable, which you can verify in the dev console with: `Object.getOwnPropertyDescriptor(window, 'top')`. The w3 spec has the properties as "unforgeable": https://www.w3.org/TR/html5/browsers.html#the-window-object If you try `Object.defineProperty(window, 'top', {get: function() { return 'foo' }})`, you will see: `Cannot redefine property: top`. – Kevin Sep 18 '17 at 20:17
  • Oh, I see. I've only tried redefining `parent`, which works. – wOxxOm Sep 18 '17 at 20:33
  • @wOxxOm, @ Kevin. I need to override `top`. Any ideas how it can be done? Q here: https://stackoverflow.com/q/46794470/632951 – Pacerier Oct 17 '17 at 16:10
  • @Pacerier I believe it's impossible. – Kevin Oct 20 '17 at 22:02

1 Answers1

5

Right now, this isn't quite possible. I've opened a feature request for Chrome extensions to better support this use case.

The two options in the meantime are:

  1. On the local extension new tab page, create an iframe to the webpage.

  2. In an extension background script, listen for new tab creation and update the URL to a website. This looks something like:

    // background.js
    
    // Listen for new tabs.
    chrome.tabs.onCreated.addListener(function (tab) {
    
      // Only redirect if this is a blank new tab (not opened by clicking a link).
      if (tab.url === 'chrome://newtab/') {
    
        // Show your website. This might highlight the omnibox,
        // but it's not guaranteed.
        chrome.tabs.update(tab.id, {url:'https://example.com'});
      }
    });
    

    As noted in the question, this has unreliably highlighted the URL in the past. The URL highlighting is broken as of now (Chrome stable v61) but should be fixed in v62.

Kevin
  • 682
  • 1
  • 9
  • 18
  • 1
    This almost worked for me, but the issue for me was that tab.url was not defined at the stage when the listener fired. For me, it was the key "pendingUrl" that I had to listen to instead of tab.url. So it might help some people to change the if to: `if (tab.pendingUrl === 'chrome://newtab/' || tab.url === 'chrome://newtab/')` instead! – Sandmountain Feb 27 '22 at 15:02