WAHtmlRenderer


Seaside-Builder

Comment:

I am passed to the method #renderContentOn: of components unless #rendererClass has been redefined. On top of the basic XHTML construction methods inherited from WAAbstractHtmlBuilder, I provide an interface to attach event handlers to anchors and to form-elements.

To render any kind of squeak object call the message #render: It will do a double dispatch and call #renderOn: on this object.  For example:

	html render: 'Some text'.
	html render: 123.					" will print the child "
	html render: nil. 					" will do nothing "
	html render: #( 'a' 'b' 'c' ).			" will print every element "	
	html render: businessObject.			" will print the #asString of your object "
	html render: childComponent.		" will render the child component "
	
This kind of double dispatch can be used with any xhtml-generating method:

	html divNamed: 'child' with: childComponent.
	html bold: #( 1 'First' ).

Hierarchy:

ProtoObject
Object
WAAbstractHtmlBuilder
WAHtmlRenderer

Summary:

instance variables:

callbacks context

methods:

instance class
*SC *SeasideTesting-override accessing compound convenience core documents javascript model as yet unclassified

Detail:

instance variables:

callbacks
inferredType:
UndefinedObject
context
inferredType:
UndefinedObject

instance methods:

*SC
fileUploadWithValue: aValue callback: aBlock
 
	self
		inputWithType: 'file'
		named: (callbacks registerCallback: aBlock)
		value: aValue
passwordInputWithCallback: callbackBlock value: v

	self
		valueInputOfType: 'password'
		value: v
		callback: callbackBlock

*SeasideTesting-override
textInputOn: aSymbol of: anObject
 
	self attributes at: 'id' ifAbsentPut: aSymbol.
	self
		textInputWithValue: (anObject perform: aSymbol)
		callback: (self callbackForSelector: aSymbol of: anObject)

accessing
callbacks

	^ callbacks
close

context

	^ context
document

	^ context document
initializeWithContext: aRenderingContext callbacks: aCallbackStore

	context _ aRenderingContext.
	callbacks _ aCallbackStore.
registry

	^ WACurrentSession value application 
request

	^ self context request
response

	^ self context response

compound
dateInputWithValue: aDate callback: aBlock

	| values |
	aBlock fixTemps.
	
	values _ Array new: 3.
	self
		selectFromList: (1 to: 12)
		selected: aDate monthIndex 
		callback: [ :month | values at: 2 put: month ]
		labels: [:ea | Date nameOfMonth: ea].
	self space.
	self
		textInputWithValue: aDate dayOfMonth 
		callback: [ :day | values at: 1 put: day ]
		maxLength: 2.
	self space.
	self 
		textInputWithValue: aDate year
		callback: [ :year | values at: 3 put: year]
		maxLength: 4.
	self hiddenInputWithCallback:
		[aBlock value: (Date
				newDay: (values first min: (Date daysInMonth: values second forYear: values third))
				monthNumber: values second
				year: values third)].
timeInputWithValue: aTime callback: aBlock

	| values |
	aBlock fixTemps.
	values _ Array new: 2.
	self
		textInputWithValue: aTime hour
		callback: [:hour | values at: 1 put: hour]
		maxLength: 2.
	self space; text: ':'; space.
	self
		textInputWithValue: aTime minutes asTwoCharacterString
		callback: [:minute | values at: 2 put: minute asNumber]
		maxLength: 2.
	self hiddenInputWithCallback:
		[aBlock value:
			(Time
				hour: values first
				minute: (values second min: 59)
				second: 0)]
		
	
	

convenience
anchorWithAction: actionBlock do: linkBlock

	self openAnchorWithAction: actionBlock.
	self render: linkBlock.
	self closeTag: 'a'.

anchorWithAction: actionBlock form: aForm

	self anchorWithAction: actionBlock do: [self imageWithForm: aForm.]
anchorWithAction: actionBlock image: aForm

	self anchorWithAction: actionBlock do: [self imageWithForm: aForm.]
anchorWithAction: actionBlock text: aString

	self anchorWithAction: actionBlock do: aString
anchorWithCallback: actionBlock do: linkBlock

	self anchorWithUrl: (self urlForIdempotentAction: actionBlock) do: linkBlock
