1

I'm creating a Google Chrome extension that adds some extra functionality to Gmail by injecting a script that I've written. By 'injected script' please see this definition.

To do this, my content script matches on ["https://mail.google.com/mail/*"].

However, the problem with this is that this is the same URL for when Gmail is loading and has finished loading. As a result, my script appears to sometimes to get injected too early, while Gmail is still loading, leading to reference errors.

To try to circumvent this problem, I'm only running my script on load by doing: window.addEventListener("load", runInjectedScript);

And in my content script (which does the injecting), it only injects when this conditional is true: if (window.self === window.top).

Yet, these measures do not seem to guarantee that my script will always get injected at the right time, once Gmail has finished loading and the inbox appears. How can I ensure that this happens? Are there any techniques that I haven't implemented?

Community
  • 1
  • 1
user5508297
  • 805
  • 2
  • 9
  • 24
  • Are you trying to utilise a specific function within gmails JS? As you could do a setTimeout checking to see if the variable has been defined yet. – Dave Aug 10 '16 at 11:10
  • I think @Dave was suggesting a function with a setTimeout that calls itself again, if the page is not loaded. Simply have it check every _n_ milliseconds and either run itself again, or run a callback if the page is loaded. – Reinstate Monica Cellio Aug 10 '16 at 11:15
  • @user5508297 you're correct. Or you can use a setInterval and clear the interval once the requirements have been met. I'll write the code as an answer – Dave Aug 10 '16 at 11:51

3 Answers3

1

To ensure injecting scripts when "inbox appears", take a look at MutationObserver, which provides a way to react to changes in the DOM, in particular for observing the input being inserted

Community
  • 1
  • 1
Haibara Ai
  • 10,703
  • 2
  • 31
  • 47
1

I inspected the gmail page and once the inbox loads they add style="display: none" to the #loading element.

You could do some polling for that to change and then bootstrap your app.

function onInboxLoaded(cb) {
  var pollInterval = setInterval(function() {
    var elem = document.getElementById('loading');
    if (elem && elem.style.display === 'none') {
      clearInterval(pollInterval);

      cb();
    }
  }, 100);
}

onInboxLoaded(function(){
  // bootstrap app
})
Joe
  • 2,596
  • 2
  • 14
  • 11
0

You could potentially run a setInterval checking to see if the data you're intercepting in Gmail is available yet.

var gmailLoaded = setInterval(function () {
    if (typeof GMAIL !== 'undefined') {
        runInjectedScript();
        clearInterval(gmailLoaded);
    }
}, 100);

You'll need to replace GMAIL with whatever you're trying to reference from Gmail. You could also use the same approach above checking to see if the loading state is active, however that may add additional overhead.

Dave
  • 193
  • 2
  • 13