<?xml version="1.0"?>

<st-source>
<!-- 
Name: MewaForSeaside
Notice: All rights reserved
BundleName: MewaForSeaside
Comment: Mewa: Meta-level Architecture for Generic Web-Application Construction

Part of Seaside Bonus Pack version SeasideBonusPack 2.7b1.1.0   8 August 2007, 15:14:13 pm

Mewa: Meta-level Architecture for Generic Web-Application Construction.
Author: Adrian Lienhard, Netstyle CH http://www.netstyle.ch
Technical Report: http://www.adrian-lienhard.ch/files/mewa.pdf

Ported from Squeak by Michel Bany [mbany@cincom.com]
Ported from Mewa.Seaside2.5-al.24.mcz

DevelopmentPrerequisites: #(#(#any 'SeasideBase' ''))
Parcel: #('MewaForSeaside')
ParcelName: MewaForSeaside
PrerequisiteParcels: #(#('SeasideBase' ''))
Version: 2.5-24
Date: 2:52:20 pm August 8, 2007
 -->
<time-stamp>From VisualWorks®, 7.5 of April 16, 2007 on August 8, 2007 at 2:52:20 pm</time-stamp>


<do-it>(Dialog confirm: 'You are filing-in a Parcel source file!\\While this is possible it will not have\the same effect as loading the parcel.\None of the Parcel''s prerequisites will\be loaded and none of its load actions\will be performed.\\Are you sure you want to file-in?' withCRs) ifFalse: [self error: 'Parcel file-in abandoned.  Choose terminate or close.']</do-it>

<class>
<name>MWExample</name>
<environment>Seaside</environment>
<super>Seaside.WAComponent</super>
<private>false</private>
<indexed-type>none</indexed-type>
<inst-vars>batcher children </inst-vars>
<class-inst-vars></class-inst-vars>
<imports></imports>
<category>Mewa-Example</category>
<attributes>
<package>Mewa-Example</package>
</attributes>
</class>

<class>
<name>MWAttribute</name>
<environment>Seaside</environment>
<super>Core.Object</super>
<private>false</private>
<indexed-type>none</indexed-type>
<inst-vars>selector metaObject cache label validationRules itemFormatBlock readOnly hidden formCssClass </inst-vars>
<class-inst-vars></class-inst-vars>
<imports></imports>
<category>Mewa-Metaobject</category>
<attributes>
<package>Mewa-Metaobject</package>
</attributes>
</class>

<class>
<name>MWRelationshipAttribute</name>
<environment>Seaside</environment>
<super>Seaside.MWAttribute</super>
<private>false</private>
<indexed-type>none</indexed-type>
<inst-vars>itemCollectionBlock linkAction </inst-vars>
<class-inst-vars></class-inst-vars>
<imports></imports>
<category>Mewa-Metaobject</category>
<attributes>
<package>Mewa-Metaobject</package>
</attributes>
</class>

<class>
<name>MWExampleSession</name>
<environment>Seaside</environment>
<super>Seaside.WASession</super>
<private>false</private>
<indexed-type>none</indexed-type>
<inst-vars></inst-vars>
<class-inst-vars></class-inst-vars>
<imports></imports>
<category>Mewa-Example</category>
<attributes>
<package>Mewa-Example</package>
</attributes>
</class>

<class>
<name>MWMultipleAttribute</name>
<environment>Seaside</environment>
<super>Seaside.MWAttribute</super>
<private>false</private>
<indexed-type>none</indexed-type>
<inst-vars>baseClass linkAction </inst-vars>
<class-inst-vars></class-inst-vars>
<imports></imports>
<category>Mewa-Metaobject</category>
<attributes>
<package>Mewa-Metaobject</package>
</attributes>
</class>

<class>
<name>MWTextAttribute</name>
<environment>Seaside</environment>
<super>Seaside.MWAttribute</super>
<private>false</private>
<indexed-type>none</indexed-type>
<inst-vars>multiLine maxLength </inst-vars>
<class-inst-vars></class-inst-vars>
<imports></imports>
<category>Mewa-Metaobject</category>
<attributes>
<package>Mewa-Metaobject</package>
</attributes>
</class>

<class>
<name>MWUrlAttribute</name>
<environment>Seaside</environment>
<super>Seaside.MWTextAttribute</super>
<private>false</private>
<indexed-type>none</indexed-type>
<inst-vars></inst-vars>
<class-inst-vars></class-inst-vars>
<imports></imports>
<category>Mewa-Metaobject</category>
<attributes>
<package>Mewa-Metaobject</package>
</attributes>
</class>

<class>
<name>MWPerson</name>
<environment>Seaside</environment>
<super>Core.Object</super>
<private>false</private>
<indexed-type>none</indexed-type>
<inst-vars>firstname male birthday father mother interests phoneNumbers </inst-vars>
<class-inst-vars></class-inst-vars>
<imports></imports>
<category>Mewa-Example</category>
<attributes>
<package>Mewa-Example</package>
</attributes>
</class>

<class>
<name>MWMultipleRelationshipAttribute</name>
<environment>Seaside</environment>
<super>Seaside.MWRelationshipAttribute</super>
<private>false</private>
<indexed-type>none</indexed-type>
<inst-vars></inst-vars>
<class-inst-vars></class-inst-vars>
<imports></imports>
<category>Mewa-Metaobject</category>
<attributes>
<package>Mewa-Metaobject</package>
</attributes>
</class>

<class>
<name>MWDomainModel</name>
<environment>Seaside</environment>
<super>Core.Object</super>
<private>false</private>
<indexed-type>none</indexed-type>
<inst-vars>persons </inst-vars>
<class-inst-vars></class-inst-vars>
<imports></imports>
<category>Mewa-Example</category>
<attributes>
<package>Mewa-Example</package>
</attributes>
</class>

<class>
<name>MWTimeAttribute</name>
<environment>Seaside</environment>
<super>Seaside.MWAttribute</super>
<private>false</private>
<indexed-type>none</indexed-type>
<inst-vars></inst-vars>
<class-inst-vars></class-inst-vars>
<imports></imports>
<category>Mewa-Metaobject</category>
<attributes>
<package>Mewa-Metaobject</package>
</attributes>
</class>

<class>
<name>MWPasswordAttribute</name>
<environment>Seaside</environment>
<super>Seaside.MWTextAttribute</super>
<private>false</private>
<indexed-type>none</indexed-type>
<inst-vars>cacheConfirmation </inst-vars>
<class-inst-vars></class-inst-vars>
<imports></imports>
<category>Mewa-Metaobject</category>
<attributes>
<package>Mewa-Metaobject</package>
</attributes>
</class>

<class>
<name>MWMultipleAttributeContainer</name>
<environment>Seaside</environment>
<super>Seaside.WAComponent</super>
<private>false</private>
<indexed-type>none</indexed-type>
<inst-vars>attribute components </inst-vars>
<class-inst-vars></class-inst-vars>
<imports></imports>
<category>Mewa-Components</category>
<attributes>
<package>Mewa-Components</package>
</attributes>
</class>

<class>
<name>MWVisitor</name>
<environment>Seaside</environment>
<super>Seaside.WAComponent</super>
<private>false</private>
<indexed-type>none</indexed-type>
<inst-vars>metaobject </inst-vars>
<class-inst-vars></class-inst-vars>
<imports></imports>
<category>Mewa-Visitors</category>
<attributes>
<package>Mewa-Visitors</package>
</attributes>
</class>

<class>
<name>MWViewerVisitor</name>
<environment>Seaside</environment>
<super>Seaside.MWVisitor</super>
<private>false</private>
<indexed-type>none</indexed-type>
<inst-vars>renderer </inst-vars>
<class-inst-vars></class-inst-vars>
<imports></imports>
<category>Mewa-Visitors</category>
<attributes>
<package>Mewa-Visitors</package>
</attributes>
</class>

<class>
<name>MWEditorVisitor</name>
<environment>Seaside</environment>
<super>Seaside.MWVisitor</super>
<private>false</private>
<indexed-type>none</indexed-type>
<inst-vars>renderer validationErrors subForm multipleAttributeEditors </inst-vars>
<class-inst-vars></class-inst-vars>
<imports></imports>
<category>Mewa-Visitors</category>
<attributes>
<package>Mewa-Visitors</package>
</attributes>
</class>

<class>
<name>MWMailAttribute</name>
<environment>Seaside</environment>
<super>Seaside.MWTextAttribute</super>
<private>false</private>
<indexed-type>none</indexed-type>
<inst-vars></inst-vars>
<class-inst-vars></class-inst-vars>
<imports></imports>
<category>Mewa-Metaobject</category>
<attributes>
<package>Mewa-Metaobject</package>
</attributes>
</class>

