javascriptdomgreasemonkeydom-eventshtml-frames

HTML frame's onload is called before the content is loaded


I am writing a simple Greasemonkey script for Java SE API reference doc [http://docs.oracle.com/javase/8/docs/api/ ]. It goes as:

// ==UserScript==
// @id          Test
// @grant       none
// @include     http://docs.oracle.com/javase/8/docs/api/*
// @version     1
// @run-at      docuitment-end
// ==UserScript==


var classNamesFrame = null;
var classNamesDoc = null;
var classNamesATags = null;
var classNames = null;

function printClassNames()
{
  classNamesATags = classNamesDoc.getElementsByTagName('a');
  classNames = new Array();
  var i;
  for (i = 0; i < classNamesATags.length; i++) {
    classNames.push(classNamesATags[i].textContent);
  }
  console.log(classNames);
  console.log(classNamesDoc.URL);
  console.log('Total number of classes: ' + classNamesATags.length);
  alert("printClassNames called");
}


classNamesFrame = document.getElementsByName('packageFrame') [0];
classNamesDoc = classNamesFrame.contentDocument;
classNamesFrame.onload = printClassNames;
//classNamesFrame.addEventListener("DOMContentLoaded", printClassNames, false);

Function printClassNames() prints names of all classes it finds in the frame where all classes are listed. I should do so when the frame has finished loading. But the onload even is called before HTML document for the frame is loaded.

I have tried using DOMContentLoaded event but it is not even called.

What can I do so that printClassNames is called after the frame has finished loading completely?


Solution

  • That script has a variety of errors (list below), but the main one is that it's grabbing the wrong contentDocument.

    This is because Firefox returns <about:blank> for frame contents until it is replaced by the actual page contents. The classNamesDoc variable remains pointed at the blank value. (Note that Chrome handles frames slightly differently and updates classNamesDoc for you.)

    So, move classNamesDoc = classNamesFrame.contentDocument; to inside printClassNames() and the most obvious problem is solved.

    Other problems, "worstest firstest":

    Putting it all together, your script would be:

    // ==UserScript==
    // @name        Test
    // @grant       none
    // @include     http://docs.oracle.com/javase/8/docs/api/*
    // @version     1
    // ==/UserScript==
    
    var classNamesFrame = null;
    var classNamesDoc = null;
    var classNamesATags = null;
    var classNames = null;
    
    function printClassNames()
    {
      classNamesDoc = classNamesFrame.contentDocument;
      classNamesATags = classNamesDoc.getElementsByTagName('a');
      classNames = new Array();
      var i;
      for (i = 0; i < classNamesATags.length; i++) {
        classNames.push(classNamesATags[i].textContent);
      }
      console.log(classNames);
      console.log(classNamesDoc.URL);
      console.log('Total number of classes: ' + classNamesATags.length);
      console.log("printClassNames called");
    }
    
    classNamesFrame = document.getElementsByName('packageFrame') [0];
    if (classNamesFrame) {
        classNamesFrame.onload = printClassNames;
    }
    

    -- which works on Both Firefox and Chrome (and probably others).