I'm creating a Greasemonkey script to automate the setting of some options in our online ticketing system in an attempt to make logging calls a bit more efficient.
Anyway, the screen for logging calls is comprised of multiple frames, only one is of interest to me with regard to automation. The stripped down HTML for the page and the frame(including the element I'm trying to edit) appear as follows:
<html>
<head>
</head>
<frameset framespacing="0" border="0" bordercolor="#ffffff" rows="130,*,22,0">
<frame scrolling="no" marginwidth="0" marginheight="0" leftmargin="0" topmargin="0" noresize="" src="top.asp?menu=&page=" name="menu">
</frame>
<frameset id="contentCols" framespacing="8" border="8" cols="250, *" bordercolor="#ffffff">
<frame marginwidth="0" marginheight="0" leftmargin="0" topmargin="0" border="0" src="../service/loading.html" name="content" frameborder="0" style="padding-right: 10px;">
<html>
<head>
</head>
<body class="winBack" style="background-color: rgb(255, 255, 255);">
<div id="scrollableContainer" class="lockedTableContainer scrollableContainerHeight" style="position: relative; height: 0px;">
<table cellspacing="1" cellpadding="3" border="0">
<form id="configFields" name="configFields" method="post" action="/ics/tt/ticketNew.asp"></form>
<input type="hidden" value="" name="task">
<input type="hidden" value="account" name="source">
<tbody>
<tr id="ROW_109094">
<td class="webCaption" style="width: 160px;">
</td>
<td class="formText">
<select id="FIELD_109094_DROPDOWN_null" class="formText" style="width: 200px;" title="Establishment Type" name="FIELD_109094_DROPDOWN_null" onchange="updateDep(109094, this.options[this.selectedIndex].value);">
</select>
</td>
</tr>
</tbody>
<table>
</div>
</frame>
</frameset>
</frameset>
</html>
What I am trying to do is set the selectedIndex
of the FIELD_109094_DROPDOWN_null
select element.
Then, I am trying to run the updateDep
function(which is contained in a script attached to the frame) that is attached to the element's change event; this function shows certain other fields depending on the value currently set in the select element.
Using Firebug's console I can achieve this using the following two lines:
frames["content"].document.getElementById("FIELD_109094_DROPDOWN_null").selectedIndex = 2;
frames["content"].updateDep(109094, frames["content"].document.getElementById("FIELD_109094_DROPDOWN_null").options[2].value);
However, when I put this into a Greasemonkey script, and attach it to either the main window onload, or the frame's onload; I get this error:
Error: frames.content.document.getElementById("FIELD_109094_DROPDOWN_null") is null
If I use, the following code however, I can at least change the select element's selected index:
document.getElementById("FIELD_109094_DROPDOWN_null").selectedIndex = 2;
I cannot figure out how to run the updateDep
function through the Greasemonkey script. The code in the script appears as follows:
// ==/UserScript==
var initElements = (function () {
var elementExists = document.getElementById("FIELD_109094_DROPDOWN_null");
if(elementExists)
{
document.getElementById("FIELD_109094_DROPDOWN_null").selectedIndex = 2;
frames["content"].updateDep(109094, frames["content"].document.getElementById("FIELD_109094_DROPDOWN_null").options[2].value);
}
}
)();
window.addEventListener('load', initElements, false);
Any help would be greatly appreciated.
The trick with frames and iFrames is that they each look like a separate page to Greasemonkey.
So, for the HTML in the question, the GM script could end up running 3 separate times, depending on how the @include
, @exclude
, and/or @match
directives were configured.
So, the same element will appear differently (or not at all) depending on which run the script is cycling through. So, don't use code like frames["content"]
unless you are precisely aware/controlling the script's executing state. It's better to test for nodes and run code conditionally.
The other thing is that when using javascript that resides on the target page, you need to use unsafeWindow
or a workaround.
Putting it all together, code like so should work:
var depSelect = document.querySelector ("#FIELD_109094_DROPDOWN_null");
if (depSelect) {
depSelect.selectedIndex = 2;
unsafeWindow.updateDep (109094, depSelect.options[2].value);
}
(assuming no funny business with the @include
, @exclude
, and/or @match
directives.)
You should not need the window.addEventListener('load'...
stuff, nor to wrap the code in initElements()
.