booleanMenuWithValue: aBoolean callback: callbackBlock

	self booleanMenuWithValue: aBoolean callback: callbackBlock labels: #(Yes No)
booleanMenuWithValue: aBoolean callback: callbackBlock labels: labelArray

	self
		selectFromList: (Array with: true with: false)
		selected: aBoolean
		callback: callbackBlock
		labels: [:b | b ifTrue: [labelArray first] ifFalse: [labelArray second]]
form: aBlock

	self
		formWithMethod: 'post'
		action: context actionUrl urlString
		do: [
			self div: [
				context actionUrl parameters keysAndValuesDo:
				[:k :v |
				self inputWithType: 'hidden' named: k value: v].
			aBlock value
		]]
hiddenInputWithCallback: callbackBlock

	self inputWithType: 'hidden' named: (self callbacks registerCallback: callbackBlock)
hiddenInputWithValue: anObject callback: callbackBlock

	self valueInputOfType: 'hidden'
		value: anObject
		callback: callbackBlock
openAnchorWithAction: actionBlock

	self
		attributeAt: 'href'
		put: (self urlForAction: actionBlock).
	self openTag: 'a'.
passwordInputWithCallback: callbackBlock

	self passwordInputWithValue: '' callback: callbackBlock
passwordInputWithValue: anObject callback: callbackBlock

	self
		valueInputOfType: 'password'
		value: anObject
		callback: callbackBlock
selectFromList: aCollection selected: selectedObject callback: callbackBlock

	self selectFromList: aCollection selected: selectedObject callback: callbackBlock labels: [:i | i asString]
selectFromList: aCollection selected: selectedObject callback: callbackBlock labels: labelsBlock

	self openSelect.
	callbackBlock fixTemps.

	aCollection do:
		[:item |
		self
			optionWithLabel: (labelsBlock value: item)
			selected: (item = selectedObject)
			callback: [callbackBlock value: item]].
	self closeTag: 'select'.
selectFromList: aCollection selected: selectedObject callback: callbackBlock labels: labelsBlock nilLabel: aString

	self selectFromList: (Array with: nil), aCollection asArray
		selected: selectedObject
		callback: callbackBlock
		labels: [:ea | ea ifNil: [aString] ifNotNil: [labelsBlock value: ea]]
selectInputOn: selectedSymbol of: anObject list: aCollection

	self
		selectFromList: aCollection
		selected: (anObject perform: selectedSymbol)
		callback: (self callbackForSelector: selectedSymbol of: anObject)
submitButtonWithAction: aBlock text: aString

	self attributeAt: 'value' put: aString.
	self submitButtonWithAction: aBlock
textInputWithCallback: callbackBlock

	self textInputWithValue: '' callback: callbackBlock
textInputWithValue: anObject callback: callbackBlock

	self
		valueInputOfType: 'text'
		value: anObject
		callback: callbackBlock
textInputWithValue: anObject callback: callbackBlock maxLength: aNumber

	self attributes
		at: 'size' put: aNumber;
		at: 'maxlength' put: aNumber.
	self textInputWithValue: anObject callback: callbackBlock.
unorderedList: aCollection selected: anObject callback: aBlock

	self unorderedList: aCollection selected: anObject  callback: aBlock labels: [:ea | ea asString]
unorderedList: aCollection selected: anObject callback: aBlock labels: labelBlock

	aBlock fixTemps.
	self cssClass: 'options'.
	self unorderedList: [
		aCollection do:
			[:ea |
			self cssClass: 'option'.
			ea = anObject ifTrue: [self cssId: 'option-selected'].
			self listItem: [self anchorWithAction: [aBlock value: ea] text: (labelBlock value: ea)]].
	]
unorderedListOn: aSymbol of: anObject list: aCollection

	self
		unorderedList: aCollection
		selected: (anObject perform: aSymbol)
		callback: (self callbackForSelector: aSymbol of: anObject)

core
cancelButtonWithAction: aBlock

	self attributes value: 'Cancel'.
	self inputWithType: 'submit' named: (self callbacks registerCancelActionCallback: aBlock)
