[Twisted-web] Quick Questions about JS mapping in Athena.

Jean-Paul Calderone exarkun at divmod.com
Thu May 17 12:54:40 EDT 2007

On Thu, 17 May 2007 19:29:26 +0300, kgi <iacovou at gmail.com> wrote:
>On Thursday 17 May 2007 18:31:59 Jean-Paul Calderone wrote:
>Hi Jean-Paul; thanks for your quick answer.
>> The import system requires more or less complete knowledge of what modules
>> are defined in order to resolve dependencies.  If each LiveElement took
>> care to declaring which file it needed, then the page would need to be
>> rendered completely before Athena could figure out which modules needed to
>> be loaded, by which time it is a little too late to include them in the
>> page (perhaps this could be made to work, but it would be a hassle).
>OK, I guess I'll just have to bite the bullet. Adding something to sys.path is
>not such a big deal.
>> I wouldn't be happy to see a solution that required declaring all
>> LiveElement classes a LivePage is going to use, since my own most common
>> use-case for LivePages involves my not having any idea what most of the
>> LiveElements will be (and in fact, changing what they will be with almost
>> every render).  I'm open to other suggestions and discussion about
>> improving this area of Athena, though.
>Oh, really? That's interesting. How does Athena push new Javascript code to a
>page after the initial render? I didn't even know it was possible to do such
>a thing: for me, Javascript has always been something you link to from the
>page header. Looks like my 4th Edition "JS Definitive Guide" (2001) is
>showing its age :-)

Basically it just notices when some required javascript is absent, loads it
from the server, and eval()'s it.  The same dependency system is used to
resolve dependencies at page render time (which are turned into <script>
tags in the <head> of the rendered page) and dynamically after the initial
page render (which are turned into these dynamic load/evals).

>> The idea is to provide a package hierarchy, as Python has.  The strings
>> will be split on "." in a couple places, but if there is simply no "." in
>> them, this will work (since it is equivalent to any top-level name in an
>> arrangement which does use dotted names).  The goal of dotted names is to
>> avoid polluting the top-level namespace more than necessary.
>You're talking about Javascript's top-level namespace, right? (I assume these
>strings never go anywhere near Python's namespace). OK, that sounds logical;
>I was just wondering whether there was anything more to it that.


>>  For sanity's
>> sake, I would define classes in a module as attributes of that module,
>> rather than using arbitrary other names
>Hmm, I'm not quite sure I understand what you mean in this context. I *think*
>you're talking about JS classes, but the terminology is Python terminology.

Yep.  Python has a pretty reasonable module system.  Athena's JS "module
system" is loosely based on it, so a lot of Python terminology makes sense
for it as well.

>If the former (JS classes) do you mean, you'd prefer to have a single (or a
>few) javascript file(s) and have these define the JS for *lots* of related
>LiveElement classes, which all declare themselves to be a (namespaced)
>jsClass, and all these jsClasses map to the same physical JS file?

I didn't mean to imply anything about how much or little JS is in any single
source file.  Mostly I just wanted to point out that I think a single source
file should completely define any particular module.  ie, if a.js puts things
onto the JS "module" A, b.js should _not_ put things onto it.

>In other words, for project "Cutlery":
># In Python LivePage stuff:
>class Fork ( LiveElement ):
>    jsClass = u'Cutlery.Fork'
>class Spoon ( LiveElement ):
>    jsClass = u'Cutlery.Spoon'
>class Knife ( LiveElement ):
>    jsClass = u'Cutlery.Knife'
># In Python plugin code:
>jsModules.mapping = {
>  # Note: the same file!
>  u'Cutlery.Fork' : 'cutlery.js',
>  u'Cutlery.Spoon' : 'cutlery.js',
>  u'Cutlery.Knife' : 'cutlery.js',

Note that since the dependency resolution system works upwards, this
mapping only needs one entry for this example to work:

    jsModules.mapping = {u'Cutlery': 'cutlery.js'}

># In the file cutlery.js:
>Cutlery = {};
>Cutlery.Fork = Nevow.Athena.Widget.subclass ( 'Cutlery.Fork' );
>Cutlery.Fork.methods ( ... );
>Cutlery.Spoon = Nevow.Athena.Widget.subclass ( 'Cutlery.Spoon' );
>Cutlery.Spoon.methods ( ... );
>Cutlery.Knife = Nevow.Athena.Widget.subclass ( 'Cutlery.Knife' );
>Cutlery.Knife.methods ( ... );
>Is this what you mean?

I... think?  so...  I'm not sure if you were trying to demonstrate something
by putting the jsModules mapping into the same file as the rest of the
Python (since you pointed it out, I suspect you were, but I'm not sure what).

>Actually, I have a couple more very quick questions that I thought up while
>typing this:
>- Am I right in thinking that no athena JS files ever need to have declare any
>of the modules mentioned in BOOTSTRAP_MODULES (e.g. Divmod, Nevow.Athena)?

Well, it'll work if they don't, since those are always loaded on every page,
but I might decide to change what's in BOOTSTRAP_MODULES. :)  To be safe,
I'd declare any dependency, even one that's in that collection at the time.

>- Is there a recommended way for LiveElements to access each other on the
>server? For example, I click on an element of (client-side) Foo that invokes
>a method on (server-side) Foo; this then needs to update the state of
>(server-side) Bar, which needs to update (client-side) Bar. At the moment I'm
>using an manual ad-hoc registry, with the occasional (naughty?)
>obj.fragmentParent thrown in. I was wondering if there was a more robust
>method already in place that I had totally missed (like the LiveElements
>being assigned names upon creation, which can then be automagically found
>through something like page.findElementByName ( "Bar" )).

Unfortunately, names would have to be unique within the context of a page,
which leads to the possibility of collisions.  Resolving this would make
it impossible to know the actual name of the element you want. :)  I'd
suggest instantiating your LiveElements with direct references to whatever
other objects they need.

This is somewhat similar to a problem many people have when implementing
protocols with Twisted.  I don't know of a general solution, but arranging
for the right objects to be referencable from the right places should solve
any particular case that comes up.


More information about the Twisted-web mailing list