[Twisted-web] DOM manipulation in an athena widget

Phil Mayers p.mayers at imperial.ac.uk
Sun Oct 1 17:57:01 CDT 2006


glyph at divmod.com wrote:
>> Also, I'm not an expert, but don't many browsers limit you to 2 HTTP 
>> requests outstanding to a given server at once, meaning it's likely 
>> you'd run into problems running e.g. the Mochikit xmlhttp and the 
>> Athena one?
> 
> Yep.  This isn't a library problem though: if you're using Athena, you 
> _must not_ use any other XHR APIs in your page.  Athena goes to a good 
> deal of trouble to allow you to have more than 2 outstanding athena 
> requests when the browser allows you only 2 HTTP requests.  It needs 
> both of those requests though, one to wait for incoming notifications 
> and one to make outgoing requests.

Ah. That's an issue.

This rules out safely calling other non-Nevow RPCs (which might be glued 
into the same server & URL space by reverse proxying, and in fact are in 
my case). Obviously I can write (tedious) code to execute those RPCs on 
the server, but scalability aside it also breaks single sign-on.

(Note: I'm not saying Nevow or Athena are doing the wrong thing here - 
as you correctly say, this is a browser limitation).

I think this can be solved using IFRAMEs to make the RPCs, but at the 
expense of another server name (and IP if using SSL in fact). Will have 
to look into that.

> 
>> What I'm trying to get a feel for with the Athena stuff is what parts 
>> of the javascript runtime, if any, are supposed to be used, and which 
>> parts are private and just for implementing callRemote and friends.
> 
> I hope someone more knowledgeable about the intent of those APIs will 
> answer.  Technically speaking the rule is that the APIs are public 
> unless they start with "_", but "public" doesn't necessarily mean 
> "supported in perpetuity".
> 
> Please feel free to ask about specific things though; hopefully someone 
> more knowledgeable about the API's intent than I will answer.

Well, the specific thing I was thinking of was the JSON-RPC but knowing 
that Athena consumes both available XHR requests makes the point moot.

Interestingly, it seems we've reached a situation analogous with the 
desire for a single event loop in the python standard library, only this 
time in the JavaScript VM ;o)

For the info of anyone reading, I did eventually get all this working, 
and am using MochiKit for the client-side DOM stuff but calling athena 
widget callRemote channels - cool stuff like (untested copy&paste):

function saveEditable(evt) {
   var tb = event.src();
   var span = tb.parentNode;
   var widget = Nevow.Athena.Widget.get(span);

   /* only if it has changed... */
   if (tb.value!=tb.orig) {

     /* mark it dirty */
     addElementClass(span, 'dirty');
     /* push update to server */
     var d = widget.callRemote('update', span.id, tb.value);

     /* wait for ok/fail */
     d.addCallbacks(
       /* ok, remove dirty mark */
       function(v) {
         removeElementClass(span, 'dirty');
       },

       /* fail, display error for 5 seconds,
       function(e) {
         var v = scrapeText(span);
         replaceChildNodes(span, e);
         callLater(5, replaceChildNodes, span, v);
       });

   }

   /* convert the span back to a plain text holder */
   replaceChildNodes(span, tb.value);
   removeElementClass(span, 'editing');
}

function makeEditable(evt) {
   var span = evt.src();

   if (hasElementClass(span, 'editing')) return false;

   /* get the contents of the span */
   var text = scrapeText(span);
   /* put it into a text field... */
   var tb = INPUT({'type': 'text', 'value': text});
   tb['orig'] = text;
   /* ...inside the span */
   replaceChildNodes(span, tb);
   tb.focus();
   connect(tb, 'onblur', saveEditable);

   addElementClass(span, 'editing');
}

function setupEditFields(node) {
   forEach(
     getElementsByTagAndClassName('span', 'editable', node),
     function(n) {
       connect(n, 'onclick', makeEditable);
     });
}

myApp.myWidget = Nevow.Athena.Widget.subclass('myApp.myWidget');
myApp.myWidget.methods(
   function __init__(self, node) {
     myApp.myWidget.upcall(self, '__init__', node);
     setupEditFields(node);
   });



More information about the Twisted-web mailing list