checkboxWithValue: aBoolean callback: callbackBlock

   | value originalAttributes |
   value _ ValueHolder new.
   originalAttributes _ attributeBuffer.
   attributeBuffer _ nil.
   self
       hiddenInputWithCallback: [value contents: false].
   attributeBuffer _ originalAttributes.
   self attributeAt: 'checked' put: aBoolean.
   self
       valueInputOfType: 'checkbox'
       value: 'true'
       callback: [value contents: true].
   callbackBlock fixTemps.
   self
       hiddenInputWithCallback: [callbackBlock value: value contents]
defaultAction: actionBlock

	self
		inputWithType: 'hidden'
		named: (self callbacks registerDefaultActionCallback: actionBlock)
fileUploadWithCallback: aBlock

	aBlock fixTemps.
	self
		inputWithType: 'file'
		named: (self callbacks registerCallback: [:f | aBlock value: (f = '' ifFalse: [f])])
label: aString input: aBlock

	| id |
	id _ 'id', self context advanceKey.
	self labelFor: id do:
		[self text: aString.
		self space.
		self cssId: id.
		aBlock value]
openSelect

	| name |
	name _ self callbacks registerDispatchCallback.
	self attributes at: 'name' put: name.
	self openTag: 'select'.	
optionGroupWithLabel: aString do: aBlock

	self attributes at: 'label' put: aString.
	self tag: 'optgroup' do: aBlock
optionWithLabel: aString callback: aBlock

	self optionWithLabel: aString selected: false callback: aBlock
optionWithLabel: labelString selected: aBoolean callback: callbackBlock

	self 
		attributeAt: 'selected' put: aBoolean;
		attributeAt: 'value' put: (self callbacks registerCallback: callbackBlock).
	
	self tag: 'option' do: labelString.
parseNumber: aString

	^ [aString asNumber]
		on: Error
		do: [:e | aString]
radioButtonInGroup: radioGroupKey selected: aBoolean callback: callbackBlock

	self attributeAt: 'checked' put: aBoolean.
	
	self inputWithType: 'radio' named: radioGroupKey value: (self callbacks registerCallback: callbackBlock)
radioButtonInGroup: radioGroupKey withValue: value on: aSelector of: anObject

	self
		radioButtonInGroup: radioGroupKey
		selected: (value = (anObject perform: aSelector))
		callback: [anObject perform: aSelector asMutator with: value]
radioGroup

	^ self callbacks registerDispatchCallback.
submitButtonWithAction: actionBlock

	self inputWithType: 'submit'
		named: (self callbacks registerActionCallback: actionBlock)
submitButtonWithAction: actionBlock do: aBlock

	self buttonWithType: 'submit'
		named: (self callbacks registerActionCallback: actionBlock)
		value: nil
		do: aBlock
submitButtonWithAction: actionBlock image: aForm

	self attributes
		src: (self context urlForDocument: aForm);
		width: aForm width;
		height: aForm height.
	self inputWithType: 'image'
		named: (self callbacks registerImageCallback: actionBlock)
textAreaWithValue: value callback: callbackBlock

	|callback name |
	callback _ value
					ifNil: [[:v | callbackBlock value: (v = '' ifTrue: [nil] ifFalse: [v])]]
					ifNotNil: [callbackBlock].
	name _ self callbacks registerCallback: callback.
	self attributes
		at: 'name' put: name;
		at: 'rows' ifAbsentPut: [3];
		at: 'cols' ifAbsentPut: [25].
	
	self tag: 'textarea' do: value.
urlForAction: actionBlock

	| url |
	url _ context actionUrl withParameter:  (self callbacks registerActionCallback: actionBlock).
	^ url asString
urlForIdempotentAction: actionBlock

	| url |
	url _ context actionUrl withParameter:  (self callbacks registerIdempotentActionCallback: actionBlock).
	^ url asString
valueInputOfType: typeString value: anObject callback: callbackBlock

	|updateKey callback value|
	value _ anObject.
	callback _ callbackBlock.
	anObject isNumber ifTrue:
		[anObject isFraction
			ifTrue:
				[value _ anObject asFloat asString.
				callback _ [:v | callbackBlock value:
									(v = value ifTrue: [anObject] ifFalse: [(self parseNumber: v)])]]
			ifFalse:
				[callback _ [:v | callbackBlock value: (self parseNumber: v)]]].
	anObject isNil ifTrue:
		[value _ ''.
		callback _ [:v | callbackBlock value: (v = '' ifTrue: [nil] ifFalse: [v])]].
					
	updateKey _ self callbacks registerCallback: callback.
	self inputWithType: typeString named: updateKey value: value.
	^ updateKey

