Javascript rendering and dynamically bound variables

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

Javascript rendering and dynamically bound variables

Mariano Montone
Hi,
     I'm developing a GoogleMaps component and have to decide how to
implement the Javascript generation.

The thing is I'm using a dynamically bound variable to hold the stream
to render the javascript on and I'm not sure that's considered good
style in Seaside.

For those who are not familiar with dynamically bound variables, here
are some documents that explain them briefly:
http://www.psg.com/~dlamkins/sl/chapter08.html
http://www.flownet.com/ron/specials.pdf

In seaside they are used to access the current session (se WACurrentSession).
Besides, they are a feature extensively used in other languages like Common
Lisp (and with the same purpose I am considering using them for).

I need to generate Javascript and keep some bindings from the Smalltalk side
of the generated Javascript variables. So, for example, this is what I have
now:

WADraggableMarkerMap>>renderContentOn: html
       
        self map
                center: 45.5267 @ -122.8390 zoom: 11;
                setUIToDefault.
       
        marker := (GMarker at: 45.5267 @ -122.8390)
                              draggable: true;
                              onDrag: ( html gmrequest callback: [:latlng | marker
color: GColor blue ]).
        self map addOverlay: marker.

In the code above, I'm rendering map and then create a marker and add
it to the map. Both the GMarker instantiation and the attributes
settings must generate javascript.

The generated javascript is the following:

var map1=new google.maps.Map2(document.getElementById("id3"),mapOptions);
map1.setCenter(new GLatLng(45.5267,-122.839), 11);
map1.setUIToDefault();
window.map1_marker1 = new GMarker(new GLatLng(45.5267,-122.839), {
draggable : true });
GEvent.addListener(window.map1_marker1, "drag", function(location){
          new Ajax.Request('http://localhost:8080/seaside/GM+maps',{'parameters':
             ['_s=FHmCjhjBaPWtVZif','_k=qdFCjsRt','1','2='+location].join('&')})});
map.addOverlay(window.map1_marker1);

Note that the marker variable in the Smalltalk code is an instance
variable and holds its javascript variable name (window.map1_marker1).
That lets me refer to the marker added to the map later. For example,
in the code above, when the user drags the marker, the callback
setting the marker's color is called. That callback generates
javascript to be executed as a response to the dragging. In
particular, the following javascript is executed:

window.map1_marker1.setColor(GColor blue);

To achieve the same giving up to dynamic variables and sticking to
Seaside brushes would require my protocol to change to something
similar to this:

marker := (GMarker at: 45.5267 @ -122.8390)
                              draggable: true;
                              onDrag: ( html gmrequest callback: [:latlng : renderer |
                                   marker color: GColor blue.
                                   marker renderOn: renderer ]).

That is to say, I have to explicitely render each of my variables to
the lexically scoped renderer. Besides, there's a renderer variable
apart from the arguments that are interesting to the callback (latlng
in this case, that holds the position the marker was dragged to).

As for the implementation with dynamic variables, the javascript is
being rendered on a dynamically bound stream, that is set in a Seaside
decoration:

WAGMapComponentDecoration>>renderContentOn: html
        |brush|

        brush := html googleMap
                        class: 'googleMap';
                        style: self component mapStyle;
                        yourself.
        self component brush: brush.
        WACurrentJSStream use: brush stream
                                       during: [ self component renderContentOn: html ]

To sum up, on the one hand, this approach is not the way Seaside
commonly renders
Javascript or HTML. On the other hand, my opinion is that using
brushes spoils the protocol at a certain extent, but I would like to
hear your opinions here.

What do you think? Can you come up with other alternatives? Which approach
do you prefer over the other and why?

Sorry for the long post, but couldn't find a way of explaining my
problem more briefly.

Thank you very much!

Mariano
_______________________________________________
seaside mailing list
[hidden email]
http://lists.squeakfoundation.org/cgi-bin/mailman/listinfo/seaside
Reply | Threaded
Open this post in threaded view
|

Re: Javascript rendering and dynamically bound variables

Lukas Renggli
> The thing is I'm using a dynamically bound variable to hold the stream
> to render the javascript on and I'm not sure that's considered good
> style in Seaside.

The use of dynamic variables is not that common in Smalltalk as it is
in lisp-like languages, but it is certainly an option. Dynamic
variables have their price, for a benchmark check Table 5 in
<http://scg.unibe.ch/archive/papers/Denk07cChangeboxes.pdf>.

> What do you think? Can you come up with other alternatives? Which approach
> do you prefer over the other and why?

You might want to check out the Scriptaculous and JQuery bindings for
Seaside. These libraries don't use a global stream object, but instead
the the stream is passed into #printOn: that recursively traverses a
tree of objects to generate the Javascript code.

Cheers,
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: Javascript rendering and dynamically bound variables

Sebastian Sastre-2
In reply to this post by Mariano Montone
>Can you come up with other alternatives?
> Which approach
> do you prefer over the other and why?
>
>
Hi Mariano,
I don't know if this helps you but I've also faced that need and not having the
canvas at the time.
I've solved it by making script renderers which are blocks that returns a
rendered script when you eval them with a canvas.
Instead of rendering directly, this family of components can preset arbitrary
script renderers that will be rendered when appropiate and have their arbitrary
javascript.

Simplifying my real framework, the basic render is something like:

renderContentOn: html

        html div
                id: self id; "every component has a unique id"
                with: [self renderPresenterContentOn: html]; "I call presenters
this kind of seaside components"
                yourself.

        html script: (self renderScriptsOn: html)

and a simplified version of:

renderScriptsOn: html

        "not all presenters inject javascript only those
        who needs the homologue dom element initialized
        with some functions and js stuff"
        self hasToInitializeHomologue ifTrue:[
                html script with: (self renderAllScriptsOn: html)]

               
the custom rendering of the componet for this family happens inside
#renderPresenterContentOn:
cheers,
sebastian

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