<class>
<name>MWSingleRelationshipAttribute</name>
<environment>Seaside</environment>
<super>Seaside.MWRelationshipAttribute</super>
<private>false</private>
<indexed-type>none</indexed-type>
<inst-vars>nilItemString </inst-vars>
<class-inst-vars></class-inst-vars>
<imports></imports>
<category>Mewa-Metaobject</category>
<attributes>
<package>Mewa-Metaobject</package>
</attributes>
</class>

<class>
<name>MWBooleanAttribute</name>
<environment>Seaside</environment>
<super>Seaside.MWSingleRelationshipAttribute</super>
<private>false</private>
<indexed-type>none</indexed-type>
<inst-vars></inst-vars>
<class-inst-vars></class-inst-vars>
<imports></imports>
<category>Mewa-Metaobject</category>
<attributes>
<package>Mewa-Metaobject</package>
</attributes>
</class>

<class>
<name>MWPhoneNumber</name>
<environment>Seaside</environment>
<super>Core.Object</super>
<private>false</private>
<indexed-type>none</indexed-type>
<inst-vars>type number </inst-vars>
<class-inst-vars></class-inst-vars>
<imports></imports>
<category>Mewa-Example</category>
<attributes>
<package>Mewa-Example</package>
</attributes>
</class>

<class>
<name>MWListItemViewer</name>
<environment>Seaside</environment>
<super>Seaside.MWViewerVisitor</super>
<private>false</private>
<indexed-type>none</indexed-type>
<inst-vars></inst-vars>
<class-inst-vars></class-inst-vars>
<imports></imports>
<category>Mewa-Example</category>
<attributes>
<package>Mewa-Example</package>
</attributes>
</class>

<class>
<name>MWDateAttribute</name>
<environment>Seaside</environment>
<super>Seaside.MWAttribute</super>
<private>false</private>
<indexed-type>none</indexed-type>
<inst-vars></inst-vars>
<class-inst-vars></class-inst-vars>
<imports></imports>
<category>Mewa-Metaobject</category>
<attributes>
<package>Mewa-Metaobject</package>
</attributes>
</class>

<class>
<name>MWMetaobject</name>
<environment>Seaside</environment>
<super>Core.Object</super>
<private>false</private>
<indexed-type>none</indexed-type>
<inst-vars>baseobject attributes </inst-vars>
<class-inst-vars></class-inst-vars>
<imports></imports>
<category>Mewa-Metaobject</category>
<attributes>
<package>Mewa-Metaobject</package>
</attributes>
</class>

<shared-variable>
<name>MWModel</name>
<environment>Seaside.MWExampleSession</environment>
<private>false</private>
<constant>false</constant>
<category>class variables</category>
<initializer>nil</initializer>
<attributes>
<package>Mewa-Example</package>
</attributes>
</shared-variable>

<methods>
<class-id>Seaside.MWExample</class-id> <category>actions</category>

<body package="Mewa-Example" selector="addNew">addNew
	| newPerson |
	newPerson := self call: (MWEditorVisitor model: MWPerson new).
	newPerson ifNotNil: [
		self session domainmodel addPerson: newPerson.
		self initialize]</body>

<body package="Mewa-Example" selector="delete:">delete: aPerson
	(self confirm: 'Do you really want to delete ' , aPerson asString , '?')
		ifTrue: [ 
			self session domainmodel removePerson: aPerson.
			self initialize ]</body>

<body package="Mewa-Example" selector="edit:">edit: aPerson 
	self call: (MWEditorVisitor model: aPerson)</body>
</methods>

<methods>
<class-id>Seaside.MWExample</class-id> <category>accessing</category>

<body package="Mewa-Example" selector="children">children
	^children</body>

<body package="Mewa-Example" selector="style">style
	^ '
		body { font-size : 12px; font-family : Arial;  }
		.TABLE-LIST { width: 500; font-size: 12px; font-family: Arial; border: thin groove; }
	'</body>
</methods>

<methods>
<class-id>Seaside.MWExample</class-id> <category>initialization</category>

<body package="Mewa-Example" selector="initialize">initialize
	| views |
	super initialize.
	views := self session domainmodel persons asOrderedCollection collect: [ :each |
		MWListItemViewer metaobject: (
			each metaobject
				hideAttributeOf: #interests;
				hideAttributeOf: #phoneNumbers;
				yourself) ].

	batcher := WABatchedList new
		items: views;
		batchSize: 5;
		yourself.
	
	children := OrderedCollection new.
	views do: [ :each | children add: each ].
     children add: batcher</body>
</methods>

<methods>
<class-id>Seaside.MWExample</class-id> <category>rendering</category>

<body package="Mewa-Example" selector="renderContentOn:">renderContentOn: html
	html heading: self class.
	html cssClass: 'TABLE-LIST'.
	html table: [
		batcher batch do: [ :viewer | html tableRow: [
			html render: viewer.
			html tableData: [
				html
					anchorWithAction: [ self edit: viewer metaobject baseobject ]
					text: 'edit'; space;
					anchorWithAction: [ self delete: viewer metaobject baseobject ]
					text: 'delete' ] ] ].
		html attributeAt: #align put: #center.
		html tableRowWith: batcher span: 8 ].
		html break.
		html anchorWithAction: [ self addNew ] text: 'create new person'</body>

<body package="Mewa-Example" selector="rendererClass">rendererClass
	^WAHtmlRenderer</body>
</methods>

<methods>
<class-id>Seaside.MWExample class</class-id> <category>as yet unclassified</category>

<body package="Mewa-Example" selector="canBeRoot">canBeRoot
	^true</body>

<body package="Mewa-Example" selector="initialize">initialize
	(self registerAsApplication: 'mewa')
		preferenceAt: #sessionClass
		put: MWExampleSession</body>
</methods>

<methods>
<class-id>Seaside.MWAttribute</class-id> <category>visitor</category>

<body package="Mewa-Metaobject" selector="accept:">accept: aVisitor
	self subclassResponsiblity</body>
</methods>

<methods>
<class-id>Seaside.MWAttribute</class-id> <category>validation</category>

<body package="Mewa-Metaobject" selector="addRequiredRule">addRequiredRule
	self
		addValidationRule: [ :value | value notNil ]
		errorString: 'required'</body>

<body package="Mewa-Metaobject" selector="addValidationRule:">addValidationRule: aBlock
	self
		addValidationRule: aBlock
		errorString: 'not valid'</body>

<body package="Mewa-Metaobject" selector="addValidationRule:errorString:">addValidationRule: aBlock errorString: aString
	validationRules add: aBlock -&gt; aString</body>

<body package="Mewa-Metaobject" selector="validateCache">validateCache
	" validate cache and return nil if all rules hold or anErrorString of first broken rule "

	validationRules do: [ :association |
		(association key value: self cache)
			ifFalse: [ ^association value ] ].
	^nil</body>
</methods>

<methods>
<class-id>Seaside.MWAttribute</class-id> <category>caching</category>

<body package="Mewa-Metaobject" selector="cache">cache
	^cache</body>

<body package="Mewa-Metaobject" selector="cache:">cache: anObject 
	cache := anObject</body>

<body package="Mewa-Metaobject" selector="commitCache">commitCache
	self isReadOnly ifFalse: [
		self metaObject baseobject
			perform: (self selector,':') asSymbol
			with: self cache ]</body>

<body package="Mewa-Metaobject" selector="refreshCache">refreshCache
	cache := self value</body>
</methods>

<methods>
<class-id>Seaside.MWAttribute</class-id> <category>accessing</category>

<body package="Mewa-Metaobject" selector="formatedValue">formatedValue
	^self itemFormatBlock value: self value</body>

<body package="Mewa-Metaobject" selector="formCssClass">formCssClass
	^formCssClass</body>

<body package="Mewa-Metaobject" selector="itemFormatBlock">itemFormatBlock
	^itemFormatBlock</body>

<body package="Mewa-Metaobject" selector="metaObject">metaObject
	^metaObject</body>

<body package="Mewa-Metaobject" selector="metaObject:">metaObject: anObject
	metaObject := anObject</body>

<body package="Mewa-Metaobject" selector="selector">selector
	^selector</body>

<body package="Mewa-Metaobject" selector="selector:">selector: aSelector
	selector := aSelector</body>

<body package="Mewa-Metaobject" selector="value">value
	^self metaObject baseobject perform: self selector</body>
</methods>

<methods>
<class-id>Seaside.MWAttribute</class-id> <category>configuration</category>

<body package="Mewa-Metaobject" selector="formatWith:">formatWith: aBlock
	itemFormatBlock := aBlock</body>

<body package="Mewa-Metaobject" selector="hide">hide
	hidden := true</body>

<body package="Mewa-Metaobject" selector="label">label
	^label</body>

