December 29, 2005

Sending messages from content to chrome?

Over the years, one of my more fundamental tasks has been to make sure information goes from one page to another. In the land of HTML, I did this with a fairly detailed tutorial on JavaScriptKit.com. The article is over five years old, but still relevant for people beginning in the business.

Since then, I've learned a few things. Chrome windows can discover each other through the window watcher. There are observers (which I do not have a firm grasp on). Chrome windows have full control over content, which lets GreaseMonkey do nice things.

Content windows still live in a sandbox, though. For very good reason! Still, I find myself wondering how I can get a message from a JavaScript function in the content window into a JavaScript function in its container chrome window.

The problem is simple: let's say you have a string A in your content window. Function B in content gets called to change A. The chrome window has a function C which is designed to run when A changes. How can B call on C? Also, when the content window unloads and a new window / document pair loads (the user clicked on a link), how can A be made available to the new window?

Put another way: A content page does something (executes a JS function, or changes a value) without loading a new page. How does the chrome window find out about it and react to it?

I've come up dry on every idea I have. Right now, I only have two decent ideas left. One is to use a load event listener (which is the only one to bubble from content to chrome) to set up a secondary event listener or JS watch on related window objects. The other (thanks to timeless) is to implement a component that registers itself as a global object, such as window.sidebar. (nsSidebar.js was the example given to me.) Unfortunately, I also need a good interface, and would prefer to implement one that Mozilla already has (as opposed to creating a new one).

Help wanted! I need this both for XUL Widgets and for corporate use.

UPDATE: bz to the rescue again! Read comments for details.

Posted by WeirdAl at December 29, 2005 12:15 AM
Comments

For content -> chrome -> content
--
I generate custom events in the content layer that trigger event handlers in chrome. The chrome code can then access the content data any way necessary.

A load event on the next page would probably suffice for triggering the process of writing that copied data back to content.

For chrome -> chrome
--
Observers. Definitely. Learn them.
http://kb.mozillazine.org/Using_observers

Posted by: Ben Basson at December 29, 2005 5:15 AM

Just have content fire an event and have chrome listen to it. And be very very careful of introducing security holes.

Posted by: Boris at December 29, 2005 7:36 AM

> load event listener (which is the only one to bubble from content to chrome)

AFAIK this isn't true. Some time ago, someone asked in the MZ Extensions forum for a solution to a similar problem, and I was able to create a custom event that bubbled up all the way to the XUL document. I wrote up the steps at http://forums.mozillazine.org/viewtopic.php?p=1005555#1005555

HTH,
Jens

Posted by: jens.b at December 29, 2005 9:35 AM

Thanks Jens, Boris... I thought I tried that approach already on the DOMAttrModified event (which is currently defined). It didn't work.

UPDATE: :-( I'm trying the code now, and it's not working on SeaMonkey 1.0b. Basically, content's detecting the event, chrome isn't, and there are no JS errors/warnings in my code.

UPDATE 2: Argh. Thanks, Boris, for pointing out http://lxr.mozilla.org/seamonkey/source/dom/public/idl/events/nsIDOMNSEventTarget.idl . That solves the problem neatly.

For those of you just joining us, the addEventListener call must have a fourth argument (true), to specify your event listener will accept untrusted events as well. This means events from a different domain, for example (all too common in chrome/content situations!) No additional argument is required for removeEventListener, apparently.

Posted by: Alex Vincent at December 29, 2005 9:59 AM

I use events too + OBJECT.watch(property, callback)/unwatch(...) JS methods.

Posted by: ElixonCMS/XUL at January 1, 2006 2:25 PM

I actually have the same need for making some chrome object available to Web pages' script, much like the "sidebar" object is made available. But I'd like my object to know which "window" and "document" it's associated with, and I haven't yet found a way from within the createInstance() of the XPCOM object to determine which "window" causes it to be instantiated. Do you by any chance know how? Thanks!

Posted by: David Huynh at January 21, 2006 3:00 PM