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?
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":
Badly malformed metadata block. Incorrect // ==/UserScript==
line. This causes the script to run (and crash) for every page and (i)frame you browse!
Script silently crashes (on Firefox, Chrome reports these errors) for every page/frame but one small subset. You need to check the value of classNamesFrame
before using it.
For example, on the docs.oracle.com/javase/8/docs/api/
pages, this script is running 4 times and silently crashing on three of those.
Missing @name
directive. This can cause scoping, updating, and maintenance problems -- as well as hamper uploading and sharing the script.
Syntax error. It should be: @run-at document-end
, except that you probably do not need this directive at all, in this case.
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).