<body package="Mewa-Metaobject" selector="label:">label: aString
	label := aString</body>

<body package="Mewa-Metaobject" selector="readOnly">readOnly
	readOnly := true</body>
</methods>

<methods>
<class-id>Seaside.MWAttribute</class-id> <category>initialization</category>

<body package="Mewa-Metaobject" selector="initialize">initialize</body>

<body package="Mewa-Metaobject" selector="initializeWithSelector:">initializeWithSelector: aSymbol
	self selector: aSymbol.
	validationRules := OrderedCollection new.
	self label: self selector displayString.
	readOnly := false.
	hidden := false.
	self formatWith: [ :item | item ifNotNil: [ item displayString ] ].
	formCssClass := 'FORM-' , self selector asUppercase .
	self initialize.</body>
</methods>

<methods>
<class-id>Seaside.MWAttribute</class-id> <category>testing</category>

<body package="Mewa-Metaobject" selector="isHidden">isHidden
	^hidden</body>

<body package="Mewa-Metaobject" selector="isMultipleAttribute">isMultipleAttribute
	^false</body>

<body package="Mewa-Metaobject" selector="isReadOnly">isReadOnly
	^readOnly</body>
</methods>

<methods>
<class-id>Seaside.MWAttribute</class-id> <category>rendering</category>

<body package="Mewa-Metaobject" selector="renderContentOn:">renderContentOn: html
	

"	| attribute itemSelectedToEdit editForm |
	attribute cache do: [ :each | 
		(editors includesKey: each)
			ifFalse: [ self renderViewerFor: each ]
			ifTrue: [
				editForm := (MWEditorVisitor model: each) subForm: true.
				editForm onAnswer: [ :value | itemSelectedToEdit := nil ].
				html render: editForm ] ] fixTemps.
			html break.
			itemSelectedToEdit isNil ifTrue: [
				form := (MWEditorVisitor model: attribute baseClass new) subForm: true.
				form onAnswer: [ :value |
					value ifNotNilDo: [ :newBaseObject | attribute addToCache: newBaseObject ] ].
					html render: form ] ] ]"</body>
</methods>

<methods>
<class-id>Seaside.MWAttribute class</class-id> <category>instance creation</category>

<body package="Mewa-Metaobject" selector="for:">for: aSelector
	^self basicNew
		initializeWithSelector: aSelector;
		yourself</body>
</methods>

<methods>
<class-id>Seaside.MWRelationshipAttribute</class-id> <category>accessing</category>

<body package="Mewa-Metaobject" selector="items">items
	^itemCollectionBlock value</body>

<body package="Mewa-Metaobject" selector="linkAction">linkAction
	^linkAction</body>
</methods>

<methods>
<class-id>Seaside.MWRelationshipAttribute</class-id> <category>configuration</category>

<body package="Mewa-Metaobject" selector="linkAction:">linkAction: aSymbol
	linkAction := aSymbol</body>

<body package="Mewa-Metaobject" selector="relationshipTo:">relationshipTo: aBlock
	self
		relationshipTo: aBlock
		formatWith: [ :item | item asString ]</body>

<body package="Mewa-Metaobject" selector="relationshipTo:formatWith:">relationshipTo: aBlock formatWith: formatBlock
	itemCollectionBlock := aBlock.
	itemFormatBlock := formatBlock</body>
</methods>

<methods>
<class-id>Seaside.MWExampleSession</class-id> <category>accessing</category>

<body package="Mewa-Example" selector="domainmodel">domainmodel
	MWModel isNil ifTrue: [ MWModel := MWDomainModel new ].
	^MWModel</body>
</methods>

<methods>
<class-id>Seaside.MWMultipleAttribute</class-id> <category>visiting</category>

<body package="Mewa-Metaobject" selector="accept:">accept: aVisitor
	aVisitor visitMultipleAttribute: self</body>
</methods>

<methods>
<class-id>Seaside.MWMultipleAttribute</class-id> <category>caching</category>

<body package="Mewa-Metaobject" selector="addToCache:">addToCache: anObject
	cache add: anObject</body>

<body package="Mewa-Metaobject" selector="refreshCache">refreshCache
	cache := self value copy</body>

<body package="Mewa-Metaobject" selector="removeFromCache:">removeFromCache: anObject
	cache remove: anObject ifAbsent: []</body>
</methods>

<methods>
<class-id>Seaside.MWMultipleAttribute</class-id> <category>configuration</category>

<body package="Mewa-Metaobject" selector="baseClass">baseClass
	^baseClass</body>

<body package="Mewa-Metaobject" selector="baseClass:">baseClass: aDomainClass
	self
		baseClass: aDomainClass
		formatBlock: [ :item | item ]</body>

<body package="Mewa-Metaobject" selector="baseClass:formatBlock:">baseClass: aDomainClass formatBlock: aBlock
	baseClass := aDomainClass.
	self formatWith: aBlock</body>

<body package="Mewa-Metaobject" selector="linkAction:">linkAction: aSymbol
	linkAction := aSymbol</body>
</methods>

<methods>
<class-id>Seaside.MWMultipleAttribute</class-id> <category>accessing</category>

<body package="Mewa-Metaobject" selector="formatedValue">formatedValue
	^self value collect: [ :each |
		self itemFormatBlock value: each ]</body>

<body package="Mewa-Metaobject" selector="linkAction">linkAction
	^linkAction</body>
</methods>

<methods>
<class-id>Seaside.MWMultipleAttribute</class-id> <category>testing</category>

<body package="Mewa-Metaobject" selector="isMultipleAttribute">isMultipleAttribute
	^true</body>
</methods>

<methods>
<class-id>Seaside.MWTextAttribute</class-id> <category>visitor</category>

<body package="Mewa-Metaobject" selector="accept:">accept: aVisitor
	aVisitor visitTextAttribute: self</body>
</methods>

<methods>
<class-id>Seaside.MWTextAttribute</class-id> <category>validation</category>

<body package="Mewa-Metaobject" selector="addRequiredRule">addRequiredRule
	self
		addValidationRule: [ :value | value isEmptyOrNil not  ]
		errorString: 'required'</body>
</methods>

<methods>
<class-id>Seaside.MWTextAttribute</class-id> <category>caching</category>

<body package="Mewa-Metaobject" selector="cache">cache
	^super cache isNil
		ifTrue: [ String new ]
		ifFalse: [ super cache ]</body>
</methods>

<methods>
<class-id>Seaside.MWTextAttribute</class-id> <category>testing</category>

<body package="Mewa-Metaobject" selector="isMultiLine">isMultiLine
	^multiLine notNil and: [ multiLine ]</body>
</methods>

<methods>
<class-id>Seaside.MWTextAttribute</class-id> <category>configuration</category>

<body package="Mewa-Metaobject" selector="maxLength">maxLength
	^maxLength</body>

<body package="Mewa-Metaobject" selector="maxLength:">maxLength: aNumber
	maxLength := aNumber</body>

<body package="Mewa-Metaobject" selector="multiLine:">multiLine: aBoolean
	multiLine := aBoolean</body>
</methods>

<methods>
<class-id>Seaside.MWUrlAttribute</class-id> <category>as yet unclassified</category>

<body package="Mewa-Metaobject" selector="accept:">accept: aVisitor
	aVisitor visitUrlAttribute: self</body>
</methods>

<methods>
<class-id>Seaside.MWPerson</class-id> <category>accessing</category>

