Re: Problem with Scriptaculous

Previous Topic Next Topic
 
classic Classic list List threaded Threaded
5 messages Options
Reply | Threaded
Open this post in threaded view
|

Re: Problem with Scriptaculous

Lukas Renggli
> I am trying to get a clickable map type effect
> using scriptaculous. I have a graph rendered
> by GraphViz, I need scriptaculous to tell me the
> click co-ordinates so that I can work out what in
> the graph was clicked upon.
>
> It wouldn't be the first time that I didnt know what
> I was doing, but I wondered if you could look at
> this code for me.
>
> The containing div id is 'workflow'.
> The problem is that callback "B" works, and callback
> "A" doesnt. If I swap them around only the second
> one works. Is this to be expected?

I tried to reproduce the problem, but it works for me (see my
file-out). My code evaluates all 4 callbacks correctly and I get the
two co-ordinates displayed. I had to refactor your code a bit as it
was missing some pieces, so maybe the problem is hidden there.

Two comments:

1. The offset co-ordinates you get are probably not those you expect.
offsetTop and offsetLeft answer the offset [1] up to the next absolute
or relative positioned div, generally not those relative to the upper
left corner of the document. In you case you probably need to use
something like cumulativeOffset [2]. It also depends on your styles of
course, so I don't know if that is a problem in your case.

[1] http://developer.mozilla.org/en/docs/DOM:element.offsetLeft
[2] http://prototypejs.org/api/position/cumulativeoffset

2. You can improve the performance of your example by combining the
two #updater together. The first of your #updater is not really an
#updater, it does not update anything. The #requestor would do here as
well. I suggest to combine them to something like:

    html updater
         id: 'co-ordinates';
         callback: [ :v | ... ] value: ...;
         callback: [ :v | ... ] value: ...;
         callback: [ :v | ... ] value: ...;
         callback: [ :v | ... ] value: ...;
         on: #renderCoordinatesOn: of: self

Cheers,
Lukas

