Widgets Advanced Uses

Programming is a complicated subject and I can't cover all the bases for how you may wish to use this library. But here are some tips and tricks for more advanced uses.

Hosting widgets.js In A Foreign Frame

In some advanced scenarios, it is desirable the main widgets.js files in a foreign frame.

Among the advantages are not reloading the .js files on every page access, regardless of the randomness of the browser cache, and the avoidance of potentially expensive re-initialization and general slowdown from executing large, redundant chunks of code.

The downside is that it will really test your knowlegde of Javascript and the page scope rules, and that there are some structures that the Widgets framework depends on that really ought to be re-initialized on every page load, mostly the ones used for event handling.

However, the library is used this way by the author so it should be able to be made to work. The keys are:

Don't mix the widget declaration amoung various windows or the WidgetNameToType registry will break.

You need to be extra careful to access the globals through "this.globals" and not "WidgetGlobals"; single-frame users can get away with the latter, you can not. If WidgetGlobals appears, that's probably a bug.

If you do this all correctly, you should end up with the result being that all of the persistent widget code stays in the frame, and all of the transient stuff you want garbage collected, like Widget instances, are attached to the changing HTML page, so everything pretty much just garbage collects naturally and memory leaks won't be XBLinJS's fault. It is worth periodically checking WidgetGlobals.Widgets (I use display(WidgetGlobals.Widgets), display is in misc.js) in the various frames to be sure that widgets are where they belong; I find it easy to forget to pass in the window parameter and that will cause Widgets to migrate into the containing frame. Fortunately, this is generally easy to fix.

Also be sure not to load widgets.js into other windows, as the separate definitions of everything causes problems; a Widget constructed from one definition won't be an instanceof the other Widget definition, which breaks some XBLinJS code. In particular, if DOM(widget) keeps returning the Widget, and not a DOM node, this is the most likely reason.

Cute (And Useful) Tricks

The Widgets shipped with XBLinJS are just the ones I've done that I think people may find generally useful; I've also built several real-world systems with this. There are several things I've learned.

First, it is advantageous to keep the .init* functions as small as possible. It is not possible to completely eliminate them in all cases, but the more you can shift into .defaults, various .set_* functions, and the rest of the .setAttribute system, the better. This eliminates a lot of conditional "did I get this parameter?" logic. It also generally results in widgets that are easier to use from within other widgets by just using .set(), which makes things much easier.

Do be sure to clearly document whether a .set_* function is capable of recieving a parameter multiple times; I often find that the ones I write for initialization only can't be called more than once. (Perhaps I should provide an easy way to indicate that so the errors can be caught earlier?)

Would you like to inherit a .content from a parent widget in such a way that changes will propogate, but you don't want it to be quite the same? Consider this cute trick:

deriveNewWidget("ChildWidget", ParentWidget);
ChildWidget.prototype.content = (
  (c = objCopy(ParentWidget.prototype.content),
   c.someParam = "newValue",
   c)
);

Recall that objCopy only copies one level deep; you may need to write a deeper copy function if you don't want to change a surface attribute.

Using XBLinJS as an XBL replacement

XBLinJS ships in such a way to make it easiest to use with cross-browser HTML environments. Using DOM in an XML environment that supports DOM2 and XML namespaces, as Mozilla's XUL does, requires significant changes, most notably by using the namespace-aware node creation functions like createElementNS or setAttributeNS.

XBLinJS ships with the easy ability to switch over to using these calls. Do one of the following:

  1. In your copy of widgets.js, change the FLAVOR = BrowserFlavor line to read FLAVOR = DOM2Flavor.
  2. In between the inclusion of flavors.js and widgets.js, add a line setting FLAVOR = DOM2Flavor, as before.

This results in a Widget class that is aware of namespaces and such, and allows you to specify defaultURIs and mnemonic->URI mappings (i.e., telling XBLinJS what "html:" means), and specifying tag names just as you would in conventional XBL. The primary difference is that you must explicitly tell XBLinJS what the namespaces are since it can't hook into XML mechanisms. (In practice this is not a problem, and XBLinJS ships with specifications for html:, xul:, and defaults to the XUL namespace, so most current Mozilla apps probably won't need to do any specification at all.)

See the DOM2Flavor class documentation for more about the relevant changes.

Note that since defaultURI can be overridden on a class-by-class basis, and since XBLinJS implements its own event system which is the same in both DOM2 and HTML, that many widgets designed for HTML can be used in XUL simply by setting their defaultURI before constructing them, as-is. Unfortunately, you will not get the nice styling that Mozilla does on XUL widgets automatically, you will need to add it yourself. (In particular, the Javascript Console can be highly useful...)

JObject

Like the general setup of Widgets, with .setAttribute and stuff, and you want to use it outside of Widgets? Good news, that's all factored out into a class called JObject, which basically has all the yummy goodness of the Widget data model without any of the DOM manipulation code. See jobject.js and the documentation.

Jerf.org : Programs & Resources : Widgets Advanced Uses

 

Current Section Links

 

Sub-Sections

 

Search Jerf.org
Google

Search WWW
Search jerf.org