<body package="Mewa-Example" selector="age">age
	^self birthday isNil
		ifFalse: [ (Date today subtractDate: self birthday) // 365 ]
		ifTrue: [ String new ]</body>

<body package="Mewa-Example" selector="asString">asString
	^self firstname</body>

<body package="Mewa-Example" selector="birthday">birthday
	^birthday</body>

<body package="Mewa-Example" selector="birthday:">birthday: anObject
	birthday := anObject</body>

<body package="Mewa-Example" selector="father">father
	^father</body>

<body package="Mewa-Example" selector="father:">father: anObject
	father := anObject</body>

<body package="Mewa-Example" selector="firstname">firstname
	^firstname</body>

<body package="Mewa-Example" selector="firstname:">firstname: anObject
	firstname := anObject</body>

<body package="Mewa-Example" selector="interests">interests
	^interests</body>

<body package="Mewa-Example" selector="interests:">interests: anObject
	interests := anObject</body>

<body package="Mewa-Example" selector="male">male
	^male</body>

<body package="Mewa-Example" selector="male:">male: aBoolean
	male := aBoolean</body>

<body package="Mewa-Example" selector="metaobject">metaobject
	| metaobject |
	metaobject := MWMetaobject for: self.

	metaobject textAttribute: #firstname do: [ :attribute | 
		attribute
			label: 'Name';
			maxLength: 30;
			addRequiredRule ].

	metaobject dateAttribute: #birthday do: [ :attribute | 
		attribute
			label: 'Birthday';
			addRequiredRule ].

	metaobject textAttribute: #age do: [ :attribute | 
		attribute
			label: 'Age';
			readOnly ].

	metaobject booleanAttribute: #male do: [ :attribute | 
		attribute
			label: 'Sex';
			trueItemString: 'male' falseItemString: 'female' ].

	metaobject singleRelationshipAttribute: #father do: [ :attribute | 
		attribute
			label: 'Father';
			relationshipTo: [ WACurrentSession value domainmodel malePersons ]
				formatWith: [ :each | each firstname , ' (' , each sex , ')'];
			nilItemString: 'unknown' ].

	metaobject singleRelationshipAttribute: #mother do: [ :attribute | 
		attribute
			label: 'Mother';
			relationshipTo: [ WACurrentSession value domainmodel femalePersons ]
				formatWith: [ :each | each firstname , ' (' , each sex , ')' ];
			nilItemString: 'unknown' ].

	metaobject multipleRelationshipAttribute: #interests do: [ :attribute | 
		attribute
			label: 'Interests';
			relationshipTo: [ self class interests ] formatWith: [ :value | value , '!' ];
			addValidationRule: [ :collection | collection size &gt; 1 ]
				errorString: 'Select at least two interest items' ].

	metaobject multipleAttribute: #phoneNumbers do: [ :attribute | 
		attribute
			label: 'Phone Numbers';
			baseClass: MWPhoneNumber
				formatBlock: [ :item | item type , ': ' , item number] ].
	^metaobject</body>

<body package="Mewa-Example" selector="mother">mother
	^mother</body>

<body package="Mewa-Example" selector="mother:">mother: anObject
	mother := anObject</body>

<body package="Mewa-Example" selector="phoneNumbers">phoneNumbers
	^phoneNumbers</body>

<body package="Mewa-Example" selector="phoneNumbers:">phoneNumbers: anObject
	phoneNumbers := anObject</body>

<body package="Mewa-Example" selector="sex">sex
	^self male
		ifTrue: [ 'm' ]
		ifFalse: [ 'f' ]</body>
</methods>

<methods>
<class-id>Seaside.MWPerson</class-id> <category>initialization</category>

<body package="Mewa-Example" selector="initialize">initialize
	self firstname: String new.
	self male: true.
	self interests: Set new.
	self phoneNumbers: OrderedCollection new</body>
</methods>

<methods>
<class-id>Seaside.MWPerson class</class-id> <category>as yet unclassified</category>

<body package="Mewa-Example" selector="interests">interests
	^#(PHP Zope Struts Coffee Aubergines Sushi)</body>
</methods>

<methods>
<class-id>Seaside.MWPerson class</class-id> <category>instance creation</category>

<body package="Mewa-Patches" selector="new">new

	^(super new)
		initialize; 
		yourself</body>
</methods>

<methods>
<class-id>Seaside.MWMultipleRelationshipAttribute</class-id> <category>visitor</category>

<body package="Mewa-Metaobject" selector="accept:">accept: aVisitor
	aVisitor visitMultipleRelationshipAttribute: self</body>
</methods>

<methods>
<class-id>Seaside.MWMultipleRelationshipAttribute</class-id> <category>validation</category>

<body package="Mewa-Metaobject" selector="addRequiredRule">addRequiredRule
	self
		addValidationRule: [ :value | value isEmpty not ]
		errorString: 'required'</body>
</methods>

<methods>
<class-id>Seaside.MWMultipleRelationshipAttribute</class-id> <category>caching</category>

<body package="Mewa-Metaobject" selector="addToCache:">addToCache: aSelectedItem
	cache add: aSelectedItem</body>

<body package="Mewa-Metaobject" selector="cache">cache
	^cache asSet asOrderedCollection</body>

<body package="Mewa-Metaobject" selector="refreshCache">refreshCache
	cache := self value copy</body>

<body package="Mewa-Metaobject" selector="removeFromCache:">removeFromCache: aSelectedItem
	cache remove: aSelectedItem ifAbsent: []</body>
</methods>

<methods>
<class-id>Seaside.MWMultipleRelationshipAttribute</class-id> <category>accessing</category>

<body package="Mewa-Metaobject" selector="formatedValue">formatedValue
	^self value collect: [ :each |
		self itemFormatBlock value: each ]</body>
</methods>

<methods>
<class-id>Seaside.MWDomainModel</class-id> <category>as yet unclassified</category>

<body package="Mewa-Example" selector="addPerson:">addPerson: aPerson
	persons add: aPerson</body>

<body package="Mewa-Example" selector="femalePersons">femalePersons
	^self persons reject: [ :each | each male ]</body>

<body package="Mewa-Example" selector="initialize">initialize
	persons := Set new</body>

<body package="Mewa-Example" selector="malePersons">malePersons
	^self persons select: [ :each | each male ]</body>

<body package="Mewa-Example" selector="persons">persons
	^persons</body>

<body package="Mewa-Example" selector="removePerson:">removePerson: aPerson
	persons remove: aPerson</body>
</methods>

<methods>
<class-id>Seaside.MWDomainModel class</class-id> <category>instance creation</category>

<body package="Mewa-Patches" selector="new">new

	^(super new)
		initialize; 
		yourself</body>
</methods>

<methods>
<class-id>Seaside.MWTimeAttribute</class-id> <category>visitor</category>

<body package="Mewa-Metaobject" selector="accept:">accept: aVisitor
	aVisitor visitTimeAttribute: self</body>
</methods>

<methods>
<class-id>Seaside.MWTimeAttribute</class-id> <category>caching</category>

<body package="Mewa-Metaobject" selector="commitCache">commitCache
	self metaObject baseobject
		perform: (self selector,':') asSymbol
		with: (self createTimeFrom: self cache)</body>

<body package="Mewa-Metaobject" selector="refreshCache">refreshCache
	" a time is represented in cache as an array to make it possible
	to cache invalid date for editors "

	cache := self value isNil
		ifFalse: [
			Array
				with: self value hours
				with: self value minutes ]
		ifTrue: [ Array new: 2 withAll: String new ].
	^cache</body>
</methods>

<methods>
<class-id>Seaside.MWTimeAttribute</class-id> <category>private</category>

<body package="Mewa-Metaobject" selector="createTimeFrom:">createTimeFrom: anArray
	^(self representsEmptyTime: anArray)
		ifFalse: [ Time fromSeconds: (anArray first * 3600 + (anArray second * 60)) ]
		ifTrue: [ nil ]</body>

<body package="Mewa-Metaobject" selector="representsEmptyDate:">representsEmptyDate: anArray
	^anArray isNil
		or: [
			anArray first isEmptyOrNil
				and: [ anArray second isEmptyOrNil ]
				and: [ anArray third isEmptyOrNil ] ]</body>

<body package="Mewa-Metaobject" selector="representsEmptyTime:">representsEmptyTime: anArray
	^anArray isNil
		or: [
			anArray first isEmptyOrNil
				and: [ anArray second isEmptyOrNil ] ]</body>
</methods>

<methods>
<class-id>Seaside.MWTimeAttribute</class-id> <category>initialization</category>

<body package="Mewa-Metaobject" selector="initialize">initialize
	super initialize.
	self formatWith: [ :item |
		item isNil ifTrue: [ ' - ' ] ifFalse: [ item asString ] ].
	self
		addValidationRule: [ :value |  (self representsEmptyTime: value)
			or: [ [ self createTimeFrom: value. true ] on: Error do: [ :err | false ] ] ]
		errorString: 'not valid'.</body>
</methods>

<methods>
<class-id>Seaside.MWPasswordAttribute</class-id> <category>as yet unclassified</category>

<body package="Mewa-Metaobject" selector="accept:">accept: aVisitor
	aVisitor visitPasswordAttribute: self</body>

<body package="Mewa-Metaobject" selector="cacheConfirmation">cacheConfirmation
	^cacheConfirmation</body>

<body package="Mewa-Metaobject" selector="cacheConfirmation:">cacheConfirmation: aString
	cacheConfirmation := aString</body>

<body package="Mewa-Metaobject" selector="multiLine:">multiLine: aBoolean
	self shouldNotImplement</body>

<body package="Mewa-Metaobject" selector="refreshCache">refreshCache
	super refreshCache.
	cacheConfirmation := self cache</body>

<body package="Mewa-Metaobject" selector="validateCache">validateCache
	self cache = self cacheConfirmation ifFalse: [
		^'Confirmation of password is not correct.' ].
	^super validateCache</body>
</methods>

<methods>
<class-id>Seaside.MWMultipleAttributeContainer</class-id> <category>accessing</category>