>renderImageOn: html
>  | offsetX offsetY |
>
>   offsetX := ValueHolder new.
>   offsetY := ValueHolder new.
>   self generateGraphForm.
>   html image
>       id: 'workflow-image';
>       onClick: (html updater
>  "A"         callback: [ :v | offsetY contents: v asNumber ] value: (((SUElement on: html) id: 'workflow') property:'offsetTop');
>  "B"         callback: [ :v | offsetX contents: v asNumber ] value: (((SUElement on: html) id: 'workflow') property:'offsetLeft');
>           callback: [ :v | graphFormClickX := v asNumber - offsetX contents ] value: SUEvent new x;
>           callback: [ :v | graphFormClickY := v asNumber - offsetY contents ] value: SUEvent new y);
>       onClick: (html updater id: 'co-ordinates'; on: #renderCoordinatesOn: of: self );
>       form: graphForm "; height: (form height // self scaleDownFactor); width: (form width // self scaleDownFactor)"
>       "] "

--
Lukas Renggli
http://www.lukas-renggli.ch
_______________________________________________
Seaside mailing list
[hidden email]
http://lists.squeakfoundation.org/cgi-bin/mailman/listinfo/seaside
Reply | Threaded
Open this post in threaded view
|

Re: Problem with Scriptaculous

Lukas Renggli
> 2. You can improve the performance of your example by combining the
> two #updater together. The first of your #updater is not really an
> #updater, it does not update anything. The #requestor would do here as
> well. I suggest to combine them to something like:
>
>     html updater
>          id: 'co-ordinates';
>          callback: [ :v | ... ] value: ...;
>          callback: [ :v | ... ] value: ...;
>          callback: [ :v | ... ] value: ...;
>          callback: [ :v | ... ] value: ...;
>          on: #renderCoordinatesOn: of: self

Sorry, I just noticed that this is even required to make it correct.
Since all AJAX actions are synchronous (the A in AJAX), there is no
guarantee that the first #updater will finish before the second one.
So you have to combine the two into one, or use the completion event
of the first to trigger the second.

Lukas

--
Lukas Renggli
http://www.lukas-renggli.ch
_______________________________________________
Seaside mailing list
[hidden email]
http://lists.squeakfoundation.org/cgi-bin/mailman/listinfo/seaside
Reply | Threaded
Open this post in threaded view
|

Re: Problem with Scriptaculous

Lukas Renggli
In reply to this post by Lukas Renggli
> Looking at the resultant javascript I worked out roughly what was going on.
>
> ((SUElement on: html) id: 'workflow'_ property:' offsetTop')
>
> was generating something like Element('workflow').toggle['offsetTop']
>
> The first time it would not work (well it would not get the correct
> answer), the second time it did. Does this make any sense?

Oups, I missed that. In this case it makes sense. The first time you
toggle it gets hidden and therefor returns the wrong result (a hidden
element has offset 0). The second time it gets shown again and the new
offset is read. I just wonder why I didn't observe that yesterday when
I tried it out :-/

> I could not find a way to get rid of the call to toggle, and even when I
> hacked the code to allow SUElement-#method to return nil,
> Element('workflow)['offsetTop'] didnt seem to work. So I ended up using

Yes these default methods are nasty. This is not the first time I got
bitten. These methods date back to the very first versions of
Scriptaculous, where the JavaScript framework was not that composable
at all. Nowadays this sort of contradicts the free composability of
the elements. I will try to refactor that, let's see if this can be
done without breaking some older code.

The problem is that offsetTop is not a Scriptaculous method, but one
from DOM. Therefor it cannot be written the same way other
Scriptaculous functions can. The shortest form would probably be:

    $('id1').offsetTop

> I didnt receive a fileOut with your email.

Sorry, I forgot to attach it and now I don't have it anymore. Anyway,
I described my changes in the mail.

> I do want to update several things perhaps 5 items, not just the
> co-ordinates, is that achievable using this scheme?
>
> e.g.
>
>      onClick: (html updater id: 'co-ordinates'; on:
> #renderCoordinatesOn: of: self );
>         onClick: (html updater id: 'workflow-focus'; on: #renderFocusOn:
> of: self );

Yes that's possible but highly inefficient (5 independent requests)
and there is no guarantee of the order in which all these updates will
be performed. So I suggest that you use the evaluator, that is made to
do such complicated things in one go (one single request):

   onClick: (html evaluator

      " data pushed to the server "
      callback: [ :v | ... ] value: ...;
      callback: [ :v | ... ] value: ...;
      callback: [ :v | ... ] value: ...;
      ...

      " response script s sent back to the client
        (in this case the contents of id1..id3 is updated) "
      callback: [ :s |
          s element id: 'id1'; render: [ :r | ... ].
          s element id: 'id2'; render: [ :r | ... ].
          s element id: 'id3'; render: [ :r | ... ].
          ... ])


HTH,
Lukas

--
Lukas Renggli
http://www.lukas-renggli.ch
_______________________________________________
Seaside mailing list
[hidden email]
http://lists.squeakfoundation.org/cgi-bin/mailman/listinfo/seaside
Reply | Threaded
Open this post in threaded view
|

Re: Problem with Scriptaculous

Lukas Renggli
> > I could not find a way to get rid of the call to toggle, and even when I
> > hacked the code to allow SUElement-#method to return nil,
> > Element('workflow)['offsetTop'] didnt seem to work. So I ended up using
>
> Yes these default methods are nasty. This is not the first time I got
> bitten. These methods date back to the very first versions of
> Scriptaculous, where the JavaScript framework was not that composable
> at all. Nowadays this sort of contradicts the free composability of
> the elements. I will try to refactor that, let's see if this can be
> done without breaking some older code.

I published a first try at this refactoring. If you are on Seaside 2.8
you can give it a try, it should be now much simpler to do what you
want. Also the generated JavaScript is simpler and the overal design,
so I think it is a good thing.

Name: Scriptaculous-lr.198
Author: lr
Time: 11 June 2007, 8:10:32 am
UUID: 8a051271-9d8f-4ade-a25e-f499d5c569a8
Ancestors: Scriptaculous-lr.197

- refactored Element, Form and FormElement to be more extensible and
to better match the new way of prototype programming
- fixed and updated some tests
- added some missing actions
- WARNING: these elements don't have default actions anymore

--
Lukas Renggli
http://www.lukas-renggli.ch
_______________________________________________
Seaside mailing list
[hidden email]
http://lists.squeakfoundation.org/cgi-bin/mailman/listinfo/seaside
Reply | Threaded
Open this post in threaded view
|

Re: Re: Problem with Scriptaculous

Stuart Herring-3
> I published a first try at this refactoring. If you are on Seaside 2.8
> you can give it a try, it should be now much simpler to do what you
> want. Also the generated JavaScript is simpler and the overal design,
> so I think it is a good thing.
>
> Name: Scriptaculous-lr.198
Excellent - I was attempting to do something similar myself.

I've published changes (Scriptaculous-srh.199) based on that version
to enable the Enumerable methods on SUElement, plus refactor
SUSelector so as to avoid duplication.

Regards,
Stuart.
_______________________________________________
Seaside mailing list
[hidden email]
http://lists.squeakfoundation.org/cgi-bin/mailman/listinfo/seaside