On Wed, 30 May 2007 17:53:11 +0300, kgi
On Wednesday 30 May 2007 15:15:56 Jean-Paul Calderone wrote:
Hi Jean-Paul; thanks for your email - very helpful.
Widgets on the client have a hierarchical relationship with each other which reflects the hierarchical relationship of their corresponding server-side LiveElement progenitors. That is, if LiveElement B has setFragmentParent called on it with LiveElement A as an argument, then Widget B will have a widgetParent property which refers to Widget A; similarly, Widget A's childWidgets array property will include widget B. These relationships can be used to pass messages between widgets in the browser without involving the server.
Yep, I see the attributes for traversing along the hierarchy. Unless I've misunderstood, in order for a widget's Javascript to be able to call another widget's Javascript, it has to do something like:
self.widgetParent.widgetParent.widgetParent ... childWidgets[0].childWidgets[1].doStuff()
This feels somewhat wrong, partly because of fragility: if I move the location of a widget in the hierarchy, its Javascript code will need updating.
Yep. One solution to this is to do something like: self.widgetParent.doStuffToSpecificThing() Supplying an implementation of doStuffToSpecific for whatever the widget's parent happens to be which knows about its position in the overall page layout. This keeps the inter-widget dependency limited to a single step.
Is there a way of accessing another widget in the page directly by name? An example might be a panel where I want any widget to be able to append status messages.
I would imagine this might entail assigning a user-controlled widget id to the top-level DOM node of a LiveElement (as opposed to *subnodes* of the widget, in which ids are rewritten for use by nodeById(), and which need the athena id to access).
I suppose the stan would look like this (this doesn't work, because the id gets clobbered by the autogenerated id):
T.div ( _id = 'my-unique-id', render = T.directive ( "mywidget" ) ), T.div ( _id = 'another-unique-id', render = T.directive ( "mywidget" ) )
Then in JS code of another widget:
w = self.getAthenaWidgetByName ( 'my-unique-id' ); w.doStuff()
Obviously, the LiveElement nodes are already all assigned a unique id, it's just that it's done automatically and there's no obvious way of getting at them ahead-of-time.
I guess I could always cheat and wrap all LiveElements inside named divs and do document.getElementById(), but that feels silly, given that the divs are already named.
There are plenty of methods in Nevow/nevow/js/Nevow/Athena/__init__.js for getting hold of things but they all seem to need either the *numeric* athena id (fromAthenaID, callByAthenaID) or a reference to a node (athenaIDFromNode, athenaClassFromNode).
Something about this approach rubs me the wrong way. Identifiers which are required to be globally unique sends one down the path of being limited to only supporting certain page configurations. Maybe if there were some well defined algorithm for choosing the "nearest" widget with a given identifier, something could be worked out. I'm not too sure about this either, though. You can already do something like this, though, if the class name is a sufficient identifier for the widget you want (find the node with the right value for athena:class, then find the widget associated with the node). I tend to discourage this approach in favor of the one I gave at the top of the message, though. Jean-Paul