[Seaside] [ENH] HandyComponent

miso.list at auf.net miso.list at auf.net
Wed Mar 24 18:04:52 CET 2004


A simple utility to make it easier/faster/nicer to work with Seaside
component, that I have come to rely on. Feedback welcome. From the
class comment:

--

Adds a few simple and handy utilities to your components:

* a 'finite state machine': Seaside components are mostly restricted
to rendering one page (#renderContentsOn:). This is often suboptimal
design-wise, where one component (eg. PersonEditor) would ideally have
all responsability for its area (eg. #displayPerson, #editPerson,
#changePassword, etc.). HandyComponent allows you to do that by
specifying what 'state' the component is in via e.g. 'self state:
#editPerson'. On the next rendering cycle, this will automatically
call the #editPerson method in your component (see #renderContentOn:).
A link to 'edit' the person would thus be: 
  self anchorWithAction: [self state: #editPerson] text: 'edit'. 
The nil state triggers #proposeMainMenu, which does nothing by default
This is the primary place that your subclass should override to fit
your needs.

* a cache for the html canvas. This allows your rendering methods to
be of the type #displayPerson, #editPerson rather than
#displayPersonOn:, #editPersonOn:, etc. A small matter of taste, but I
found it surprisingly more readable!

* a <temps> dictionary mainly intended as a place to collect values of
a form for later checking and processing. It also gives the
convenience method #contentsOfTemp: which does some elementary
checking to ensure that the variable has some content, allowing the
pattern:
(self contentsOfTemp: #username) ifNotNilDo: [:val | ... ]

* a simple error handling mechanism for form processing: while
validating the form arguments, simply note each error by calling
#userError: . This adds the error to a list of errors. At the end of
validation, say 'self errors ifNotEmpty: [^self]. On the next
rendering cycle, the errors will be automatically shown to the user,
together with an explanation that the back button should be used to go
back to editing.

-------------- next part --------------
'From Squeak3.6 of ''6 October 2003'' [latest update: #5429] on 24 March 2004 at 11:42:28 am'!
WAComponent subclass: #HandyComponent
	instanceVariableNames: 'html state argument temps errors '
	classVariableNames: ''
	poolDictionaries: ''
	category: 'Seaside-Enh'!
!HandyComponent commentStamp: 'miso 3/24/2004 11:40' prior: 0!
Adds a few simple and handy utilities to your components:

* a 'finite state machine': Seaside components are mostly restricted to rendering one page (#renderContentsOn:). This is often suboptimal design-wise, where one component (eg. PersonEditor) would ideally have all responsability for its area (eg. #displayPerson, #editPerson, #changePassword, etc.). HandyComponent allows you to do that by specifying what 'state' the component is in via e.g. 'self state: #editPerson'. On the next rendering cycle, this will automatically call the #editPerson method in your component. Thus the link to 'edit' the person would be: self anchorWithAction: [self state: #editPerson] text: 'edit'. The nil state triggers #proposeMainMenu, which does nothing by default (see #renderContentOn: and #proposeMainMenu). Override #proposeMainMenu to your needs. 

* a cache for the html canvas. This allows your rendering methods to be of the type #displayPerson, #editPerson rather than #displayPersonOn:, #editPersonOn:, etc. A small matter of taste, but I found it surprisingly more readable!!

* a <temps> dictionary mainly intended as a place to collect values of a form for later checking and processing. It also gives the convenience method #contentsOfTemp: which does some elementary checking to ensure that the variable has some content.

* a simple error handling mechanism for form processing: while validating the form arguments, simple note each error by calling #userError: . This adds them to a list of errors. At the end of validation, say 'self errors ifNotEmpty: [^self]. On the next rendering cycle, the errors will be automatically shown to the user, together with an explanation that the back button should be used to go back to editing.
!


!HandyComponent methodsFor: 'action/argument' stamp: 'miso 1/26/2004 21:17'!
arguments

^ argument
! !

!HandyComponent methodsFor: 'action/argument' stamp: 'miso 1/26/2004 21:17'!
arguments: arg

argument _ arg
! !

!HandyComponent methodsFor: 'action/argument' stamp: 'miso 1/26/2004 21:16'!
proposeMainMenu
"do nothing by default"! !

!HandyComponent methodsFor: 'action/argument' stamp: 'miso 3/23/2004 18:10'!
renderContentOn: aCanvas

html _ aCanvas.

errors isEmpty ifFalse: [^self showErrors].
self state 
	ifNil: [self proposeMainMenu]
	ifNotNil: [self perform: self state withArguments: self arguments]
! !

!HandyComponent methodsFor: 'action/argument' stamp: 'miso 3/24/2004 11:23'!
state

^ state
! !

!HandyComponent methodsFor: 'action/argument' stamp: 'miso 3/24/2004 11:42'!
state: aSymbol

state _ aSymbol.
self arguments: {}. "state was changed, so reset arguments. This can be potentially misleading if someone sets the arguments before changing the state... But it avoids a series of bugs where one transitions to a state without arguments, but forgets to zap the old arguments. No-argument states being a frequent pattern, this seems worth the tradeoff"
! !

!HandyComponent methodsFor: 'action/argument' stamp: 'miso 3/24/2004 11:24'!
state: aSymbol argument: anObject

^ self state: aSymbol arguments: {anObject}! !

!HandyComponent methodsFor: 'action/argument' stamp: 'miso 3/24/2004 11:24'!
state: aSymbol arguments: anArray

self state: aSymbol.
self arguments: anArray! !


!HandyComponent methodsFor: 'errors' stamp: 'miso 3/24/2004 11:27'!
errors

^ errors! !

!HandyComponent methodsFor: 'errors' stamp: 'miso 3/24/2004 11:26'!
showErrors

html text: 'Please corrrect the following errors. Use the back button in your browser to go back to editing your data and correcting the errors'.
html list: self errors do: [:error |
	html attributes color: 'blue'.
	html font: [html text: error]].
errors _ OrderedCollection new.! !

!HandyComponent methodsFor: 'errors' stamp: 'miso 1/26/2004 21:35'!
userError: aString

errors addLast: aString
! !


!HandyComponent methodsFor: 'misc' stamp: 'miso 3/24/2004 11:27'!
contentsOfTemp: aKey
"utility for form processing. Ideally should be able to call 'aValue contents' with #contents implemented in string/nil"

| val |
val _ temps at: aKey ifAbsent: [].
val ifNil: [^nil].
val _ val withBlanksTrimmed.
^ val isEmpty ifTrue: [] ifFalse: [val]! !

!HandyComponent methodsFor: 'misc' stamp: 'miso 1/26/2004 21:17'!
initialize

self arguments: Array new.
errors _ OrderedCollection new.
temps _ Dictionary new.! !


More information about the Seaside mailing list