Can I fire onchange() event in GM script?

2,472 views
Skip to first unread message

matej

unread,
Nov 30, 2007, 10:25:28 AM11/30/07
to greasemonkey-users
Hi,

trying to massage a page from the Red Hat bugzilla with GM (example of
the page is on http://mcepl.fedorapeople.org/tmp/show_bug.html -- it
is from inside of the bugzilla with proper bits for RH employees, so
not the same what you get from outside). The problem I have is how set
NEEDINFO state of the bug. In the HTML page the element with NEEDINFO
switch is this:

<input id="knob-changestatus" type="radio" name="knob"
value="changestatus"
onchange="toggleNeedinfo(document.changeform);">
<label for="knob-changestatus">Change status to</label>
<select name="newstatus"
onchange="document.changeform.knob[1].checked=true;
toggleNeedinfo(document.changeform); ">
<option value="assigned" title="Accept bug">ASSIGNED</
option>
<option value="needinfo" title="Report needs more
information">NEEDINFO</option>
<option value="modified" title="Fix waiting for
confirmation">MODIFIED</option>
<option value="on_dev" title="Undergoing integration
testing in dev">ON_DEV</option>
<option value="on_qa" title="Undergoing full testing by
QA">ON_QA</option>
<option value="verified" title="QA testing is
complete">VERIFIED</option>
<option value="fails_qa" title="Fails QA
testing">FAILS_QA</option>
<option value="release_pending" title="Fix has been
approved by QA and is ready for beta">RELEASE_PENDING</option>
<option value="post" title="A transient state between
ASSIGNED and MODIFIED">POST</option>
</select>

