[Greasemonkey] XPCNativeWrappers and Deer Park compatibility

Mark Pilgrim pilgrim at gmail.com
Wed Jul 27 18:23:35 EDT 2005


Simon and I have been furiously working on updating all the scripts in
"Greasemonkey Hacks" to work with GM-TNG and Deer Park alpha 2.  Here
are the most frequent problems I've encountered so far.

Every element you get from document.anything(), including new elements
you create with document.createElement, or elements you get from
document.getElementById or document.getElementsByTagName, is a "deep
wrapper" (technically, an XPCNativeWrapper object) around the real
element.  XPCNativeWrappers have several limitations that will
frustrate you, and you will be tempted to say "screw it" and just use
unsafeWindow/contentWindow where "everything just works."  Resist this
temptation!  Take the time to learn about XPCNativeWrappers.

1. You can't access form elements by name.  For the form <form
id="foo"><input name="bar"></form>, the following code no longer
works:

var elmForm = document.getElementById('foo');
elmForm.bar.value = '...';

Instead, you need to to do this:

var elmForm = document.getElementById('foo');
elmForm.elements.namedItem('bar').value = '...';

2. Scripts often create new elements (like links) and assign onclick
or other event handlers to them directly.  Setting
elementWrapper.onclick = 'javascript code' does not work; neither does
setting elementWrapper.onclick = functionRef, as explempfied by the
following non-working code:

function my_click_handler() { ...; return false; }
var elmLink = document.createElement('a');
elmLink.onclick = my_click_handler;

Instead, you need to use addEventListener and call
event.preventDefault() inside your event handler if you want to
prevent the event from bubbling, like this:

function my_click_handler(event) { ...; event.preventDefault(); }
var elmLink = document.createElement('a');
elmLink.addEventListener('click', my_click_handler, true);

This applies to any element, not just new ones you create, and any
event handler, not just onclick.  If you are defining an onkeypress
handler for an input element you get by ID, this is the only variation
that works in Deer Park:

function my_keypress_handler(event) { ...; event.preventDefault(); }
var elmInput = document.getElementById('foo');
elmInput.addEventListener('keypress', my_keypress_handler, true);

3. Scripts often create brand new properties on elements to reference
them later.  For example my Zoom Textarea script (
http://diveintogreasemonkey.org/download/zoomtextarea.user.js )
inserts a button before each <textarea> and "associates" each button
with its <textarea> by creating a new _target property on the button
(and then referencing that property later in the button's onclick
handler).  This simply doesn't work at all in Deer Park; you just
can't create new properties on XPCNativeWrappers.  You will need to
refactor your code to remove the custom property, and pass it to the
event handler (or whatever) some other way, like with a closure.

Non-working code (violates #2 and #3 above):

function my_button_click(event) {
  var elmTextarea = event.currentTarget._target;
  ...
  return false;
}
var elmTextarea = document.getElementById('foo');
var elmButton = document.createElement('a');
elmButton._target = elmTextarea;
elmButton.onclick = my_button_click;

Refactored code that works in Deer Park:

function my_button_click(event, elmTextarea) {
  ...
  event.preventDefault();
}
var elmTextarea = document.getElementById('foo');
var elmButton = document.createElement('a');
elmButton.addEventListener('click', function(event) {
  my_button_click(event, elmTextarea);
}, true);

All of these techniques also work in GM-TNG under FF 1.0.6, so you
don't need to sacrifice backward compatibility to gain forward
compatibility.

I have been notifying individual developers as I fix their scripts. 
If we're using one of your scripts in "Greasemonkey Hacks" and you
don't hear from either me or Simon in the next few weeks, chances are
your script works without modification in Deer Park.

Once "Greasemonkey Hacks" is done, I will be updating Dive Into
Greasemonkey to include a chapter on Deer Park compatibility, as well
as updating all the examples, patterns, case studies, and the rest of
my own scripts.  Until then, keep watching this mailing list, and I'll
report any new stumbling blocks as I, er, stumble over them.

Many thanks to Aaron Boodman, who patiently explained all this to me,
and even went to the trouble of fixing one of my book's scripts.  His
efforts served as a starting point in my own education, and now your
education as well.

-- 
Cheers,
-Mark


More information about the Greasemonkey mailing list