PackageDescription: Seaside-Gadgets


Seaside - Gadgets

Last published: March 26, 2009 by 'tkogan'

Defines 20 Classes
Extends 22 Classes


Seaside-Gadgets is a set of widgets, nicknamed 'Gadgets' in this package. They are built on top of Seaside-Mootools using the Mootools Javascript library.

Overview
This package is a compliment to the Seaside-Mootools package and provides a set of "gadgets" that are built on top of Mootools. This is sort of like a widget library. The Seaside-Mootools package tries not to define any particular idiom for using Mootools, while this package sets out a specific way that the javascript and running Seaside server can communicate in an efficient manner.

More gadgets will be added to this package on an as-needed basis.

Usage
The various gadgets are added to the canvas, so you can use them by calling a method and they work like regular HTML elements, however by design the gadgets are generally ajax driven, using the CommunicationGadget behavior to drive interaction between Seaside and the web browser.

The philosophy is of RPC. Each gadget can contain both Smalltalk and Javascript side by side (it can also contain CSS where appropriate). You write the Javascript code on the class like you would Smalltalk code. When MootoolsLibrary is included, the javascript from these classes is transformed in to Mootools classes and installed on the client for the current web session.

Because the Smalltalk and Javascript methods are built side by side in the traditional Smalltalk approach, it is appropriate that the Javascript be able to call the Smalltalk code with little arm twisting. (It is currently not possible for the Smalltalk code to call Javascript methods, though there are techniques to achieve this that may be implemented at a later date).

There are pragmas you can place inside Smalltalk methods that tell the javascript generator that you want to be able to call the Smalltalk method from Javascript. Here is an example:

ping: message

^Timestamp now printString, ' - ', message

alertPing() {
alert(this.ping("from the client!"))
}

In the above example, the javascript generator will create a client side ping(message) method which will call the server through a Seaside callback. It will serialize the parameters as a JSON message object, which looks a lot like a Smalltalk Message object. The object is deserialized on the Smalltalk side - and if the message selector includes the pragma (as in, make this a javascript function() please), it will call the message. The resulting object is then serialized back in to JSON and returned to the client as the response.

There are a few variations on what you can do with the pragma, where the parameter specifies which type of function callback you want to perform. The list is here:
#send -- this is the default
#async -- don't expect a result at all, fork it off and forget about it
#refresh -- expect that the response will contain html and javascript properties to be applied to the current page
#popup -- expect that the response will contain html and javascript properties to be placed in a Mootools-Mocha popup window
#dialog -- expect that the response will contain html and javascript properties to be placed in a Mootools-Mocha dialog

Naturally the javascript calling the method can rightly expect whatever it is you want to send it from the Smalltalk image, but the above idioms of #refresh and #dialog are very common. The response for a #refresh is quite special. It is a set of XML tags that may or may not include id's. Inside the #refresh logic, it assumes that if one of the tags includes an id, you want to replace the existing element with the same id with this new tag. If it doesn't have an id, it assumes you want to place that content at the end of the current element.

The #refresh logic is not set in stone, you can just as easily have the javascript call a Smalltalk method that returns html and javascript, and then apply the resulting tags anywhere you want on the page without letting the server decide for itself. Examples of this in action are ToggleBox and ContextMenu.

When the Smalltalk method is called, it does not have a HTMLCanvas to render on to - however it is a Seaside Brush and has access to the last canvas. From that, you can create a new canvas to render on, then serialize the response out as the result to the ajax call. This sounds more complex than it is:

myServersideMethod

^self newRendererDo: [:html | html text: 'Hello!']

Because this simply creates a dictionary containing the resulting html and javascript, you can actually return more information to the client, or indeed do multiple disperate renderings and return all of them. The javascript code would have to interpret this response of course.

Architecture
Each Gadget is a mesh between Smalltalk code, Javascript code and CSS code. The Javascript code is installed as a Mootools Class object from the Seaside-Mootools package and they are based off of the MooBrush class which allows Javascript and CSS to be written as normal methods along side Smalltalk code. The simplicity of javascript coding next to Smalltalk coding makes development of new "gadgets" very easy.