<div id="needinfo" style="display:none;">
<script type="text/javascript" language="JavaScript">
document.write('from <select id="requestee_actor-16"
name="requestee_actor-16"
onchange="updateNeedinfoForm(document.changeform);">');
document.write('<option value="" selected>Other</option>');
document.write('<option value="krh&#64;redhat.com" >Assignee</
option>');
document.write('<option value="kyrsjo&#64;solution-forge.net"
>Reporter</option>');
document.write('<option value="extras-
qa&#64;fedoraproject.org" >QA Contact</option>');
document.write('</select> ');
document.write('<input type="text" size="20" maxlength="255"
id="requestee_type-16" name="requestee_type-16" value="">');
document.write('<input type="hidden" id="flag_type-16"
name="flag_type-16" value="X"/>');
</script>
</div>

<br/>

.... and following elements in the form ...

The problem I have is that after <input id="knob-changestatus"> is
changed onchange even should be fired. So I tried running
unsafeWindow.toggleNeedinfo(document.changeform) but it didn't change
things a bit. So, now my question is, would it be possible to
run .onchange() method directly. Something like this:

function needinfoHandler(evt) {
/** set bug to NEEDINFO reporter.
*/
var sel = document.forms[1].elements.namedItem("newstatus");
var statesList = [];
var state = "";

for (var i=0; i < sel.length; i++) {
state = sel[i].getAttribute("value");
state = state.replace(/\s*(.*)\s*/,"$1");
statesList[statesList.length] = state;
}
var stateIndex = statesList.indexOf("needinfo");
var selectedState = sel.getElementsByTagName("option")
[stateIndex];

document.getElementById("knob-leave").checked = false;
document.getElementById("knob-changestatus").checked = true;
// THIS IS THE PROBLEM !!!!
unsafeWindow.document.getElementById("knob-
changestatus").onchange()
selectedState.selected = true;

var newOptions = document.getElementById("requestee_actor-16");
var newOptionList = newOptions.getElementsByTagName("option");

var newOptionReporter = pickElement(newOptionList,
function(elem) {
return elem.innerHTML.test(/Reporter/);
});
return("");
}

Could anybody help me to resolve this, please?

Patrick Wiseman

unread,
Nov 30, 2007, 10:38:57 AM11/30/07
to greasemon...@googlegroups.com

You'd have to use something like
document.getElementById(whatever).addEventListener('change', callfunc,
false), I believe.

Patrick

matej

unread,
Nov 30, 2007, 10:49:51 AM11/30/07
to greasemonkey-users
On Nov 30, 4:38 pm, "Patrick Wiseman" <pwise...@gmail.com> wrote:
> You'd have to use something like
> document.getElementById(whatever).addEventListener('change', callfunc,
> false), I believe.

I am not sure I get this -- there is already onchange= in the original
HTML

> <input id="knob-changestatus" type="radio" name="knob"
> value="changestatus"
> onchange="toggleNeedinfo(document.changeform);">

Wouldn't it break somehow if there were two onchange-listeners on
element running the same script? And could I use
unsafeWindow.toggleNeedinfo in my listener?

Matěj

RodMcguire

unread,
Nov 30, 2007, 2:42:07 PM11/30/07
to greasemonkey-users
The wiki contains a section on how to invoke an "onclick" handler
without using unsafeWindow. You could do the same to invoke your
"onchange" handler.

http://wiki.greasespot.net/Location_hack#Invoke_onclick_behavior

If you want to go through unsafWindow you need to make sure
everything is unwrapped. Instead of

unsafeWindow.toggleNeedinfo(document.changeform)

you need something like

unsafeWindow.toggleNeedinfo(unsafeWindow.document.changeform)

> Wouldn't it break somehow if there were two onchange-listeners on
> element running the same script? And could I use
> unsafeWindow.toggleNeedinfo in my listener?

I'm not sure why Patrick told you to add another event listener.
Elements can have multiple event listeners but it seems that what you
want to do is to invoke the pre-existing one.

your

unsafeWindow.document.getElementById("knob-
changestatus").onchange()

definitely makes no sense. You need to eval the "onchange" which the
location-hack example above does in the proper scope.

esquifit

unread,
Nov 30, 2007, 6:11:41 PM11/30/07
to greasemon...@googlegroups.com
En/na RodMcguire ha escrit:

> The wiki contains a section on how to invoke an "onclick" handler
> without using unsafeWindow. You could do the same to invoke your
> "onchange" handler.
>
> http://wiki.greasespot.net/Location_hack#Invoke_onclick_behavior

Clever. This has the disadvantage that it only calls the actual
function in the onchange handler but fails to trigger any other event
that could be bound to the same event via addEventListener (probably not
relevant in this particular case).

In general it is possible to synthesize events [1] so that the result is
the same as if they had been triggered by an user's action.

A quick solution would look approximately as follows:

// We are assuming <SELECT ID='foo'><OPTION ...></SELECT>
var SELECT = document.getElementById('foo');

// This just sets the right option but does not trigger onchange
SELECT.childNodes[3].selected = true;

// This does triggers 'onchange';
// the previous lines are still necessary
var evt = document.createEvent("HTMLEvents");
evt.initEvent("change", true, true);
SELECT.dispatchEvent(evt);


[1] http://developer.mozilla.org/en/docs/DOM:document.createEvent

RodMcguire

unread,
Dec 1, 2007, 5:14:30 AM12/1/07
to greasemonkey-users
On Nov 30, 6:11 pm, esquifit <esqui...@googlemail.com> wrote:
...

I took your below comments and used them to create a new wiki
subsection:

http://wiki.greasespot.net/Location_hack#Really_simulating_a_click

Ok?

matej

unread,
Dec 2, 2007, 1:45:24 AM12/2/07
to greasemonkey-users
On 30 Lis, 20:42, RodMcguire <mcgu...@telerama.com> wrote:
> you need something like
>
> unsafeWindow.toggleNeedinfo(unsafeWindow.document.changeform)

This is my error, thanks! I have modified my script to
http://mcepl.fedorapeople.org/scripts/bugzillaCopyOwnerToCC.user.js
and it now sets correctly the form, but when I am finally (after six
hours of debugging!) so close to the victory some bloody even handler
(or something) just screws me up and removes the value of the input
field. See http://mcepl.fedorapeople.org/tmp/samplePage.html (and
other additional files saved by Firefox in http://mcepl.fedorapeople.org/tmp/samplePage_soubory/).

What I want to achieve is that "Bug status change" should be set to
change status to NEEDINFO and From should be set to Reporter. When I
set this correctly in needinfoHandler, it looks for a fraction of
second correctly on page, but then the from Field is set back to Other
and <input type="text"> is cleared out.

Do you have any suggestion how to find out who is to blame for this?

Is there some way how to list all event handlers currently registered
in the page?

Thanks for the help!!!

Matěj

esquifit

unread,
Dec 2, 2007, 8:34:30 AM12/2/07
to greasemon...@googlegroups.com
Rod: thank you for taking the trouble of documenting it, I am too lazy
for that :(
Nevertheless my suggestion has actually nothing to do with the location
hack, except that it can be used in a particular case as an alternative
to another hack (yours) which relies on the location hack ;) Probably
the code snippets section [1] is more appropriate.

[1] http://wiki.greasespot.net/Code_snippets

En/na RodMcguire ha escrit:

esquifit

unread,
Dec 2, 2007, 11:47:14 AM12/2/07
to greasemon...@googlegroups.com
En/na matej ha escrit:

> What I want to achieve is that "Bug status change" should be set to
> change status to NEEDINFO and From should be set to Reporter. When I
> set this correctly in needinfoHandler, it looks for a fraction of
> second correctly on page, but then the from Field is set back to Other
> and <input type="text"> is cleared out.

This is working for me in the test page you indicated:

// 1 - Select radio button 'Change status to'
var cs = document.getElementById('knob-changestatus');
cs.checked = true;

// 2 - Select option 'NEEDINFO'
var sf = document.forms.namedItem( 'changeform');
var ns = sf.elements.namedItem('newstatus');
var ni = ns.options[1];
// NEEDINFO is the second option, i.e. options[1]
ni.selected = true;

// Trigger 'onchange';


var evt = document.createEvent("HTMLEvents");
evt.initEvent("change", true, true);

// set 'Reporter' after change status; this is necessary because
// the 'change' event occurs asynchronously
ni.addEventListener('change',setReporter,true);
ni.dispatchEvent(evt);

// 3 - Select from 'Reporter'
function setReporter(){
var ac = document.getElementById('requestee_actor-16');
ac.options[2].selected = true;
/* trigger onchange to ensure we're not missing
somenthing important, we never know... */


var evt = document.createEvent("HTMLEvents");
evt.initEvent("change", true, true);

ac.dispatchEvent(evt);
}

Of course you have to provide some error-handling in the code above in
order for it to be robust.

> Do you have any suggestion how to find out who is to blame for this?

We should carefully read the code used by the page;
better than that is to reproduce the actions a human user would take, which
is what I did above.

> Is there some way how to list all event handlers currently registered
> in the page?

If by that you mean something like 'foo.getEventListeners()', then the
answer is 'no'. I do not know whether it would be possible to attach
a listener which would capture the instant at which other event would be
triggered, an in that case if we could even know the name of the
listener or a reference to it. This seems like an interesting exercise ;)

matej

unread,
Dec 3, 2007, 1:05:40 PM12/3/07
to greasemonkey-users
On Dec 2, 5:47 pm, esquifit <esqui...@googlemail.com> wrote:
> // 2 - Select option 'NEEDINFO'
> var sf = document.forms.namedItem( 'changeform');
> var ns = sf.elements.namedItem('newstatus');
> var ni = ns.options[1];
> // NEEDINFO is the second option, i.e. options[1]

Actually, it is the first one, so we have to use options[0]

> // 3 - Select from 'Reporter'
> function setReporter(){
> var ac = document.getElementById('requestee_actor-16');
> ac.options[2].selected = true;
> /* trigger onchange to ensure we're not missing
> somenthing important, we never know... */
> var evt = document.createEvent("HTMLEvents");
> evt.initEvent("change", true, true);
> ac.dispatchEvent(evt);
>
> }

Actually, this doesn't work, because we have to get needinfo.flag_id
from the global scope (take a look at the original HTML, whole INPUT
element is generated by the Javascript with the changing name/id).
However, whatever I tried I cannot get to the global needinfo (even
unsafeWindow.needinfo doesn't work -- I don't care about unsafeWindow
in this case, because I pretty much have to trust bugzilla of my
employer ;-)). Any thoughts?

The last version of the script is on http://mcepl.fedorapeople.org/scripts/bugzillaCopyOwnerToCC.user.js
and in git repository on http://mcepl.fedorapeople.org/repo/greasemonkey.git
(get it with git clone http://mcepl.fedorapeople.org/repo/greasemonkey.git).

Thanks for all the help. Really!

Matěj

esquifit

unread,
Dec 3, 2007, 6:11:27 PM12/3/07
to greasemon...@googlegroups.com
En/na matej ha escrit:

> On Dec 2, 5:47 pm, esquifit <esqui...@googlemail.com> wrote:
>> // NEEDINFO is the second option, i.e. options[1]
>
> Actually, it is the first one, so we have to use options[0]

I developed my script on the page you indicated in your original post:

http://mcepl.fedorapeople.org/tmp/show_bug.html

There NEEDINFO was option[1].


>
>> // 3 - Select from 'Reporter'
>> function setReporter(){
>> var ac = document.getElementById('requestee_actor-16');

>>[...]


>> }
>
> Actually, this doesn't work, because we have to get needinfo.flag_id
> from the global scope (take a look at the original HTML, whole INPUT
> element is generated by the Javascript with the changing name/id).
> However, whatever I tried I cannot get to the global needinfo (even
> unsafeWindow.needinfo doesn't work -- I don't care about unsafeWindow
> in this case, because I pretty much have to trust bugzilla of my
> employer ;-)). Any thoughts?

I see. Anyway replacing the line above by the following

var ac = document.getElementById('requestee_actor-' +
unsafeWindow.needinfo.flag_id );

works just fine. Why are you saying you cannot get
unsafeWindow.needinfo to work?

I cannot completely test the script on the sample page because I get a
404 upon submit (button "NEEDINFO reporter"). However, if you slightly
modify the addNewButton function to inhibit the submit:

function addNewButton(oldButton,newId,newLabel,handlerFunc) {
var newButton = oldButton.cloneNode(true);
newButton.setAttribute('type','button'); // ---> added line
newButton.id=newId
...
}

you will find that it sets the status correctly, as well as the 'from'
field. This leads me to think that the problem is probably the
submission taking place before our synthesized events get a chance to be
triggered. If this is is so, we could attempt to capture the submit
event, trigger our events, and then release the submit and let it go.

Alternatively you can try delaying the submit:

1) Inhibit the submit by setting the button type to 'button' as above
2) At the end of function needinfoHandler call the form's submit method
with a delay of 300 milliseconds:
setTimeout("document.forms.namedItem('changeform').submit()",300);

Not the fantastic solution, but it may help you to find the culprit.


Matěj Cepl

unread,
Dec 4, 2007, 6:55:27 PM12/4/07
to greasemon...@googlegroups.com
esquifit píše v Út 04. 12. 2007 v 00:11 +0100:

> I cannot completely test the script on the sample page because I get a
> 404 upon submit (button "NEEDINFO reporter"). However, if you slightly
> modify the addNewButton function to inhibit the submit:
>
> function addNewButton(oldButton,newId,newLabel,handlerFunc) {
> var newButton = oldButton.cloneNode(true);
> newButton.setAttribute('type','button'); // ---> added line
> newButton.id=newId
> ...
> }
>
> you will find that it sets the status correctly, as well as the 'from'
> field.

Yes, this is correct. Finally, at least something in this mess seems to
work as I would expect it!

> This leads me to think that the problem is probably the
> submission taking place before our synthesized events get a chance to be
> triggered. If this is is so, we could attempt to capture the submit
> event, trigger our events, and then release the submit and let it go.

Do you mean adding

document.forms[0].addEventListener("submit",FakeSubmit,true)

and then doing something like this:

function FakeSubmit(evt) {
needinfoHandler();
var evtSubmit = document.createEvent("HTMLEvents");
evtSubmit.initEvent("submit", true, true);
ac.dispatchEvent(evtSubmit);

evt.stopPropagation();
evt.preventDefault();

}

Is that what you meant?

Thanks for all the help,

Matěj

--
http://www.ceplovi.cz/matej/blog/, Jabber: ceplma<at>jabber.cz
GPG Finger: 89EF 4BC6 288A BF43 1BAB 25C3 E09F EF25 D964 84AC

Whenever Christ our life is revealed, then also you will be
revealed with Him in glory.
-- Colossians 3:4 (Green's Literal Translation)

Matěj Cepl

unread,
Dec 4, 2007, 6:58:15 PM12/4/07
to greasemon...@googlegroups.com
Matěj Cepl píše v St 05. 12. 2007 v 00:55 +0100:

> Is that what you meant?

Or in other words, is there any way how to wait until the event finishes
to happen? Some kind of callbacks or something?

Matěj
--
http://www.ceplovi.cz/matej/blog/, Jabber: ceplma<at>jabber.cz
GPG Finger: 89EF 4BC6 288A BF43 1BAB 25C3 E09F EF25 D964 84AC

There's nothing wrong with you that reincarnation won't cure.
-- Jack F. Leonard

matej

unread,
Dec 5, 2007, 7:00:21 AM12/5/07
to greasemonkey-users
On Dec 4, 12:11 am, esquifit <esqui...@googlemail.com> wrote:
> > The last version of the script is onhttp://mcepl.fedorapeople.org/scripts/bugzillaCopyOwnerToCC.user.js

> function addNewButton(oldButton,newId,newLabel,handlerFunc) {
> var newButton = oldButton.cloneNode(true);
> newButton.setAttribute('type','button'); // ---> added line
> newButton.id=newId

Using this trick I have managed to make both (I have add one more
button as well adding a long request for information string to the
comment textarea) buttons working as non-submitting. THANKS!!! This is
at least working for me somehow. The updated version is both on the
same URL as before and in the above-mentioned git repository.

Now, the question is whether we wouldn't be able to make that
submitting working. Any thoughts?

Thanks a lot!!!!

Matěj

matej

unread,
Dec 10, 2007, 11:59:13 AM12/10/07
to greasemonkey-users
On 3 Pro, 19:05, matej <matej.c...@gmail.com> wrote:
> On Dec 2, 5:47 pm, esquifit <esqui...@googlemail.com> wrote:
>
> > // 2 - Select option 'NEEDINFO'
> > var sf = document.forms.namedItem( 'changeform');
> > var ns = sf.elements.namedItem('newstatus');
> > var ni = ns.options[1];
> > // NEEDINFO is the second option, i.e. options[1]
>
> Actually, it is the first one, so we have to use options[0]

Actually, neither -- the content of that listbox is generated and it
depends on the given status of the bug in the given moment. I had to
find out the current situation of the listbox dynamically.

> The last version of the script is onhttp://mcepl.fedorapeople.org/scripts/bugzillaCopyOwnerToCC.user.js
> and in git repository onhttp://mcepl.fedorapeople.org/repo/greasemonkey.git
It seems to work now.

Thanks for all the help and encouragement!!!

Matěj
Reply all
Reply to author
Forward
0 new messages