<body package="Mewa-Components" selector="children">children
	^components</body>
</methods>

<methods>
<class-id>Seaside.MWMultipleAttributeContainer</class-id> <category>actions</category>

<body package="Mewa-Components" selector="createEmptyEditor">createEmptyEditor	
	^(MWEditorVisitor model: attribute baseClass new)
		subForm: true;
		onAnswer: [ :value |
			value ifNotNilDo: [ :newBaseObject |
				attribute addToCache: newBaseObject.
				components removeLast.
				components add: (MWViewerVisitor model: newBaseObject).
				components add: self createEmptyEditor ] ];
		yourself</body>

<body package="Mewa-Components" selector="delete:">delete: aViewerComponent	
	attribute removeFromCache: aViewerComponent metaobject baseobject.
	components remove: aViewerComponent</body>

<body package="Mewa-Components" selector="editorFor:">editorFor: aMetaobject
	^(MWEditorVisitor metaobject: aMetaobject) subForm: true</body>

<body package="Mewa-Components" selector="switchToEditMode:">switchToEditMode: aViewerComponent
	aViewerComponent call: (self editorFor: aViewerComponent metaobject)</body>

<body package="Mewa-Components" selector="viewerFor:">viewerFor: aMetaobject
	^MWViewerVisitor metaobject: aMetaobject</body>
</methods>

<methods>
<class-id>Seaside.MWMultipleAttributeContainer</class-id> <category>initialization</category>

<body package="Mewa-Components" selector="initializeWithAttribute:">initializeWithAttribute: aMultipleAttribute
	components := OrderedCollection new.
	attribute := aMultipleAttribute.
	aMultipleAttribute cache do: [ :each |
		components add: (self viewerFor: each metaobject) ].
	components add: self createEmptyEditor</body>
</methods>

<methods>
<class-id>Seaside.MWMultipleAttributeContainer</class-id> <category>rendering</category>

<body package="Mewa-Components" selector="isViewer:">isViewer: aComponent
	aComponent visiblePresentersDo: [ :each |
		each isDecoration ifFalse: [ ^each isViewer ] ].
	self error: 'there should be at least one visible presenter for aComponent'</body>

<body package="Mewa-Components" selector="renderContentOn:">renderContentOn: html
	components do: [ :each |
		(self isViewer: each)
			ifTrue: [
				html render: each.
				html submitButtonWithAction: [ self switchToEditMode: each ] text: 'edit'.
				html space.
				html submitButtonWithAction: [ self delete: each ] text: 'delete'.
				html break; break ]
			ifFalse: [
				html render: each.
				html break; break ] ] fixTemps</body>

<body package="Mewa-Components" selector="rendererClass">rendererClass
	^WAHtmlRenderer</body>
</methods>

<methods>
<class-id>Seaside.MWMultipleAttributeContainer class</class-id> <category>instance creation</category>

<body package="Mewa-Components" selector="for:">for: aMultipleAttribute
	^self new
		initializeWithAttribute: aMultipleAttribute;
		yourself</body>
</methods>

<methods>
<class-id>Seaside.MWVisitor</class-id> <category>initialization</category>

<body package="Mewa-Visitors" selector="initializeWith:">initializeWith: aMetaobject
	metaobject := aMetaobject</body>
</methods>

<methods>
<class-id>Seaside.MWVisitor</class-id> <category>testing</category>

<body package="Mewa-Visitors" selector="isViewer">isViewer
	^false</body>
</methods>

<methods>
<class-id>Seaside.MWVisitor</class-id> <category>accessing</category>

<body package="Mewa-Visitors" selector="metaobject">metaobject
	^metaobject</body>

<body package="Mewa-Visitors" selector="style">style
	^' body { font-size : 12px; font-family : Arial;  } '</body>

<body package="Mewa-Visitors" selector="visit:">visit: anAttribute</body>
</methods>

<methods>
<class-id>Seaside.MWVisitor</class-id> <category>rendering</category>

<body package="Mewa-Visitors" selector="rendererClass">rendererClass
	^WAHtmlRenderer</body>
</methods>

<methods>
<class-id>Seaside.MWVisitor class</class-id> <category>instance-creation</category>

<body package="Mewa-Visitors" selector="metaobject:">metaobject: aMetaobject
	^self new
		initializeWith: aMetaobject;
		yourself</body>

<body package="Mewa-Visitors" selector="model:">model: aDomainObject
	^self metaobject: aDomainObject metaobject</body>
</methods>

<methods>
<class-id>Seaside.MWViewerVisitor</class-id> <category>testing</category>

<body package="Mewa-Visitors" selector="isViewer">isViewer
	^true</body>
</methods>

<methods>
<class-id>Seaside.MWViewerVisitor</class-id> <category>rendering</category>

<body package="Mewa-Visitors" selector="renderContentOn:">renderContentOn: html
	html cssClass: 'TABLE-VIEWER'.
	html table: [ self renderFieldsOn: html ]</body>

<body package="Mewa-Visitors" selector="renderFieldsOn:">renderFieldsOn: html
	renderer := html.
	self metaobject accept: self</body>

<body package="Mewa-Visitors" selector="renderLabel:control:">renderLabel: aString control: aBlock
	renderer
		tableRowWith: aString
		with: [ aBlock value: renderer ]</body>

<body package="Mewa-Visitors" selector="renderLabel:value:">renderLabel: aString value: anotherString
	renderer
		tableRowWith: aString
		with: [ renderer bold: anotherString ]</body>
</methods>

<methods>
<class-id>Seaside.MWViewerVisitor</class-id> <category>visiting</category>

<body package="Mewa-Visitors" selector="renderRelationshipItem:of:on:">renderRelationshipItem: anObject of: aRelationshipAttribute on: html
	| linkAction text |
	text := aRelationshipAttribute itemFormatBlock value: anObject.
	(linkAction := aRelationshipAttribute linkAction) isNil
		ifFalse: [
			html
				anchorWithAction: [
					self targetSend: (Message
						selector: linkAction
						argument: anObject) ]
				text: text ]
		ifTrue: [ html render: text ]</body>

<body package="Mewa-Visitors" selector="visitDateAttribute:">visitDateAttribute: aDateAttribute
	self visitTextAttribute: aDateAttribute</body>

<body package="Mewa-Visitors" selector="visitMailAttribute:">visitMailAttribute: aMailAttribute
	self
		renderLabel: aMailAttribute label
		control: [ :html | html anchorWithMailto: aMailAttribute formatedValue ]</body>

<body package="Mewa-Visitors" selector="visitMultipleAttribute:">visitMultipleAttribute: aMultipleAttribute
	"For view same as other relationships"
	self visitMultipleRelationshipAttribute: aMultipleAttribute</body>

<body package="Mewa-Visitors" selector="visitMultipleRelationshipAttribute:">visitMultipleRelationshipAttribute: aRelationshipAttribute
	| control |
	control := [ :html |
		aRelationshipAttribute value
			do: [ :each |
				self renderRelationshipItem: each of: aRelationshipAttribute on: html ]
			separatedBy: [ html break ] ].

	self
		renderLabel: aRelationshipAttribute label
		control: control</body>

<body package="Mewa-Visitors" selector="visitPasswordAttribute:">visitPasswordAttribute: aPasswordAttribute
	self
		renderLabel: aPasswordAttribute label
		value: '********'</body>

<body package="Mewa-Visitors" selector="visitSingleRelationshipAttribute:">visitSingleRelationshipAttribute: aRelationshipAttribute
	self
		renderLabel: aRelationshipAttribute label
		control: [ :html |
			self
				renderRelationshipItem: aRelationshipAttribute value
				of: aRelationshipAttribute
				on: html ]</body>

<body package="Mewa-Visitors" selector="visitTextAttribute:">visitTextAttribute: aTextAttribute
	self
		renderLabel: aTextAttribute label
		value: aTextAttribute formatedValue</body>

<body package="Mewa-Visitors" selector="visitTimeAttribute:">visitTimeAttribute: aTimeAttribute
	self visitTextAttribute: aTimeAttribute</body>

<body package="Mewa-Visitors" selector="visitUrlAttribute:">visitUrlAttribute: aUrlAttribute
	self
		renderLabel: aUrlAttribute label
		control: [ :html | html
			anchorWithUrl: 'http://' , aUrlAttribute value
			do: aUrlAttribute formatedValue ]</body>
</methods>

<methods>
<class-id>Seaside.MWViewerVisitor</class-id> <category>accessing</category>

<body package="Mewa-Visitors" selector="style">style
	^ ' .TABLE-VIEWER { font-size: 12px; font-family: Arial; }'</body>
</methods>

<methods>
<class-id>Seaside.MWEditorVisitor</class-id> <category>visiting</category>

