Fix loading bug in waitForBodyLoaded.js.

Page loading normally happens in two phases: first DOMContentLoaded is fired, and readyState goes to interactive, second the normal document/window.load is fired and readyState goes to complete.

isBodyLoaded.js verifies loading state by checking if readyState is complete. However, waitForBodyLoaded.js listens for DOMContentLoaded. So when that event is fired, the ready state is not there yet, thus this event handler is useless.

(GWT has a fallback mechanism, a 50ms interval timer. That works, but it causes an unnecessary latency. Also, I'm working on a project where raw JS scripts are loaded next to GWT and they assume GWT is loaded when window.load is fired. But because of this bug, this doesn't work, causing hacky workarounds.)

Repro here: https://jsfiddle.net/wxawpadr/1/ . This is mostly a copy of GWT's scripts and logs what's happening to the console. This shows that the callback is triggered by the timer, not the event.

The fix is really simple: if isBodyLoaded.js wants a complete readyState, then we listen for the readystatechange event. Also there's a minor code cleanup relating to that, because we don't want to fire when readyState goes to interactive.

Change-Id: I7c9f1c89bd12916549581ffe8bbc522c09f56b50
Review-Link: https://gwt-review.googlesource.com/#/c/16960/
diff --git a/dev/core/src/com/google/gwt/core/ext/linker/impl/waitForBodyLoaded.js b/dev/core/src/com/google/gwt/core/ext/linker/impl/waitForBodyLoaded.js
index 4d4c33f..91cf0dc 100644
--- a/dev/core/src/com/google/gwt/core/ext/linker/impl/waitForBodyLoaded.js
+++ b/dev/core/src/com/google/gwt/core/ext/linker/impl/waitForBodyLoaded.js
@@ -13,13 +13,17 @@
 
   // If the page is not already loaded, setup some listeners and timers to
   // detect when it is done.
-  function onBodyDone() {
+  function checkBodyDone() {
     if (!bodyDone) {
+      if (!isBodyLoaded()) {
+        return;
+      }
+
       bodyDone = true;
       callback();
 
       if ($doc.removeEventListener) {
-        $doc.removeEventListener("DOMContentLoaded", onBodyDone, false);
+        $doc.removeEventListener("readystatechange", checkBodyDone, false);
       }
       if (onBodyDoneTimerId) {
         clearInterval(onBodyDoneTimerId);
@@ -27,15 +31,13 @@
     }
   }
 
-  // For everyone that supports DOMContentLoaded.
+  // For everyone that supports readystatechange.
   if ($doc.addEventListener) {
-    $doc.addEventListener("DOMContentLoaded", onBodyDone, false);
+    $doc.addEventListener("readystatechange", checkBodyDone, false);
   }
 
   // Fallback. If onBodyDone() gets fired twice, it's not a big deal.
   var onBodyDoneTimerId = setInterval(function() {
-    if (isBodyLoaded()) {
-      onBodyDone();
-    }
-  }, 50);
+    checkBodyDone();
+  }, 10);
 }