documents
anchorWithDocument: anObject mimeType: mimeType fileName: fileName text: aString

	self openAnchorWithDocument: anObject mimeType: mimeType fileName: fileName.
	self text: aString.
	self closeTag: 'a'.
anchorWithDocument: anObject mimeType: mimeType text: aString

	self anchorWithDocument: anObject mimeType: mimeType fileName: nil text: aString
anchorWithDocument: anObject text: aString

	self anchorWithDocument: anObject mimeType: nil text: aString
imageMapWithAction: aBlock form: aForm

	|point pointKey url |
	aBlock fixTemps.
	point _ ValueHolder new.
	pointKey _ self callbacks registerCallback:
								[:ptString |
								point contents: (self parseImageMap: ptString)].
	url _ self urlForAction: [aBlock value: point contents].
	
	self
		attributeAt: 'href'
		put: url, '&', pointKey, '='.
	self tag: 'a' do: [
		self attributeAt: 'border' put: 0; attributeAt: 'ismap' put: true.
		self imageWithForm: aForm.
	]
imageWithForm: aForm

	self image: (self context urlForDocument: aForm) width: aForm width height: aForm height
openAnchorWithDocument: anObject mimeType: mimeType fileName: fileName

	self attributeAt: 'href' put: (self context urlForDocument: anObject mimeType: mimeType fileName: fileName).
	self openTag: #a.
parseImageMap: aString

	|s x y|
	('?*,*' match: aString) ifFalse: [^ nil].
	s _ aString readStream.
	s upTo: $?.
	x _ s upTo: $,.
	y _ s upToEnd.
	^ x asNumber @ y asNumber
	
urlForDocument: anObject

	^ self context urlForDocument: anObject

javascript
anchorWithAction: actionBlock liveAction: liveBlock text: aString

	| uri id |
	id _ self ensureId.
	self anchorWithAction: actionBlock text: aString.
	uri _ self urlForLiveRequest: [:t :h | liveBlock value: h].
	self script: 'document.getElementById(',id printString,').onclick = liveUpdaterUri(',uri asString printString, ')'
anchorWithPopupAction: aBlock extent: aPoint do: anObject

	self
		anchorWithPopupUrl: (self urlForAction: aBlock)
		extent: aPoint
		do: anObject
anchorWithPopupAction: aBlock extent: aPoint text: aString

	self
		anchorWithPopupAction: aBlock 
		extent: aPoint 
		do: aString
anchorWithPopupAction: aBlock name: nameString extent: aPoint toggles: aCollection do: anObject

	self
		anchorWithPopupUrl: (self urlForAction: aBlock)
		name: nameString 
		extent: aPoint
		toggles: aCollection
		do: anObject
anchorWithScript: aString do: linkBlock

	self attributes at: 'onClick' put: aString.
	self anchorWithUrl: '#' do: linkBlock
autofocus: aBlock

	| id |
	id _ self ensureId.
	aBlock value.
	self script: 'document.getElementById("', id asString, '").focus()'
divWithShow: showLink hide: hideLink do: aBlock

	| linkId divId onClick |
	linkId _ self context advanceKey.
	divId _ self context advanceKey.
	onClick _ 'swapDisplay(', linkId printString, ', ', divId printString, '); return false;'.
	self attributes id: linkId; style: 'display: block'.
	self anchorWithScript: onClick do: showLink.
	self attributes id: divId; style: 'display: none'.
	self div: [
		self anchorWithScript: onClick do: hideLink.
		self div: aBlock.
	]
ensureId

	^ (self attributes at: 'id' ifAbsentPut: ['id', self context advanceKey]) value
selectFromList: aCollection selected: anObject callback: callbackBlock labels: labelsBlock liveCallback: liveBlock

	| uri id items |
	id _ self ensureId.
	items _ aCollection asArray.
	self selectFromList: items selected: anObject callback: callbackBlock labels: labelsBlock.
	uri _ self urlForLiveRequest: [:index :h | liveBlock value: (items at: index asInteger + 1 ifAbsent: []) value: h].
	self script: 'document.getElementById(',id printString,').onchange = liveSelect(',id printString,',',uri asString printString,')'