<body package="Mewa-Visitors" selector="callDateSelectorFor:">callDateSelectorFor: aDateAttribute
	| date calendar newDate |
	date := aDateAttribute dateFromCache ifNil: [ Date today ].
	newDate := self call: (calendar := WAMiniCalendar new
		date: date;
		month: date month;
		canSelectBlock: [ :d | true ];
		selectBlock: [ :d | calendar answer: d ]).
	newDate ifNotNil: [
		aDateAttribute cache: (Array
			with: newDate dayOfMonth
			with: newDate monthIndex
			with: newDate year) ]</body>

<body package="Mewa-Visitors" selector="visitDateAttribute:">visitDateAttribute: aDateAttribute
	| fieldValues |
	aDateAttribute isReadOnly ifFalse: [
		self
			renderLabel: aDateAttribute label
			control: [ :html |
				fieldValues := aDateAttribute cache.
				html
					attributeAt: #size put: 2; attributeAt: #maxlength put: 2;
					textInputWithValue: fieldValues first displayString
					callback: [ :day | fieldValues at: 1 put: day ].
				html
					attributeAt: #size put: 2; attributeAt: #maxlength put: 2;
					textInputWithValue: fieldValues second displayString
					callback: [ :month | fieldValues at: 2 put: month ].
				html
					attributeAt: #size put: 4; attributeAt: #maxlength put: 4;
					textInputWithValue: fieldValues third displayString
					callback: [ :year |
						fieldValues at: 3 put: year.
						aDateAttribute cache: fieldValues ].
				html
					submitButtonWithAction: [ self callDateSelectorFor: aDateAttribute ]
					text: 'calendar' ] fixTemps ]</body>

<body package="Mewa-Visitors" selector="visitMailAttribute:">visitMailAttribute: aMailAttribute
	self visitTextAttribute: aMailAttribute</body>

<body package="Mewa-Visitors" selector="visitMultipleAttribute:">visitMultipleAttribute: aMultipleAttribute
	aMultipleAttribute isReadOnly ifFalse: [
		self
			renderLabel: aMultipleAttribute label
			control: (self multipleAttributeEditors at: aMultipleAttribute) ]</body>

<body package="Mewa-Visitors" selector="visitMultipleRelationshipAttribute:">visitMultipleRelationshipAttribute: aRelationshipAttribute
	| items |
	aRelationshipAttribute isReadOnly ifFalse: [
		self
			renderLabel: aRelationshipAttribute label
			control: [ :html |
				items := aRelationshipAttribute items.
				items size &gt; self maxMultiRelationshipListSizeForRadioButtons
					ifTrue: [
						html
							multipleSelectFromList: items
							selected: aRelationshipAttribute cache
							callback: [:list |
								(aRelationshipAttribute cache: list) ]
							labels: aRelationshipAttribute itemFormatBlock ]
					ifFalse: [
						items do: [ :each |
							html cssClass: aRelationshipAttribute formCssClass.
							html
								checkboxWithValue: (aRelationshipAttribute cache includes: each)
								callback: [ :selected |
									selected
										ifTrue: [ aRelationshipAttribute addToCache: each ]
										ifFalse: [ aRelationshipAttribute removeFromCache: each ] ].
						html
							render: (aRelationshipAttribute itemFormatBlock value: each);
							break ] ] ] ]</body>

<body package="Mewa-Visitors" selector="visitPasswordAttribute:">visitPasswordAttribute: aPasswordAttribute
	aPasswordAttribute isReadOnly ifFalse: [
		self
			renderLabel: aPasswordAttribute label
			control: [ :html | 
				aPasswordAttribute maxLength ifNotNilDo: [ :num |
					html attributes maxlength: num ].
				html cssClass: aPasswordAttribute formCssClass.
				html passwordInputWithCallback: [ :pw1 |
					pw1 isEmptyOrNil ifFalse: [ aPasswordAttribute cache: pw1 ] ] ].
		self
			renderLabel: 'Confirmation'
			control: [ :html | 
				aPasswordAttribute maxLength ifNotNilDo: [ :num |
					html attributes maxlength: num ].
				html cssClass: aPasswordAttribute formCssClass.
				html passwordInputWithCallback: [ :pw2 |
					pw2 isEmptyOrNil ifFalse: [ aPasswordAttribute cacheConfirmation: pw2 ] ] ] ]</body>

<body package="Mewa-Visitors" selector="visitSingleRelationshipAttribute:">visitSingleRelationshipAttribute: aRelationshipAttribute
	aRelationshipAttribute isReadOnly ifFalse: [
		self
			renderLabel: aRelationshipAttribute label
			control: [ :html |
				html cssClass: aRelationshipAttribute formCssClass.
				html
					selectFromList: aRelationshipAttribute items
					selected: aRelationshipAttribute cache
					callback: [ :value | aRelationshipAttribute cache: value ]
					labels: aRelationshipAttribute itemFormatBlock ] ]</body>

<body package="Mewa-Visitors" selector="visitTextAttribute:">visitTextAttribute: aTextAttribute
	aTextAttribute isReadOnly ifFalse: [
		self
			renderLabel: aTextAttribute label
			control: [ :html | 
				aTextAttribute isMultiLine
					ifFalse: [
						aTextAttribute maxLength ifNotNilDo: [ :num |
							html attributes maxlength: num ].
						html cssClass: aTextAttribute formCssClass.
						html
							textInputWithValue: (aTextAttribute cache)
							callback: [ :value | aTextAttribute cache: value ] ]
					ifTrue: [ 
						html attributes cols: 35; rows: 10.
						html cssClass: aTextAttribute formCssClass.
						html
							textAreaWithValue: (aTextAttribute cache)
							callback: [ :value | aTextAttribute cache: value ] ] ] ]</body>

<body package="Mewa-Visitors" selector="visitTimeAttribute:">visitTimeAttribute: aTimeAttribute
	| fieldValues |
	aTimeAttribute isReadOnly ifFalse: [
		self
			renderLabel: aTimeAttribute label
			control: [ :html | 
				fieldValues := aTimeAttribute cache.
				html
					attributeAt: #size put: 2; attributeAt: #maxlength put: 2;
					textInputWithValue: fieldValues first displayString
					callback: [ :hour | fieldValues at: 1 put: hour ].
				html render: ' : '.
				html
					attributeAt: #size put: 2; attributeAt: #maxlength put: 2;
					textInputWithValue: fieldValues second displayString
					callback: [ :minutes |
						fieldValues at: 2 put: minutes.
						aTimeAttribute cache: fieldValues ] ] fixTemps ]</body>

<body package="Mewa-Visitors" selector="visitUrlAttribute:">visitUrlAttribute: anUrlAttribute
	self visitTextAttribute: anUrlAttribute</body>
</methods>

<methods>
<class-id>Seaside.MWEditorVisitor</class-id> <category>actions</category>

<body package="Mewa-Visitors" selector="cancel">cancel
	^self answer: nil</body>

<body package="Mewa-Visitors" selector="commit">commit
	self metaobject commitCache</body>

<body package="Mewa-Visitors" selector="save">save
	self isValid ifTrue: [
		self commit.
		self answer: self metaobject baseobject ]</body>
</methods>

<methods>
<class-id>Seaside.MWEditorVisitor</class-id> <category>accessing</category>

<body package="Mewa-Visitors" selector="children">children
	^self multipleAttributeEditors values asArray</body>

<body package="Mewa-Visitors" selector="maxMultiRelationshipListSizeForRadioButtons">maxMultiRelationshipListSizeForRadioButtons
	^5</body>

<body package="Mewa-Visitors" selector="multipleAttributeEditors">multipleAttributeEditors
	^multipleAttributeEditors</body>

<body package="Mewa-Visitors" selector="style">style
	^' .TABLE-EDITOR { font-size: 12px; font-family: Arial; "border: thin groove;" }'</body>

<body package="Mewa-Visitors" selector="subForm:">subForm: aBoolean
	subForm := aBoolean</body>
</methods>

<methods>
<class-id>Seaside.MWEditorVisitor</class-id> <category>initialization</category>

<body package="Mewa-Visitors" selector="initializeSubForms">initializeSubForms
	multipleAttributeEditors := Dictionary new.
	self metaobject multipleAttributes do: [ :each |
		multipleAttributeEditors at: each put: (MWMultipleAttributeContainer for: each) ]</body>

<body package="Mewa-Visitors" selector="initializeWith:">initializeWith: aMetaobject
	super initializeWith: aMetaobject.
	self metaobject refreshCache.
	self subForm: false.
	self initializeSubForms</body>
</methods>

<methods>
<class-id>Seaside.MWEditorVisitor</class-id> <category>testing</category>

