XPCNativeWrapper
Contents |
[edit] Overview
Most all objects on a target web page that a user script sees are wrapped in XPCNativeWrapper. The reason for this is so that a script can change the properties of an object (actually the wrapper) without any JavaScript on the target page being able to interfere. Mostly the wrapping is "transparent" - wrapped and unwrapped objects behave the same because the wrapping object passes all access through to the wrapped object; there are some exceptions though.
Note: in Firefox 4, XrayWrapper replaced XPCNativeWrapper. They have different names but in effect serve the same purpose.
[edit] wrappedJSObject
For a script to access the real underlying object there is the method
var realObj = wrappedObj.wrappedJSObject;
Be very careful when using the wrappedJSObject property. It is just as dangerous as unsafeWindow is.
[edit] Security
Related to security.
[edit] Limitations / Problems
[edit] Expando Properties
Expando Properties do not work on XPCNativeWrappers. This means that, for example, this will not work:
var el = document.createElement("a");
el.onclick = "alert('Error'); return false;";
Instead, use setAttribute and addEventListener methods. Note the use of the preventDefault method to emulate the "return false" behavior above.
addEventListener example:
function showTheError(event) {
event.preventDefault();
/* some code */
}
var el = document.createElement("a");
el.addEventListener("click", showTheError, false);
setAttribute example:
var el = document.createElement("a");
el.setAttribute("onclick", "alert('Error'); return false;");
This applies to any element, not just new ones you create (those references from createElement and those from getElementById et al), and any event handler, not just onclick.
[edit] for ... in on HTMLCollections
DOM methods like getElementsByTagName return HTMLCollections.
var arInputs = document.getElementsByTagName("input");
for (var elmInput in arInputs) {
/* some code */
}
Instead use this...
var arInputs = document.getElementsByTagName("input");
var elmInput;
for (var i = arInputs.length - 1; i >= 0; --i) {
elmInput = arInputs[i];
/* some code */
}
or
var arInputs = document.getElementsByTagName("input");
for each(var elmInput in arInputs) {
/* some code */
}
[edit] Named Items
Items like frames, form elements, and so on can be referenced by name in normal JavaScript.
XPCNativeWrappers cannot reference items by name. Use the namedItem method.
With a <input name="foo"> in the form:
form.foo;
Instead use this...
form.elements.namedItem("foo");
The same goes for frames:
window.framename;
Instead use this...
window.frames["framename"];}
[edit] Event Handlers
Normal JavaScript can access an element's event handlers with code like:
element.onclick = myClickHandler;
or
element.onclick = "myClickHandler(this)";
This does not work on XPCNativeWrappers; it will result in a Component not available error in the JavaScript console. Instead, use addEventListener:
element.addEventListener("click", myClickHandler, false);
Any Greasemonkey script written before version 0.5 was released in mid-2005 may need updating to use addEventListener.