selectFromList: aCollection selected: anObject callback: aBlock labels: labelBlock other: otherBlock label: aString

	| id other  |
	id _ 'id', self context advanceKey asString.
	other _ (self context nextKey asNumber + aCollection size + 1) asString.
	self attributes onChange: 'if(this.value == ', other printString, ') {document.getElementById(', id printString, ').style.display = "inline"; document.getElementById(', id printString, ').focus()} else {document.getElementById(', id printString, ').style.display = "none"}'.
	self
		selectFromList: (aCollection asArray copyWith: aString)
		selected: anObject
		callback: [:v | v = aString ifFalse: [aBlock value: v]]
		labels: [:ea | ea = aString ifTrue: [aString] ifFalse: [labelBlock value: ea]].
	self space.
	self cssId: id.
	self attributes style: 'display: none'.
	self textInputWithValue: nil callback: [:v | v ifNotNil: [otherBlock value: v]]
textInputWithCallback: callbackBlock liveCallback: liveBlock

	| uri id |
	id _ self ensureId.
	self textInputWithValue: '' callback: callbackBlock.
	uri _ self urlForLiveRequest: liveBlock.
	self script: 'liveSearch(',id printString,',',uri asString printString,')'.
	
urlForLiveRequest: aBlock

	| text response renderer document |
	^ WACurrentSession value actionUrlForContinuation:
		[:req |
		text _ req at: 's' ifAbsent: [].
		response _ WAResponse new.
		renderer _ WAHtmlRenderer
						context: self context copy
						callbacks: self callbacks.
		document _ WAHtmlStreamDocument new stream: response stream.
		renderer context document: document.
		aBlock value: text value: renderer.
		document close.
		WACurrentSession value returnResponse: response]

model
anchorOn: aSymbol of: anObject

	self
		cssId: aSymbol;
		anchorWithAction: (MessageSend receiver: anObject selector: aSymbol)
		text: (self labelForSelector: aSymbol)
booleanMenuOn: aSymbol of: anObject

	self
		cssId: aSymbol;
		booleanMenuWithValue: (anObject perform: aSymbol)
		callback: (self callbackForSelector: aSymbol of: anObject)
callbackForSelector: aSymbol of: anObject

	^ MessageSend receiver: anObject selector: (aSymbol copyWith: $:) asSymbol
checkboxOn: aSymbol of: anObject

	self
		checkboxWithValue: (anObject perform: aSymbol)
		callback: (self callbackForSelector: aSymbol of: anObject)
labelledRowForCheckboxOn: aSymbol of: anObject

	self tableRowWithLabel: (self labelForSelector: aSymbol) column: 
		[self checkboxOn: aSymbol of: anObject]
labelledRowForList: aCollection on: aSymbol of: anObject

	self tableRowWithLabel: (self labelForSelector: aSymbol) column: 
		[self
			selectFromList: aCollection
			selected: (anObject perform: aSymbol)
			callback: (self callbackForSelector: aSymbol of: anObject)]
labelledRowForTextAreaOn: aSymbol of: anObject

	self tableRowWithLabel: (self labelForSelector: aSymbol) column: 
		[self textAreaOn: aSymbol of: anObject]
labelledRowForTextInputOn: aSymbol of: anObject

	self labelledRowForTextInputOn: aSymbol of: anObject size: nil
labelledRowForTextInputOn: aSymbol of: anObject size: sizeIntegerOrNil

	self tableRowWithLabel: (self labelForSelector: aSymbol) column: 
		[sizeIntegerOrNil ifNotNil: [self attributeAt: #size put: sizeIntegerOrNil].
		self textInputOn: aSymbol of: anObject]
submitButtonOn: aSymbol of: anObject

	self
		cssId: aSymbol;
		submitButtonWithAction: (MessageSend receiver: anObject selector: aSymbol)
		text: (self labelForSelector: aSymbol)
textAreaOn: aSymbol of: anObject

	self
		cssId: aSymbol;
		textAreaWithValue: (anObject perform: aSymbol)
		callback: (self callbackForSelector: aSymbol of: anObject)

class methods:

as yet unclassified
context: aRenderingContext callbacks: aCallbackStore

	^ self basicNew initializeWithContext: aRenderingContext callbacks: aCallbackStore

^top


- made by Dandelion -