<body package="Mewa-Visitors" selector="isSubForm">isSubForm
	^subForm</body>

<body package="Mewa-Visitors" selector="isValid">isValid
	validationErrors := self metaobject validate.
	^ validationErrors isEmpty</body>
</methods>

<methods>
<class-id>Seaside.MWEditorVisitor</class-id> <category>rendering</category>

<body package="Mewa-Visitors" selector="renderButtonsOn:">renderButtonsOn: html
	html submitButtonWithAction: [ self save ] text: 'save'.
	html space.
	html submitButtonWithAction: [ self cancel ] text: 'cancel'</body>

<body package="Mewa-Visitors" selector="renderContentOn:">renderContentOn: html
	self isSubForm
		ifTrue: [ self renderMainOn: html ]
		ifFalse: [ html form: [ self renderMainOn: html ] ]</body>

<body package="Mewa-Visitors" selector="renderFieldsOn:">renderFieldsOn: html
	renderer := html.
	self metaobject accept: self.</body>

<body package="Mewa-Visitors" selector="renderLabel:control:">renderLabel: aString control: aBlock
	renderer attributes valign: #top.
	renderer
		tableRowWith: aString
		with: aBlock</body>

<body package="Mewa-Visitors" selector="renderMainOn:">renderMainOn: html
	html cssClass: 'TABLE-EDITOR'.
	html table: [
		self renderValidationErrorsOn: html.
		self renderFieldsOn: html.
		html tableRowWith: [ self renderButtonsOn: html ] span: 2 ]</body>

<body package="Mewa-Visitors" selector="renderValidationErrorsOn:">renderValidationErrorsOn: html
	validationErrors isEmptyOrNil ifFalse: [
		html tableRowWith: [
			html render: 'The following fields are not valid. Please correct.'.
			html list: (validationErrors collect: [ :each |
				each key label, ': ', each value ]) ] span: 2 ]</body>
</methods>

<methods>
<class-id>Seaside.MWMailAttribute</class-id> <category>as yet unclassified</category>

<body package="Mewa-Metaobject" selector="accept:">accept: aVisitor
	aVisitor visitMailAttribute: self</body>
</methods>

<methods>
<class-id>Seaside.MWSingleRelationshipAttribute</class-id> <category>visitor</category>

<body package="Mewa-Metaobject" selector="accept:">accept: aVisitor
	aVisitor visitSingleRelationshipAttribute: self</body>
</methods>

<methods>
<class-id>Seaside.MWSingleRelationshipAttribute</class-id> <category>testing</category>

<body package="Mewa-Metaobject" selector="hasNilItem">hasNilItem
	^nilItemString notNil</body>
</methods>

<methods>
<class-id>Seaside.MWSingleRelationshipAttribute</class-id> <category>accessing</category>

<body package="Mewa-Metaobject" selector="itemFormatBlock">itemFormatBlock
	^self hasNilItem
		ifTrue: [
			[ :item | item notNil
				ifTrue: [ itemFormatBlock value: item ]
				ifFalse: [ nilItemString ] ] ]
		ifFalse: [ itemFormatBlock ]</body>

<body package="Mewa-Metaobject" selector="items">items
	| items |
	items := super items.
	^self hasNilItem
		ifTrue: [ items asOrderedCollection
			addFirst: nil;
			yourself ]
		ifFalse: [ items ]</body>
</methods>

<methods>
<class-id>Seaside.MWSingleRelationshipAttribute</class-id> <category>configuration</category>

<body package="Mewa-Metaobject" selector="nilItemString:">nilItemString: aString
	nilItemString := aString</body>
</methods>

<methods>
<class-id>Seaside.MWBooleanAttribute</class-id> <category>initialization</category>

<body package="Mewa-Metaobject" selector="initialize">initialize
	super initialize.
	self trueItemString: 'yes' falseItemString: 'no'</body>
</methods>

<methods>
<class-id>Seaside.MWBooleanAttribute</class-id> <category>configuration</category>

<body package="Mewa-Metaobject" selector="trueItemString:falseItemString:">trueItemString: aString falseItemString: anotherString
	self
		relationshipTo: [ OrderedCollection with: true with: false ]
		formatWith: [ :item | item
			ifTrue: [ aString ]
			ifFalse: [ anotherString ] ]</body>
</methods>

<methods>
<class-id>Seaside.MWPhoneNumber</class-id> <category>accessing</category>

<body package="Mewa-Example" selector="metaobject">metaobject
	| metaobject |
	metaobject := MWMetaobject for: self.

	metaobject textAttribute: #type do: [ :attribute |
		attribute
			label: 'Type';
			maxLength: 10;
			addRequiredRule ].

	metaobject textAttribute: #number do: [ :attribute |
		attribute
			label: 'Number';
			maxLength: 20;
			addRequiredRule ].

	^metaobject</body>

<body package="Mewa-Example" selector="number">number
	^number</body>

<body package="Mewa-Example" selector="number:">number: anObject
	number := anObject</body>

<body package="Mewa-Example" selector="type">type
	^type</body>

<body package="Mewa-Example" selector="type:">type: anObject
	type := anObject</body>
</methods>

<methods>
<class-id>Seaside.MWListItemViewer</class-id> <category>rendering</category>

<body package="Mewa-Example" selector="renderContentOn:">renderContentOn: html
	self renderFieldsOn: html</body>

<body package="Mewa-Example" selector="renderLabel:value:">renderLabel: aString value: anotherString
	renderer tableData: anotherString</body>
</methods>

<methods>
<class-id>Seaside.MWDateAttribute</class-id> <category>visitor</category>

<body package="Mewa-Metaobject" selector="accept:">accept: aVisitor
	aVisitor visitDateAttribute: self</body>
</methods>

<methods>
<class-id>Seaside.MWDateAttribute</class-id> <category>configuration</category>

<body package="Mewa-Metaobject" selector="addRequiredRule">addRequiredRule
	self
		addValidationRule: [ :value | (value isNil or: [
				value first isEmptyOrNil
				| value second isEmptyOrNil
				| value third isEmptyOrNil ]) not ]
		errorString: 'required'</body>
</methods>

<methods>
<class-id>Seaside.MWDateAttribute</class-id> <category>caching</category>

<body package="Mewa-Metaobject" selector="commitCache">commitCache
	self metaObject baseobject
		perform: (self selector,':') asSymbol
		with: (self createDateFrom: self cache)</body>

<body package="Mewa-Metaobject" selector="dateFromCache">dateFromCache
	^self createDateFrom: self cache</body>

<body package="Mewa-Metaobject" selector="refreshCache">refreshCache
	" a date is represented as an array in cache to make it possible
	to cache invalid date data for editors "

	cache := self value isNil
		ifFalse: [
			Array
				with: self value dayOfMonth
				with: self value monthIndex
				with: self value year ]
		ifTrue: [ Array new: 3 withAll: String new ].
	^cache</body>
</methods>

<methods>
<class-id>Seaside.MWDateAttribute</class-id> <category>private</category>

<body package="Mewa-Metaobject" selector="createDateFrom:">createDateFrom: anArray
	^(self representsEmptyDate: anArray)
		ifFalse: [
			Date
				newDay: anArray first asNumber
				month: anArray second asNumber
				year: anArray third asNumber ]
		ifTrue: [ nil ]</body>

<body package="Mewa-Metaobject" selector="representsEmptyDate:">representsEmptyDate: anArray
	^anArray isNil
		or: [
			anArray first isEmptyOrNil
				and: [ anArray second isEmptyOrNil ]
				and: [ anArray third isEmptyOrNil ] ]</body>
</methods>

<methods>
<class-id>Seaside.MWDateAttribute</class-id> <category>initialization</category>

<body package="Mewa-Metaobject" selector="initialize">initialize
	super initialize.
	self formatWith: [ :item |
		item isNil ifTrue: [ ' - ' ] ifFalse: [ item displayString ] ].
	self
		addValidationRule: [ :value |  (self representsEmptyDate: value)
			or: [ [ self createDateFrom: value. true ] on: Error do: [ :err | false ] ] ]
		errorString: 'not valid'.</body>
</methods>

<methods>
<class-id>Seaside.MWMetaobject</class-id> <category>visitor</category>

<body package="Mewa-Metaobject" selector="accept:">accept: aVisitor
	(self attributes reject: [ :each | each isHidden ])
		do: [ :each | each accept: aVisitor ]</body>
</methods>

<methods>
<class-id>Seaside.MWMetaobject</class-id> <category>accessing-attributes</category>

<body package="Mewa-Metaobject" selector="addAttribute:">addAttribute: anAttribute
	anAttribute metaObject: self.
	self removeAttributeOf: anAttribute selector ifAbsent: [ ].
	attributes add: anAttribute</body>

