Seaside-Component


Seaside-Component Comment
WAAnswerHandler

WAComponent
I am a class representing a graphical element of a seaside application. A component has state (instance variables, that might be backtracked using #registerObjectForBacktracking:), behavior decorations, children and an appearance that is specified in #renderContentOn:. A component might chose to display another component with #call:.

Child Components:
It is common for a component to display instances of other components while rendering itself.  It does this by passing them into the #render: method of WAHtmlRenderer.  For example, this #renderContentOn: method simply renders a heading and then displays a counter component 
immediately below it:

	renderContentOn: html
		html heading: 'My Counter' level: 3.
		html render: myCounter.

It's important that you use #render:, rather than directly calling the #renderContentOn: method of the subcomponent. The following is *not* correct:

	renderContentOn: html
		html heading: 'My Counter' level: 3.
		myCounter renderContentOn: html.   "DON'T DO THIS".

These subcomponents are usually instance variables of the component that is "embedding" them.  They are commonly created as part of the components #initialize method:

	initialize
		myCounter := WACounter new.

They may also be stored in a collection. One fairly common pattern is to keep a lazily initialized dictionary of subcomponents that match a collection of model items. For example, if you wanted a BudgetItemRow subcomponent for each member of budgetItems, you might do something like this:

	initialize
		budgetRows := Dictionary new.

	rowForItem: anItem
		^budgetRows at: anItem ifAbsentPut: [ BudgetItemRow item: anItem ].

	renderContentOn: html
		self budgetItems
			do: [ :each | html render: (self rowForItem: each) ]
			separatedBy: [ html horizontalLine ].

Each parent component *must* implement a #children method that returns a collection of all of the subcomponents that it might display on the next render. For the above two examples, #children might look like this:

	children
		^Array with: myCounter

or this:

	children
		^self budgetItems collect: [ :each | self rowForItem: each ].
		
Call/Answer:
If a subcomponent makes a #call: to another component, that component will appear in place of the subcomponent.  In the first example, if myCounter made a #call: to DateSelector, that DateSelector would appear in the context of the counter's parent, with the 'My Counter' heading 
above it.

Since a subcomponent has not been #call:'d, in general #answer: is a no-op.  However, the parent may attach an #onAnswer: block to the subcomponent to be notified if it sends #answer:. This allows one component to be used both from #call: and through embedding. For example:

	initialize
		dateSelector := WADateSelector new 
			onAnswer: [ :date | self dateChosen: date ].
WADecoration
I am an abstract decoration around instances of WAComponent. I can be added to aComponent by calling #addDecoration: and I change the basic behaviour or look of a component. There are several methods that can be overriden to archive this:

- #renderContentOn: to emit xhtml around the decorated component. Call #renderOwnerOn: to let the owner emit its output.

- #processChildCallbacks: to intercept the callback processing of the owner.

- #handleAnswer: to intercept the answer processing.
WADelegation

WAPresenter

WATask
I am a subclass of WAComponent, specialized for defining workflow.  The difference between a task and a component is the following:

Both of them are reusable, embeddable, callable pieces of user interface. A component has state (instance variables), behavior (it may change its state, and it may also choose to display other components with #call:), and appearance (it renders HTML). A Task has only the first two - it doesn't render any HTML directly, but only through the components it calls. This is useful when what you want to encapsulate/embed/call is purely a process (show this component, then this one, then this one).

The key method for WATask is #go - as soon as a task is displayed, this method will get invoked, and will presumably #call: other components.

In terms of implementation, you can think of a WATask in the following way: it is a component which renders two things:
- a link whose callback invokes the #go method
- a header that immediately redirects to the URL of that link

^top


- made by Dandelion -