<body package="Mewa-Metaobject" selector="allSelectors">allSelectors
	^attributes collect: [ :each | each selector ]</body>

<body package="Mewa-Metaobject" selector="attributeOf:">attributeOf: aSelector
	^self
		attributeOf: aSelector
		ifAbsent: [ self error: 'attribute not found' ]</body>

<body package="Mewa-Metaobject" selector="attributeOf:ifAbsent:">attributeOf: aSelector ifAbsent: aBlock
	^attributes
		detect: [ :each | each selector = aSelector ]
		ifNone: aBlock</body>

<body package="Mewa-Metaobject" selector="attributes">attributes
	^attributes</body>

<body package="Mewa-Metaobject" selector="hideAttributeOf:">hideAttributeOf: aSymbol
	(self attributeOf: aSymbol) hide</body>

<body package="Mewa-Metaobject" selector="hideAttributesOf:">hideAttributesOf: anArray
	anArray do: [ :each |
		self hideAttributeOf: each ]</body>

<body package="Mewa-Metaobject" selector="removeAttributeOf:">removeAttributeOf: aSelector
	attributes remove: (self attributeOf: aSelector)</body>

<body package="Mewa-Metaobject" selector="removeAttributeOf:ifAbsent:">removeAttributeOf: aSelector ifAbsent: aBlock
	attributes remove: (self attributeOf: aSelector ifAbsent: [ ^aBlock value ])</body>
</methods>

<methods>
<class-id>Seaside.MWMetaobject</class-id> <category>convenience</category>

<body package="Mewa-Metaobject" selector="attribute:class:do:">attribute: aSymbol class: aAttributeClass do: aBlock
	| attribute |
	attribute := aAttributeClass for: aSymbol.
	aBlock value: attribute.
	self addAttribute: attribute</body>

<body package="Mewa-Metaobject" selector="booleanAttribute:do:">booleanAttribute: aSymbol do: aBlock
	self attribute: aSymbol class: MWBooleanAttribute do: aBlock</body>

<body package="Mewa-Metaobject" selector="dateAttribute:do:">dateAttribute: aSymbol do: aBlock
	self attribute: aSymbol class: MWDateAttribute do: aBlock</body>

<body package="Mewa-Metaobject" selector="multipleAttribute:do:">multipleAttribute: aSymbol do: aBlock
	self attribute: aSymbol class: MWMultipleAttribute do: aBlock</body>

<body package="Mewa-Metaobject" selector="multipleRelationshipAttribute:do:">multipleRelationshipAttribute: aSymbol do: aBlock
	self attribute: aSymbol class: MWMultipleRelationshipAttribute do: aBlock</body>

<body package="Mewa-Metaobject" selector="passwordAttribute:do:">passwordAttribute: aSymbol do: aBlock
	self attribute: aSymbol class: MWPasswordAttribute do: aBlock</body>

<body package="Mewa-Metaobject" selector="singleRelationshipAttribute:do:">singleRelationshipAttribute: aSymbol do: aBlock
	self attribute: aSymbol class: MWSingleRelationshipAttribute do: aBlock</body>

<body package="Mewa-Metaobject" selector="textAttribute:do:">textAttribute: aSymbol do: aBlock
	self attribute: aSymbol class: MWTextAttribute do: aBlock</body>

<body package="Mewa-Metaobject" selector="timeAttribute:do:">timeAttribute: aSymbol do: aBlock
	self attribute: aSymbol class: MWTimeAttribute do: aBlock</body>
</methods>

<methods>
<class-id>Seaside.MWMetaobject</class-id> <category>accessing</category>

<body package="Mewa-Metaobject" selector="baseobject">baseobject
	^baseobject</body>

<body package="Mewa-Metaobject" selector="baseobject:">baseobject: anObject
	baseobject := anObject</body>

<body package="Mewa-Metaobject" selector="multipleAttributes">multipleAttributes
	^self attributes select: [ :each | each isMultipleAttribute ]</body>
</methods>

<methods>
<class-id>Seaside.MWMetaobject</class-id> <category>services</category>

<body package="Mewa-Metaobject" selector="commitCache">commitCache
	self attributes do: [ :each |
		each commitCache ]</body>

<body package="Mewa-Metaobject" selector="refreshCache">refreshCache
	self attributes do: [ :each |
		each refreshCache ]</body>

<body package="Mewa-Metaobject" selector="validate">validate
	^self attributes
		inject: OrderedCollection new
		into: [ :errors :attribute |
			attribute validateCache ifNotNilDo: [ :errorString |
				errors add: attribute -&gt; errorString ].
			errors ]</body>
</methods>

<methods>
<class-id>Seaside.MWMetaobject</class-id> <category>initialization</category>

<body package="Mewa-Metaobject" selector="initialize">initialize
	attributes := OrderedCollection new</body>
</methods>

<methods>
<class-id>Seaside.MWMetaobject class</class-id> <category>instance creation</category>

<body package="Mewa-Metaobject" selector="for:">for: anObject
	^self new
		baseobject: anObject;
		yourself.</body>

<body package="Mewa-Patches" selector="new">new

	^(super new)
		initialize; 
		yourself</body>
</methods>

<methods>
<class-id>Seaside.WAHtmlRenderer</class-id> <category>*Mewa</category>

<body package="Mewa-Extensions" selector="maxSizeOfSelectBox">maxSizeOfSelectBox
	^5</body>

<body package="Mewa-Extensions" selector="multipleSelectFromList:selected:callback:">multipleSelectFromList: list selected: aCollection callback: aBlock
	self
		multipleSelectFromList: list
		selected: aCollection
		callback: aBlock
		labels: [ :object | object displayString ]</body>

<body package="Mewa-Extensions" selector="multipleSelectFromList:selected:callback:labels:">multipleSelectFromList: list selected: aCollection callback: aBlock labels: labelsBlock
	| add  remove size |
	add := ValueHolder new.
	remove := ValueHolder new.
	size := (aCollection size max: (list size - aCollection size)) min: self maxSizeOfSelectBox.
	self layoutTable: [
		self tableRow: [
			self tableData: [
				self attributeAt: #size put: size.
				self
					selectFromList: aCollection
					selected: nil
					callback: [ :value | remove contents: value ]
					labels: labelsBlock].
			self tableData: [
				self submitButtonWithAction: [
					add contents ifNotNilDo: [ :item |
						aBlock value: (aCollection copyWith: item) ] ] text: ' &lt; '.
				self break.
				self submitButtonWithAction: [
					remove contents ifNotNilDo: [ :item |
						aBlock value: (aCollection copyWithout: item)]] text: ' &gt; ' ].
			self tableData: [
				self attributeAt: #size put: size.
				self
					selectFromList: (list copyWithoutAll: aCollection)
					selected: nil
					callback: [ :value | add contents: value ]
					labels: labelsBlock ] ] ]</body>
</methods>

<initialize>
<class-id>Seaside.MWExample</class-id>
</initialize>

<do-it>"Imported Classes:"</do-it>

<do-it>self error: 'Attempting to file-in parcel imports.  Choose terminate or close'</do-it>

<class>
<name>Object</name>
<environment>Core</environment>
<super></super>
<private>false</private>
<indexed-type>none</indexed-type>
<inst-vars></inst-vars>
<class-inst-vars></class-inst-vars>
<imports></imports>
<category>Kernel-Objects</category>
<attributes>
<package>Kernel-Objects</package>
</attributes>
</class>

<class>
<name>WAHtmlRenderer</name>
<environment>Seaside</environment>
<super>Seaside.WAAbstractHtmlBuilder</super>
<private>false</private>
<indexed-type>none</indexed-type>
<inst-vars>context callbacks shortcutBuffer </inst-vars>
<class-inst-vars></class-inst-vars>
<imports></imports>
<category>Seaside-Builder</category>
<attributes>
<package>Seaside-Builder</package>
</attributes>
</class>

<class>
<name>WAComponent</name>
<environment>Seaside</environment>
<super>Seaside.WAPresenter</super>
<private>false</private>
<indexed-type>none</indexed-type>
<inst-vars>decoration </inst-vars>
<class-inst-vars></class-inst-vars>
<imports></imports>
<category>Seaside-Component</category>
<attributes>
<package>Seaside-Component</package>
</attributes>
</class>

<class>
<name>WASession</name>
<environment>Seaside</environment>
<super>Seaside.WAExpiringHandler</super>
<private>false</private>
<indexed-type>none</indexed-type>
<inst-vars>continuations escapeContinuation monitor state currentRequest scripts jumpTo internalError cookiesEnabled </inst-vars>
<class-inst-vars></class-inst-vars>
<imports></imports>
<category>Seaside-Session</category>
<attributes>
<package>Seaside-Session</package>
</attributes>
</class>

</st-source>
