<?xml version="1.0"?>

<st-source>
<!-- 
Name: SeasideAsync
Notice: All rights reserved
BundleName: SeasideAsync
Comment: SeasideAsync for VisualWorks

Seaside 2.7 is required for this version of SeasideAsync.

Starting with Seaside 2.6, the live-update (i.e. AJAX) features of Seaside were removed from the Seaside core parcel and placed in a new parcel named SeasideAsync.
Contributors : Avi Bryant, Michel Bany, Lukas Renggli, Philippe Marschall, Radoslav Hodnicak, Anthony Lander

Keywords: Web, Continuations, HTML, XML, AJAX, Javascript, Internet, Squeak

Port from SeasideAsync-mb.73.mcz      18 October 2007 4:54:11 pm

DevelopmentPrerequisites: #(#(#any 'SeasideBase' ''))
Parcel: #('SeasideAsync')
ParcelName: SeasideAsync
PrerequisiteParcels: #(#('SeasideBase' ''))
Version: 1.73
Date: 12:04:07 am October 19, 2007
 -->
<time-stamp>From VisualWorks®, 7.5 of April 16, 2007 on October 19, 2007 at 12:04:07 am</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>WAUnknownVariable</name>
<environment>Seaside</environment>
<super>Core.Error</super>
<private>false</private>
<indexed-type>none</indexed-type>
<inst-vars>varName </inst-vars>
<class-inst-vars></class-inst-vars>
<imports></imports>
<category>SeasideAsync-Browser</category>
<attributes>
<package>SeasideAsync-Browser</package>
</attributes>
</class>

<class>
<name>WAAsyncRenderCanvas</name>
<environment>Seaside</environment>
<super>Seaside.WARenderCanvas</super>
<private>false</private>
<indexed-type>none</indexed-type>
<inst-vars></inst-vars>
<class-inst-vars></class-inst-vars>
<imports></imports>
<category>SeasideAsync-Renderers</category>
<attributes>
<package>SeasideAsync-Renderers</package>
</attributes>
</class>

<class>
<name>WAAsyncComponent</name>
<environment>Seaside</environment>
<super>Seaside.WAComponent</super>
<private>false</private>
<indexed-type>none</indexed-type>
<inst-vars></inst-vars>
<class-inst-vars></class-inst-vars>
<imports></imports>
<category>SeasideAsync-Rendering</category>
<attributes>
<package>SeasideAsync-Rendering</package>
</attributes>
</class>

<class>
<name>WAAsyncAutoCompleteTest</name>
<environment>Seaside</environment>
<super>Seaside.WAAsyncComponent</super>
<private>false</private>
<indexed-type>none</indexed-type>
<inst-vars>autocomplete inputValue inputValueComplete selectedClass </inst-vars>
<class-inst-vars></class-inst-vars>
<imports></imports>
<category>SeasideAsync-Tests</category>
<attributes>
<package>SeasideAsync-Tests</package>
</attributes>
</class>

<class>
<name>WAAsyncPeriodicRequestTest</name>
<environment>Seaside</environment>
<super>Seaside.WAAsyncComponent</super>
<private>false</private>
<indexed-type>none</indexed-type>
<inst-vars>log </inst-vars>
<class-inst-vars></class-inst-vars>
<imports></imports>
<category>SeasideAsync-Tests</category>
<attributes>
<package>SeasideAsync-Tests</package>
</attributes>
</class>

<class>
<name>WAAsyncScripts</name>
<environment>Seaside</environment>
<super>Seaside.WAFileLibrary</super>
<private>false</private>
<indexed-type>none</indexed-type>
<inst-vars></inst-vars>
<class-inst-vars></class-inst-vars>
<imports></imports>
<category>SeasideAsync-Libraries</category>
<attributes>
<package>SeasideAsync-Libraries</package>
</attributes>
</class>

<class>
<name>WAXmlStreamDocument</name>
<environment>Seaside</environment>
<super>Seaside.WAHtmlStreamDocument</super>
<private>false</private>
<indexed-type>none</indexed-type>
<inst-vars></inst-vars>
<class-inst-vars></class-inst-vars>
<imports></imports>
<category>SeasideAsync-Rendering</category>
<attributes>
<package>SeasideAsync-Rendering</package>
</attributes>
</class>

<class>
<name>WAAsyncLiveRequestTest</name>
<environment>Seaside</environment>
<super>Seaside.WAAsyncComponent</super>
<private>false</private>
<indexed-type>none</indexed-type>
<inst-vars>input1 input2 selection count bool country province city date booleans time multiSelected nSelection selectedCurrency selectedCountry </inst-vars>
<class-inst-vars></class-inst-vars>
<imports></imports>
<category>SeasideAsync-Tests</category>
<attributes>
<package>SeasideAsync-Tests</package>
</attributes>
</class>

<class>
<name>WALiveEvent</name>
<environment>Seaside</environment>
<super>Core.Object</super>
<private>false</private>
<indexed-type>none</indexed-type>
<inst-vars>type when elementTagName elementId elementValue elementType </inst-vars>
<class-inst-vars></class-inst-vars>
<imports></imports>
<category>SeasideAsync-Rendering</category>
<attributes>
<package>SeasideAsync-Rendering</package>
</attributes>
</class>

<class>
<name>WAClassBrowserPane</name>
<environment>Seaside</environment>
<super>Seaside.WAAsyncComponent</super>
<private>false</private>
<indexed-type>none</indexed-type>
<inst-vars>componentName main </inst-vars>
<class-inst-vars></class-inst-vars>
<imports></imports>
<category>SeasideAsync-Browser</category>
<attributes>
<package>SeasideAsync-Browser</package>
</attributes>
</class>

<class>
<name>WAClassBrowserSourcePane</name>
<environment>Seaside</environment>
<super>Seaside.WAClassBrowserPane</super>
<private>false</private>
<indexed-type>none</indexed-type>
<inst-vars>sourceCode </inst-vars>
<class-inst-vars></class-inst-vars>
<imports></imports>
<category>SeasideAsync-Browser</category>
<attributes>
<package>SeasideAsync-Browser</package>
</attributes>
</class>

<class>
<name>WALiveDateInput</name>
<environment>Seaside</environment>
<super>Seaside.WADateInput</super>
<private>false</private>
<indexed-type>none</indexed-type>
<inst-vars></inst-vars>
<class-inst-vars></class-inst-vars>
<imports></imports>
<category>SeasideAsync-Renderers</category>
<attributes>
<package>SeasideAsync-Renderers</package>
</attributes>
</class>

<class>
<name>WAPermissiveBrowser</name>
<environment>Seaside</environment>
<super>Squeak.Browser</super>
<private>false</private>
<indexed-type>none</indexed-type>
<inst-vars>component </inst-vars>
<class-inst-vars></class-inst-vars>
<imports></imports>
<category>SeasideAsync-Browser</category>
<attributes>
<package>SeasideAsync-Browser</package>
</attributes>
</class>

<class>
<name>WAAsyncFocusTest</name>
<environment>Seaside</environment>
<super>Seaside.WAAsyncComponent</super>
<private>false</private>
<indexed-type>none</indexed-type>
<inst-vars>log cbValue selected radioValue </inst-vars>
<class-inst-vars></class-inst-vars>
<imports></imports>
<category>SeasideAsync-Tests</category>
<attributes>
<package>SeasideAsync-Tests</package>
</attributes>
</class>

<class>
<name>WAClassBrowserRightPane</name>
<environment>Seaside</environment>
<super>Seaside.WAClassBrowserPane</super>
<private>false</private>
<indexed-type>none</indexed-type>
<inst-vars></inst-vars>
<class-inst-vars></class-inst-vars>
<imports></imports>
<category>SeasideAsync-Browser</category>
<attributes>
<package>SeasideAsync-Browser</package>
</attributes>
</class>

<class>
<name>WAFullClassBrowser</name>
<environment>Seaside</environment>
<super>Seaside.WAAsyncComponent</super>
<private>false</private>
<indexed-type>none</indexed-type>
<inst-vars>leftComponents left rightComponents right bottom isReadOnly message browser contents </inst-vars>
<class-inst-vars></class-inst-vars>
<imports></imports>
<category>SeasideAsync-Browser</category>
<attributes>
<package>SeasideAsync-Browser</package>
</attributes>
</class>

<class>
<name>WAClassBrowserDialogDecoration</name>
<environment>Seaside</environment>
<super>Seaside.WADecoration</super>
<private>false</private>
<indexed-type>none</indexed-type>
<inst-vars></inst-vars>
<class-inst-vars></class-inst-vars>
<imports></imports>
<category>SeasideAsync-Browser</category>
<attributes>
<package>SeasideAsync-Browser</package>
</attributes>
</class>

<class>
<name>WAAutoCompleteEntryField</name>
<environment>Seaside</environment>
<super>Seaside.WAAsyncComponent</super>
<private>false</private>
<indexed-type>none</indexed-type>
<inst-vars>callback selectedObject listHeight name listWidth stringsToObjects strings prefix selectedString </inst-vars>
<class-inst-vars></class-inst-vars>
<imports></imports>
<category>SeasideAsync-Widgets</category>
<attributes>
<package>SeasideAsync-Widgets</package>
</attributes>
</class>

<comment>
<class-id>Seaside.WAAutoCompleteEntryField</class-id>
<body>This widget is a contribution from Anthony Lander
(anthony@etherealplanet.org)</body>
</comment>

<class>
<name>WALiveActionCallback</name>
<environment>Seaside</environment>
<super>Seaside.WAActionCallback</super>
<private>false</private>
<indexed-type>none</indexed-type>
<inst-vars>rendererClass callbacks </inst-vars>
<class-inst-vars></class-inst-vars>
<imports></imports>
<category>SeasideAsync-Rendering</category>
<attributes>
<package>SeasideAsync-Rendering</package>
</attributes>
</class>

<comment>
<class-id>Seaside.WALiveActionCallback</class-id>
<body>This idea is from Radoslav Hodnicak
(rh@4096.sk)

Apparently the way LiveUpdate is built currently(SeasideAsync-mb.23), the 
live callbacks have a different session step (_k) than the rest of the page,
i.e. a new continuation for each live callback. If you generate enough of
them, then the original page gets pushed so far back in the history that
it blows the cache. 

Rado's changes fix this problem by processing live callbacks in the same way
normal callbacks are processed, instead of treating them as separate continuations.

The changes are activated in WAHtmlRenderer and WARenderCanvas by sending
#urlForLiveAction: rather than #urlForLiveRequest: The old behavior can be
restored by sending #urlForLiveRequest: rather than #urlForLiveAction:

</body>
</comment>

<class>
<name>WAXmlRoot</name>
<environment>Seaside</environment>
<super>Seaside.WAHtmlRoot</super>
<private>false</private>
<indexed-type>none</indexed-type>
<inst-vars></inst-vars>
<class-inst-vars></class-inst-vars>
<imports></imports>
<category>SeasideAsync-Rendering</category>
<attributes>
<package>SeasideAsync-Rendering</package>
</attributes>
</class>

<class>
<name>WAClassBrowserLeftPane</name>
<environment>Seaside</environment>
<super>Seaside.WAClassBrowserPane</super>
<private>false</private>
<indexed-type>none</indexed-type>
<inst-vars></inst-vars>
<class-inst-vars></class-inst-vars>
<imports></imports>
<category>SeasideAsync-Browser</category>
<attributes>
<package>SeasideAsync-Browser</package>
</attributes>
</class>

<class>
<name>WALiveTimeInput</name>
<environment>Seaside</environment>
<super>Seaside.WATimeInput</super>
<private>false</private>
<indexed-type>none</indexed-type>
<inst-vars></inst-vars>
<class-inst-vars></class-inst-vars>
<imports></imports>
<category>SeasideAsync-Renderers</category>
<attributes>
<package>SeasideAsync-Renderers</package>
</attributes>
</class>

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

<body package="SeasideAsync-Browser" selector="messageText">messageText
	"Return an exception's message text."

	^'Undefined variable ' , varName printString</body>

<body package="SeasideAsync-Browser" selector="varName">varName
	"Answer the value of varName"

	^ varName</body>

<body package="SeasideAsync-Browser" selector="varName:">varName: anObject
	"Set the value of varName"

	varName := anObject</body>
</methods>

<methods>
<class-id>Seaside.WAAsyncRenderCanvas</class-id> <category>encoding</category>

<body package="SeasideAsync-Renderers" selector="encode:">encode: anObject 
	^ anObject displayString</body>
</methods>

<methods>
<class-id>Seaside.WAAsyncRenderCanvas</class-id> <category>form-elements</category>

<body package="SeasideAsync-Renderers" selector="dateInput">dateInput
	^ self brush: WALiveDateInput new</body>

<body package="SeasideAsync-Renderers" selector="timeInput">timeInput
	^ self brush: WALiveTimeInput new</body>
</methods>

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

<body package="SeasideAsync-Renderers" selector="urlForLiveAction:">urlForLiveAction: actionBlock 
	^ context actionUrl
				withParameter: (self callbacks registerLiveActionCallback: actionBlock renderer: self).
</body>
</methods>

<methods>
<class-id>Seaside.WAAsyncRenderCanvas</class-id> <category>xml</category>

<body package="SeasideAsync-Renderers" selector="spaceEntity">spaceEntity
	^'&amp;#160;'</body>
</methods>

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

<body package="SeasideAsync-Rendering" selector="rendererClass">rendererClass
	^ WAAsyncRenderCanvas</body>
</methods>

<methods>
<class-id>Seaside.WAAsyncComponent class</class-id> <category>registration</category>

<body package="SeasideAsync-Rendering" selector="registerAsApplication:">registerAsApplication: appName
	^(super registerAsApplication: appName)
		addLibrary: WAAsyncScripts;
		yourself
		</body>

<body package="SeasideAsync-Rendering" selector="registerAsAuthenticatedApplication:">registerAsAuthenticatedApplication: appName
	^(super registerAsAuthenticatedApplication: appName)
		addLibrary: WAAsyncScripts;
		yourself
		</body>
</methods>

<methods>
<class-id>Seaside.WAAsyncAutoCompleteTest</class-id> <category>initialize-release</category>

<body package="SeasideAsync-Tests" selector="initialize">initialize
	super initialize.
	autocomplete := WAAutoCompleteEntryField new name: 'Choose a class:';
				 listHeight: 8;
				 listWidth: 40;
				 yourself</body>
</methods>

<methods>
<class-id>Seaside.WAAsyncAutoCompleteTest</class-id> <category>css</category>

<body package="SeasideAsync-Tests" selector="style">style
	^'
#input input {
	width: 100%;
}
#autoComplete select {
	background-color: lightyellow;
	width: 100%;
}
form {
	width: 60%; 
	border: 1px solid green;
	padding: 5px;
	background-color: lightyellow;
}
'</body>
</methods>

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

<body package="SeasideAsync-Tests" selector="children">children
	^Array with: autocomplete</body>

<body package="SeasideAsync-Tests" selector="renderAutoCompleteOn:">renderAutoCompleteOn: html 
	| selection |
	html div id: #autoComplete;
		with: 
			[(inputValue isEmptyOrNil not and: [inputValueComplete not]) 
				ifTrue:
					[selection := self namelist 
								detect: [:ea | (ea copyFrom: 1 to: (inputValue size min: ea size)) asUppercase = inputValue asUppercase]
								ifNone: [nil].
					html select 
						id: #autoCompleteSelect;
						list: self namelist;
						size: 3;
						selected: selection;
						callback:
							[:v |
							inputValue := v.
							inputValueComplete := true];
						labels: [:ea | ea];
						liveCallback: 
							[:v :h | 
							inputValue := v.
							inputValueComplete := true.
							self renderTextFieldOn: h]]].
	html script: 'document.getElementById("autoComplete").style.width = document.getElementById("input").style.width'.
	</body>

<body package="SeasideAsync-Tests" selector="renderContentOn:">renderContentOn: html 
	| classes |


	html heading
		level: 3;
		with: 'AutoComplete Test (two different techniques)'.
	html break.

	html form
		defaultAction: [self inform: inputValue];
		with: [
			self renderTextFieldOn: html.
			html submitButton text: 'Go'].

	classes := (Object withAllSubclasses reject: [:e | e class = Metaclass]) asArray.

	autocomplete objects: classes strings: (classes collect: [:e | e name]).
	autocomplete callback: [:class | selectedClass := class].

	html form
		with: [
			html 
				text: 'You have selected: ';
				text: (selectedClass isNil ifTrue: ['Nothing'] ifFalse: [selectedClass name]);
				break;
				break.
			html render: autocomplete.
			html submitButton callback: []; text: 'Go'].
</body>

<body package="SeasideAsync-Tests" selector="renderTextFieldOn:">renderTextFieldOn: html
	html div
		id: #input;
		style: 'width: 15em';
		with: [
			html textInput
				id: #inputField;
				value: inputValue;
				callback:
					[:v |
					inputValue := v. 
					inputValueComplete := true];
				liveCallback: 
					[:v :h | 
					inputValue := v.
					inputValueComplete := false.
					self renderAutoCompleteOn: h]].
	self renderAutoCompleteOn: html</body>
</methods>

<methods>
<class-id>Seaside.WAAsyncAutoCompleteTest</class-id> <category>constants</category>

<body package="SeasideAsync-Tests" selector="namelist">namelist
	^#(Andrew Bengt Chuck Daniel Elmer Franz George Henry Isildur) ,
		#(Jefferson Jeffrey Jeremy Jerry John Josuah Kleber Lewis Mike) , 
			#( Nancy Oscar Peter Robert Roger Stephen Steven Tobias Vincent William)</body>
</methods>

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

<body package="SeasideAsync-Tests" selector="description">description
	^'Auto-completion examples'</body>

<body package="SeasideAsync-Tests" selector="initialize">initialize
	self registerAsApplication: 'tests/async/autocomplete'</body>
</methods>

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

<body package="SeasideAsync-Tests" selector="initialize">initialize
	super initialize.
	log := String new writeStream</body>
</methods>

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

<body package="SeasideAsync-Tests" selector="renderContentOn:">renderContentOn: html

	self renderRefreshedElementsOn: html.
	self renderRefreshedLogOn: html.</body>

<body package="SeasideAsync-Tests" selector="renderLogOn:">renderLogOn: html
	html withLineBreaks: log contents</body>

<body package="SeasideAsync-Tests" selector="renderRefreshedElementsOn:">renderRefreshedElementsOn: html 
	| liveUpdateBlock |
	liveUpdateBlock := [:event :h | 
				log nextPutAll:
						'Timed log ' , event type , 
						' at ' , Time now printString , 
						' for ' , event elementType ,
						' id=' , event elementId;
					 cr;
					 nextPut: Character lf.
			h text: Time now printString].
	html table
		with: [html tableRow
				with: [html tableData with: 'Current Time in default div:'.
					html tableData
						with: ["Anonymous div."
							log nextPutAll: 'Anonymous div id=' , html peekNextId; cr; nextPut: Character lf.
							html div refreshWith: liveUpdateBlock every: 3 seconds]].
			html tableRow
				with: [html tableData with: 'Current Time in default span:'.
					html tableData
						with: ["Anonymous span. "
							log nextPutAll: 'Anonymous span id=' , html peekNextId; cr; nextPut: Character lf.
							html span refreshWith: liveUpdateBlock every: 5 seconds]].
			html tableRow
				with: [html tableData with: 'Current Time in named div:'.
					html tableData
						with: ["Named div"
							log nextPutAll: 'Named div id=livediv'; cr; nextPut: Character lf.
							html div id: 'livediv';
								 refreshWith: liveUpdateBlock every: 1 seconds]].
			html tableRow
				with: [html tableData with: 'Current Time in named span:'.
					html tableData
						with: ["Named span"
							log nextPutAll: 'Named span id=livespan'; cr; nextPut: Character lf.
							html span id: 'livespan';
								 refreshWith: liveUpdateBlock every: 2 seconds]]]</body>

<body package="SeasideAsync-Tests" selector="renderRefreshedLogOn:">renderRefreshedLogOn: html
	html heading level: 3; with: 'Refreshed log'.
	html div
		id: 'log';
		refreshWith:
			[ :event :h | 
			h break.
			self renderLogOn: h]
	 	every: 5 seconds 
			
</body>
</methods>

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

<body package="SeasideAsync-Tests" selector="description">description
	^'Periodical update examples'</body>

<body package="SeasideAsync-Tests" selector="initialize">initialize
	self registerAsApplication: 'tests/async/periodictests'.</body>
</methods>

<methods>
<class-id>Seaside.WAAsyncScripts</class-id> <category>scripts</category>

<body package="SeasideAsync-Libraries" selector="ajaxJs">ajaxJs
	^ '

var requests = [];

function liveUpdater(uriFunc, ret)
{
	function xmlUpdater()
	{
		return sendHttpCallback(uriFunc(), ret);
	}
	return xmlUpdater;

	//	Build and send HTTP request to Seaside

	function sendHttpCallback(uri, ret, respFunc)
	{
		var request = newHttpRequest();
		if (!request)
			return ret;
		if (!respFunc)
			respFunc = processRequestChange;
		request.onreadystatechange = respFunc;
		// Resolve xml entity before issuing the request
		var uri = addParameter(uri, "timestamp", (new Date()).getTime().toString());
		var regex = new RegExp("&amp;amp;", "g");
		uri = uri.replace(regex,"&amp;");
		request.open("GET", uri, true);
		setRequestHeaders(request);
		request.send(null);
		requests[requests.length] = request;
		// debug("GET " + uri);
		// debug ("Pending " + requests.length);
		return ret;
	}
}


//	Process state change of HTTP requests

function processRequestChange()
	{
		var pendingRequests = [];
		for ( var rx = 1 ; rx &lt;= requests.length ; rx++ ) {
			var request = requests[rx-1];
			if (request.readyState == 4) {
				if (request.responseText.length &gt; 51) handleLiveResponse(request);
			} else {
				pendingRequests[pendingRequests.length] = request;
			}
		}
		if (requests.length != pendingRequests.length) {
			requests = pendingRequests
			// debug ("Pending " + requests.length);
		}
	}


//	Parse HTTP response from the Seaside live callbacks as XML and update the document

function handleLiveResponse(request)
	{	
		var doc = request.responseXML;
		var replacements = [];
		var anyReplacement = false;
		var anyScriptEvaluated = false;
		// debug("HTTP status " + request.status + " " + request.statusText);
		// debug(request.responseText);			
		// debug(request.getAllResponseHeaders() );	
		if (doc != null) {
			var elements = doc.getElementsByTagName("*");
			if (elements.length == 0) {
				// IE does not support the above, use an alternative hard-coded technique
				elements = getAllElements(doc)
			}
			// Find html elements with the id= attribute
			for ( var x = 1 ; x &lt;= elements.length ; x++ ) {
				var elem = elements[x-1];
				if (elem.tagName == "body") {
					var body = xmlString(elem);
				}
				var attributes = elem.attributes;
				if (attributes.length &gt; 0) {
					for ( var ax = 1 ; ax &lt;= attributes.length ; ax++ ) {
						var attr = attributes[ax-1];
						var attrName = attr.name;
						if (attrName == "id") {
							// Find the html element in the document that has a matching id and replace it
							var docElement = document.getElementById(attr.value);
							if (docElement) {
								if (!includes(replacements,elem)) {
									// HTML is only updated with the parent at highest level
									// Resolve IE and Opera issue where &lt;br&gt;&lt;/br&gt; skips two lines
									var regex = new RegExp("&lt;br&gt;&lt;/br&gt;", "g");
									var replacement = xmlString(elem).replace(regex,"&lt;br/&gt;");
									try {
										docElement.innerHTML = replacement;
										anyReplacement = true;
										replacements[replacements.length] = attr.value;
									} catch (e) {
										// Some browsers (like Safari) have read-only elements
										// IE does not allow form elements for innerHTML
									}
								}
							}
						}
					}
				}   
			}
			// Find html &lt;script&gt; elements and execute them
			for ( var x = 1 ; x &lt;= elements.length ; x++ ) {
				var elem = elements[x-1];
				if (elem.tagName == ''script'') {
					// debug("About to evaluate script");
					// debug(xmlString(elem));
					eval(xmlString(elem));
					// debug("Evaluated");
					anyScriptEvaluated = true;
				}
			}
		}
		if (!anyReplacement &amp; !anyScriptEvaluated) {
			if ( body ) {
				// Here when XML could be parsed but was unproductive
				// Most probable reason : a bug in the live callback code
				alert("No replacement and no script evaluated, probable bug in your callback code.\n\n"
					+ "See below the response produced by the callback code.\n\n"
					+ request.responseText);
				// document.body.innerHTML = body;
			} else {
				// Here when XML could not be parsed
				// Most probable reason : response does not have an xml content
				// For instance : an exception in the live callback
				// So we replace the whole page with the whole response
				try {
					if (!request.responseText.length == 0) {
						document.body.innerHTML = request.responseText;
					} else {
						debug("HTTP code " + request.status + " " + request.statusText
									+ " with no text in response!");
					}	
				} catch (e) {
					// In some cases of concurrency
					// readyState is 4, but there status is not available
					debug("HTTP response status not available although readyState is 4!");
					debug(request.responseText);	
				}					
			}
		}
	}

'</body>

<body package="SeasideAsync-Libraries" selector="eventTrackingJs">eventTrackingJs
	^ '
var eventRequests = [];

function liveEventTrackerUri(event, uri)
{
	var target = (event.target) ? event.target : event.srcElement;
	var type = target.type;
	var value = target.value;
	if (type == "radio") value = target.checked;
	if (type == "checkbox") value = (value == "on");
	uri = addParameter(uri, "timestamp", (new Date()).getTime().toString());
	uri = addParameter(uri, "eventType", event.type);
	uri = addParameter(uri, "targetValue", value);
	uri = addParameter(uri, "targetType", type);
	uri = addParameter(uri, "tagName", target.tagName);
	uri = addParameter(uri, "id", target.id);
//	Cursor position ?
	var request = newHttpRequest();
	if (!request) return false;
	request.onreadystatechange = processEventTracker;
	// Resolve xml entity before issuing the request
	var regex = new RegExp("&amp;amp;", "g");
	uri = uri.replace(regex,"&amp;");
	request.open("GET", uri, true);
	setRequestHeaders(request);
	request.send(null);
	eventRequests[eventRequests.length] = request;
	return false;
}

//	Process state change of HTTP requests

function processEventTracker()
{
	var pendingEvents = [];
	for ( var rx = 1 ; rx &lt;= eventRequests.length ; rx++ ) {
		var request = eventRequests[rx-1];
		if (request.readyState == 4) {
			// debug (request.responseText);
			var doc = request.responseXML;
			var body = doc.getElementsByTagName("body")[0];
			// Discard empty responses
			if (body.childNodes.length &gt; 0) handleLiveResponse(request);
		} else {
			pendingEvents[pendingEvents.length] = request;
		}
	}
	if (eventRequests.length != pendingEvents.length) {
		eventRequests = pendingEvents;
		// debug ("Pending events " + eventRequests.length);
	}
}

'</body>

<body package="SeasideAsync-Libraries" selector="liveUpdateJs">liveUpdateJs
	^ '

	var nav;
	if (navigator.userAgent.indexOf("Safari") &gt; 0)
			nav = "Safari";
	else if (navigator.product == "Gecko")
			nav = "Gecko";
	else
			nav = "IE";

function liveUpdaterUri(uri)
{
	return liveUpdater(function() { return uri; } , false);
}

// Selection in a list box possibly with multiple selections, add the selected indexes to the callback
function liveSelect(id, uri)
{
	function constructUri()
	{

		var indexes = [];
		var options = document.getElementById(id).options;
		for ( var x = 1 ; x &lt;= options.length ;  x++ ) {
			if (options[x-1].selected) indexes[indexes.length+1] = x;
		}
		return addParameter(uri, "ms", indexes.toString());
	}
	return liveUpdater(constructUri, false);
}

// Key stroke in an entry field, add the field value to the callback
function liveSearch(id, uri)
{
	function constructUri()
	{
		return addParameter(uri, "s", document.getElementById(id).value);
	}

   	var updater = liveUpdater(constructUri, false);
	var last = document.getElementById(id).value;
	var timeout = false;
  
	function update()
	{
		if (last != document.getElementById(id).value) {
			last = document.getElementById(id).value;
			updater();
		}
	}
	   
	function start() {
		if (timeout)
			window.clearTimeout(timeout);
		timeout = window.setTimeout(update, 300);
	}

	if (navigator.userAgent.indexOf("Safari") &gt; 0)
		document.getElementById(id).addEventListener("keydown",start,false);
	else if (navigator.product == "Gecko")
		document.getElementById(id).addEventListener("keypress",start,false);
	else
		document.getElementById(id).attachEvent("onkeydown",start);
}

// Click
function liveClick(id, uri)
{
	return liveUpdaterUri(uri);
}

// Click in a checkbox
function liveCheck(id, uri)
{
	function constructUri()
	{
		return addParameter(uri, "s", document.getElementById(id).checked);
	}
	return liveUpdater(constructUri);
}

function liveScroll(id, uri)
{
   function constructUri()
   {
         return addParameter(uri, "s", document.getElementById(id).scrollTop.toString());
   }
   
   var updater = liveUpdater(constructUri, false);
   var timeout = false;

    function start() {
	   if (timeout)
	       window.clearTimeout(timeout);
	   
    	   timeout = window.setTimeout(updater, 100);
    }
   return start;
}

function timedUpdate(uri, milliSeconds)
{
	var updater = liveUpdaterUri(uri, false);
	updater();
	var again = "timedUpdate(\""+uri+"\","+milliSeconds+")";
	setTimeout(again, milliSeconds);
}
'</body>

<body package="SeasideAsync-Libraries" selector="liveUpdateUtilitiesJs">liveUpdateUtilitiesJs
	^'
function addParameter(uri, key, value)
{
	// See http://xkr.us/articles/javascript/encode-compare/
	var separator = "?";
	if (uri.indexOf("?") &gt;= 0)
		separator = "&amp;";
	return uri + separator + key + "=" + encodeURIComponent(value);
}

// Function below to instantiate an XMLHttpRequest object
// Credits: http://jibbering.com/2002/4/httprequest.html
// Credits: http://www.toutjavascript.com/savoir/xmlhttprequest.php3
function newHttpRequest()
{
	var httpRequest = false;
	if(window.XMLHttpRequest)
		// Firefox, Mozilla, Safari
		httpRequest = new XMLHttpRequest();
	else if(window.ActiveXObject) 
		// Internet Explorer
		{	try {  
 				httpRequest = new ActiveXObject("Microsoft.XMLHTTP");
			} catch (e) {
  				try {
   					httpRequest = new ActiveXObject("Msxml2.XMLHTTP");
				} catch (E) {
					httpRequest = false;
 	 			}
			}
		}
	return httpRequest;
}

function setRequestHeaders(request)
{
	request.setRequestHeader("X-Requested-With","XMLHttpRequest");
	request.setRequestHeader("X-Requested-By","SeasideAsync");
	request.setRequestHeader("Accept","text/html, application/xml, text/xml, */*");
}

// Functions below to rebuild the xml string of an element
function xmlString (element) {
	var xml = "";
	for ( var x = 1 ; x &lt;= element.childNodes.length ;  x++ ) {
		var node = element.childNodes[x-1];
		xml += outerXmlString(node);
	}
	return xml;
}
function outerXmlString (element) {
	if (!element.tagName) {
		var elementData = element.data;
		// Resolve entities
		var regex = new RegExp("&lt;", "g");
		elementData = elementData.replace(regex,"&amp;lt;");
		var regex = new RegExp("&gt;", "g");
		elementData = elementData.replace(regex,"&amp;gt;");
		return elementData;
	}
	var xml = "&lt;" + element.tagName;
	for ( var x = 1 ; x &lt;= element.attributes.length ;  x++ ) {
		var attr = element.attributes[x-1];
		xml += " " + attr.name + "=" + ''"'' + attr.value + ''"'';
	}
	xml += "&gt;";
	for ( var x = 1 ; x &lt;= element.childNodes.length ;  x++ ) {
		var node = element.childNodes[x-1];
		xml += outerXmlString(node);
	}
	xml += "&lt;/" + element.tagName + "&gt;";
	return xml;
}

// Function below to get stable equivalent of document.getElementsByTagName("*")
// Credits: http://www.siteexperts.com/tips/contents/ts16/page3.asp
function getAllElements(document)
{
	var elements = [];
	getElements(elements,document.childNodes[0])
	return elements;   
}

// Function below to recursively and deeply collect all sub-elements of an element
// Credits: http://www.siteexperts.com/tips/contents/ts16/page3.asp
function getElements(collection, element) {
	if (element == null) return;
	for ( var x = 1 ; x &lt;= element.childNodes.length ; x++ ) {
		var node = element.childNodes[x-1];
		if (node.nodeType == 1) {
			collection[collection.length] = node[x-1];
				getElements(collection,element);
		}
	}
}

// Function below to detect if the id of any parent of an element is part of an array
function includes(collection, element) {
	var parent = element.parentNode;
	while (parent.tagName) {
		var attributes = parent.attributes;
		if (attributes.length &gt; 0) {
			for ( var ax = 1 ; ax &lt;= attributes.length ; ax++ ) {
				var attr = attributes[ax-1];
				var attrName = attr.name;
				if (attrName == "id") {
					for ( var x = 1 ; x &lt;= collection.length ; x++ ) {
						if (collection[x-1] == attr.value) return true;
					}
				}
			}
		}
		parent = parent.parentNode;
	}
	return false;
}

// Get the text of the body element
function bodyText(doc)
{
	var elements = doc.getElementsByTagName("*");
	if (elements.length == 0) {
		// IE does not support the above, use an alternative hard-coded technique
		elements = getAllElements(doc)
	}
	// Find html elements with the id= attribute
	for ( var x = 1 ; x &lt;= elements.length ; x++ ) {
		var elem = elements[x-1];
		if (elem.tagName == "BODY") {
			var body = xmlString(elem);
		}
	}
	return body;	
}

function debug(aString)
{
	var newDiv = document.createElement("div");
	newDiv.setAttribute("style","position: relative; top: -1.5em; "
		+ "font-size: 60%; font-family: Verdana; color: blue; "
		+ "width: 100%; background-color: lightyellow");
	var textNode = document.createTextNode(aString);
	newDiv.appendChild(textNode);
	document.body.appendChild(newDiv);
}

'</body>
</methods>

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

<body package="SeasideAsync-Libraries" selector="selectorsToInclude">selectorsToInclude
	^ #( ajaxJs eventTrackingJs liveUpdateJs liveUpdateUtilitiesJs )</body>
</methods>

<methods>
<class-id>Seaside.WAAsyncScripts class</class-id> <category>processing</category>

<body package="SeasideAsync-Libraries" selector="updateRoot:">updateRoot: anHtmlRoot
	"This method is not supplied by superclass in Seaside 2.7"
	self new
		do: [:ea | anHtmlRoot addScript: ea]</body>
</methods>

<methods>
<class-id>Seaside.WAXmlStreamDocument</class-id> <category>public</category>

<body package="SeasideAsync-Rendering" selector="close">close
	self writeLoadScripts.
	self closeTag: 'body'</body>

<body package="SeasideAsync-Rendering" selector="writeLoadScripts">writeLoadScripts
	| session renderer aStream |
	session := WACurrentSession value.
	(session isNil or: [ session onLoadScripts isEmpty ])
		ifTrue: [ ^ self ].
	renderer := WAStaticHtmlCanvas document: self.
	aStream := (String new: 200) writeStream.
	session onLoadScripts
		do: [ :each | aStream nextPutAll: each displayString ]
		separatedBy: [ aStream nextPut: $; ].
	renderer script: aStream contents.		
	session clearLoadScripts</body>
</methods>

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

<body package="SeasideAsync-Tests" selector="initialize">initialize
	super initialize.
	count := 0.
	bool := false.
	input1 := String new.
	input2 := String new.
	multiSelected := #(0 7 ).
	self country: 'Argentina'.
	booleans := Dictionary new at: #English put: true;
				 at: #Russian put: false;
				 at: #Japanese put: false;
				 yourself</body>
</methods>

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

<body package="SeasideAsync-Tests" selector="renderAnchorOn:">renderAnchorOn: html 
	html anchor
		callback: ["The live callback disables the regular callback"
			self error: 'Should not come here'];
		 onClick: 'debug("Good that you clicked that link, thanks from a piece of Javascript.")';
		
		liveCallback: [:h | 
			"The live callback does not disable previous onclick"
			h span id: 'timestamp';
				 with: TimeStamp now.
			h span id: 'time';
				 with: Time now];
		 with: 'Show time'.
	html space.
	html span id: 'timestamp';
		 with: ''</body>

<body package="SeasideAsync-Tests" selector="renderButtonOn:">renderButtonOn: html 
	html
		form: [html submitButton
				callback: ["The live callback disables the regular callback"
					self error: 'Should not come here'];
				"The live callback does not disable previous onclick"

				 onClick: 'debug("Good that you clicked that button, thanks from a piece of Javascript.")';
				
				liveCallback: [:h | 
					h span id: 'timestamp-button';
						 with: TimeStamp now.
					h span id: 'time';
						 with: Time now];
				 text: 'Show time';
				"The live callback disables any subsequent onclick"
				
				 onClick: 'debug("This should not display")'
			].
	html space.
	html span id: 'timestamp-button';
		 with: ''</body>

<body package="SeasideAsync-Tests" selector="renderCheckBoxOn:">renderCheckBoxOn: html

	html form:
		[html checkbox
				value: bool; 
				callback: [:v | bool := v];
				liveCallback: 
					[:item :h |
					bool := item.
					"Update multiple areas of the document using one live callback"
					h span id: 'checkbox'; with: (bool ifTrue: ['checked'] ifFalse: ['unchecked']).
					h span id: 'chk'; with: (bool ifTrue: ['checked'] ifFalse: ['unchecked']).
					].
			
		html space.
		html span id: 'chk'; with: (bool ifTrue: ['checked'] ifFalse: ['unchecked']).
		].
	</body>

<body package="SeasideAsync-Tests" selector="renderContentOn:">renderContentOn: html 
	self renderWarningOn: html.
	html
		table: [html
				tableRow: [html
						tableData: [self renderInput1On: html.
							self renderInput2On: html.
							self renderDateInputOn: html.
							self renderTimeInputOn: html.
							self renderListOn: html.
							self renderMultiSelectOn: html.
							self renderCheckBoxOn: html.
							self renderRadioOn: html.
							self renderAnchorOn: html.
							html break.
							self renderButtonOn: html].
					html
						tableData: [html heading level:3; with: 'Forward'.
							html div id: 'forward';
								 with: ''.
							html heading level:3; with: 'Backward'.
							html div id: 'backward';
								 with: ''.
							html heading level:3; with: 'Date'.
							html div id: 'date';
								 with: ''.
							html heading level:3; with: 'Time'.
							html div id: 'xtime';
								 with: ''.
							html heading level:3; with: 'Selection'.
							html span id: 'selection';
								 with: ''.
							html heading level:3; with: 'Multiple Selection'.
							html span id: 'multiselect';
								 with: ''.
							html heading level:3; with: 'Checkbox'.
							html span id: 'checkbox';
								 with: ''.
							html heading level:3; with: 'Radio buttons'.
							html span id: 'radio';
								 with: booleans printString.
							html heading level:3; with: 'Time'.
							html span id: 'time';
								 with: '']]].
	html heading level:3; with: 'Nested live callbacks'.
	self renderCountriesOn: html.
	self renderCurrenciesOn: html.
	self renderWarningOn: html</body>

<body package="SeasideAsync-Tests" selector="renderDateInputOn:">renderDateInputOn: html

	html form:
		[html dateInput
			value: date;
			liveCallback:
					[:value :h |
					date := value.
					h div id: 'date'; with: date.
					h span id: 'dat'; with: 'Value entered= ' , date displayString.
					].
		html space.
		html span id: 'dat'; with: 'Value entered= ' , date displayString.
		].</body>

<body package="SeasideAsync-Tests" selector="renderInput1On:">renderInput1On: html

	html form:
		[html textInput
				value: input1; 
				callback: [:v | input1 := v];
				liveCallback: 
					[:text :h |
					input1 := text. 
					"Update multiple areas of the document using one live callback"
					h div id: 'forward'; with:
						[h unorderedList:
							[input1 do:
								[:c | 
								h listItem:
									[h anchor 
									callback: [self inform: c displayString];
									text: c displayString]]]].
					h span id: 'fwd'; with:
						[h text: 'Value entered= ' , input1.
						h script: 'debug("javascript in a live callback ' , input1 , ' ");']
					].
		html space.
		html span id: 'fwd'; with:'Value entered= ' , input1.
		html break.
		html text: 'Above: Javascript attached= debug("Javascript in a live callback xxx ");'
		].
</body>

<body package="SeasideAsync-Tests" selector="renderInput2On:">renderInput2On: html

	html form:
		[html textArea
				value: input2;
				callback: [:v | input2 := v];
				liveCallback: 
					[:text :h |
					input2 := text.
					h div id: 'backward'; with: 
						[h unorderedList: 
							[input2 reverse do: 
								[:c |
								h listItem: 
									[h anchor 
										callback: [self inform: c displayString];
										text: c displayString]]]].
					h span id: 'bwd'; with: 'Value entered= ' , input2
					].
		html space.
		html span id: 'bwd'; with: 'Value entered= ' , input2
		].
</body>

<body package="SeasideAsync-Tests" selector="renderListOn:">renderListOn: html

	html form:
		[html select 
				list: #(Horse Cat Dog Camel Cow Pterodactyl);
				beOptional;
				optionalLabel: '&lt;select&gt;';
				selected: selection; 
				labels: [:ea | ea displayString];
				liveCallback:
					[:item :h |
					selection := item. 
					"Update multiple areas of the document using one live callback"
					h span id: 'selection'; with: selection.
					h span id: 'sel'; with: 'Value selected= ' , selection displayString
					].
		html space.
		html span id: 'sel'; with: 'Value selected= ' , selection displayString
		].
</body>

<body package="SeasideAsync-Tests" selector="renderMultiSelectOn:">renderMultiSelectOn: html 
	html
		form: [html multiSelect list: #(0 1 2 3 4 5 6 7 8 9 );
				 selected: multiSelected;
				
				labels: [:ea | ea displayString];
				
				callback: [:aCollection | multiSelected := aCollection];
				
				liveCallback: [:aCollection :h | 
					multiSelected := aCollection.
					h span id: 'multiselect';
						 with: multiSelected.
					h span id: 'multisel';
						 with: 'Values selected= ' , multiSelected displayString].
			html space.
			html span id: 'multisel';
				 with: 'Values selected= ' , multiSelected displayString]</body>

<body package="SeasideAsync-Tests" selector="renderRadioOn:">renderRadioOn: html
	html
		form: [
			html table: [
				html tableRow: [
					html tableData: 'Language'.
					html tableData: 'Yes'.
					html tableData: 'No'].

				booleans associationsDo:
					[:assoc | 
					| group |
					html tableRow: [
						group := html radioGroup.
						html tableData: assoc key.
						html tableData: [
							(html radioButton)
								id: assoc key asString , '-on';
								group: group;
								selected: assoc value;
								liveCallback:
									[:item :h |
									assoc value: true.
									h span id: 'radio'; with: booleans printString]].
						html tableData: [
							(html radioButton)
								id: assoc key asString , '-off';
								group: group;
								selected: assoc value not;
								liveCallback:
									[:item :h |
									assoc value: false.
									h span id: 'radio'; with: booleans printString.]].
					]].
			]]
</body>

<body package="SeasideAsync-Tests" selector="renderTimeInputOn:">renderTimeInputOn: html

	html form:
		[html timeInput
			value: time;
			liveCallback:
					[:value :h |
					time := value.
					h div id: 'xtime'; with: time.
					h span id: 'tim'; with: 'Value entered= ' , time displayString.
					].
		html space.
		html span id: 'tim'; with: 'Value entered= ' , time displayString.
		].</body>

<body package="SeasideAsync-Tests" selector="renderWarningOn:">renderWarningOn: html 
	"The #insert: method was not available in 2.6a1"
	(html respondsTo: #insert:) ifFalse:
		[html heading: 'Warning : Canvas rendering is unfinished in this release' level: 2]   </body>
</methods>

<methods>
<class-id>Seaside.WAAsyncLiveRequestTest</class-id> <category>nested</category>

<body package="SeasideAsync-Tests" selector="city:">city: anObject
	city := anObject.
</body>

<body package="SeasideAsync-Tests" selector="cityNames">cityNames
	province = 'Oranjestad'
		ifTrue: [^#( 'Casibari' 'Bubali')	].
	province = 'Santa Cruz'
		ifTrue: [^#( 'Arikok' 'Yamonta')	].
	province = 'Buenos Aires'
		ifTrue: [^#('La Plata' 'Azul')].
	province = 'Cordoba'
		ifTrue: [^#('Alta Gracia' 'La Falda')].
	province = 'California'
		ifTrue: [^#('Los Angeles' 'Monterey' 'San Jose' 'Santa Monica')].
	province = 'Ohio'
		ifTrue: [^#('Cincinnati' 'Dayton' 'Clifton')].
	^#()


</body>

<body package="SeasideAsync-Tests" selector="country:">country: anObject
	country := anObject. 
	self province: self provinceNames first. 
</body>

<body package="SeasideAsync-Tests" selector="province:">province: anObject
	province := anObject.
	self city: self cityNames first.

</body>

<body package="SeasideAsync-Tests" selector="provinceNames">provinceNames
	country = 'Aruba'
		ifTrue: [^#('Oranjestad' 'Santa Cruz')].
	country = 'Argentina'
		ifTrue: [^#( 'Buenos Aires' 'Cordoba')].
	country = 'USA'
		ifTrue: [^#( 'Ohio' 'California')].
	^#()


</body>

<body package="SeasideAsync-Tests" selector="renderCitiesOn:">renderCitiesOn: html

	html span id: 'citySelector'; with:
		[(html select)
			list: self cityNames;
			selected: city;
			callback:[:f | city := f ];						
			labels: [:ea |  ea ]]		
</body>

<body package="SeasideAsync-Tests" selector="renderCountriesOn:">renderCountriesOn: html
	(html select)
		list: #( 'Argentina' 'Aruba' 'USA' );
		selected: country;
		callback: [:f | country := f]; 
		labels: [:ea |  ea ];
		liveCallback: 
			[:anObject :h | 
			country := anObject. 
			province := self provinceNames first. 
			city := self cityNames first.
			self renderProvincesOn: h].

	self renderProvincesOn: html.
</body>

<body package="SeasideAsync-Tests" selector="renderCountryListOn:">renderCountryListOn: html

	html span
		id: 'countryList';
		with: 
			[selectedCurrency notNil ifTrue:
				[selectedCurrency == #Euros ifTrue: [
					html select 
						list: #(Germany France Spain Italy Belgium Ireland Austria Luxemburg Netherlands);
						beOptional;
						optionalLabel: '&lt;Select a ''country'' &amp; watch&gt;'; "May not contain angle brackets"
						selected: selectedCountry; 
						labels: [:ea | ea displayString];
						liveCallback:
							[:item :h |
							selectedCountry := item. 
							self renderCountryStatusOn: h].
					html space.
					self renderCountryStatusOn: html]
				ifFalse:
					[html text: 'This is not euro, cannot show euroland countries']]]</body>

<body package="SeasideAsync-Tests" selector="renderCountryStatusOn:">renderCountryStatusOn: html

	html span
		id: 'countryStatus';
		with: 
			[selectedCountry notNil ifTrue:
				[html text: 'That''s correct, ' , selectedCountry displayString , ' uses Euros']].
</body>

<body package="SeasideAsync-Tests" selector="renderCurrenciesOn:">renderCurrenciesOn: html

	html form:
		[html select 
				list: #(Euros Dollars Yens);
				beOptional;
				optionalLabel: '&lt;select a currency&gt;';
				selected: selectedCurrency; 
				labels: [:ea | ea displayString];
				liveCallback:
					[:item :h |
					selectedCurrency := item. 
					self renderCountryListOn: h].
		html space.
		self renderCountryListOn: html]
</body>

<body package="SeasideAsync-Tests" selector="renderProvincesOn:">renderProvincesOn: html

	html span id: 'provinceSelector'; with:
		[(html select)
			list:  self provinceNames;
			selected: province;
			callback: [:f | province := f]; 
			labels: [:ea |  ea ];
			liveCallback: 
				[:anObject :h | 
				province := anObject. 
				city := self cityNames first.
				self renderCitiesOn: h]].
	self renderCitiesOn: html.


</body>
</methods>

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

<body package="SeasideAsync-Tests" selector="description">description
	^'Live update examples'</body>

<body package="SeasideAsync-Tests" selector="initialize">initialize
	self registerAsApplication: 'tests/async/livetests'.</body>
</methods>

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

<body package="SeasideAsync-Tests" selector="canBeRoot">canBeRoot
	^ true</body>
</methods>

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

<body package="SeasideAsync-Rendering" selector="elementId">elementId
	^ elementId</body>

<body package="SeasideAsync-Rendering" selector="elementId:">elementId: aString
	elementId := aString</body>

<body package="SeasideAsync-Rendering" selector="elementTagName">elementTagName
	^ elementTagName</body>

<body package="SeasideAsync-Rendering" selector="elementTagName:">elementTagName: aString
	elementTagName := aString</body>

<body package="SeasideAsync-Rendering" selector="elementType">elementType
	^ elementType</body>

<body package="SeasideAsync-Rendering" selector="elementType:">elementType: aString
	elementType := aString</body>

<body package="SeasideAsync-Rendering" selector="elementValue">elementValue
	^ elementValue</body>

<body package="SeasideAsync-Rendering" selector="elementValue:">elementValue: anObject
	elementValue := anObject</body>

<body package="SeasideAsync-Rendering" selector="type">type
	^ type</body>

<body package="SeasideAsync-Rendering" selector="type:">type: aString
	type := aString</body>

<body package="SeasideAsync-Rendering" selector="when">when
	^ when</body>
</methods>

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

<body package="SeasideAsync-Rendering" selector="value">value
	type = 'check' ifTrue: [^self valueAsBoolean].
	^elementValue.</body>

<body package="SeasideAsync-Rendering" selector="valueAsBoolean">valueAsBoolean
	^elementValue = 'true'</body>
</methods>

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

<body package="SeasideAsync-Rendering" selector="fromRequest:">fromRequest: aRequest 
	aRequest isLiveRequest
		ifFalse: [^ self error: 'Not a live request'].
	when := aRequest at: 'timestamp'.
	(aRequest includesKey: 's')
		ifTrue: ["Live callback"
			elementValue := aRequest at: 's'].
	(aRequest includesKey: 'ms')
		ifTrue: ["Live callback multi-select"
			elementValue := (aRequest at: 'ms')
						findTokens: ','].
	(aRequest includesKey: 'eventType')
		ifTrue: ["Event tracking"
			type := aRequest at: 'eventType'.
			elementType := aRequest at: 'targetType'.
			elementTagName := aRequest at: 'tagName'.
			elementId := aRequest at: 'id'.
			elementValue := aRequest at: 'targetValue']</body>
</methods>

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

<body package="SeasideAsync-Rendering" selector="newFromRequest:">newFromRequest: aRequest
	^self new fromRequest: aRequest</body>
</methods>

<methods>
<class-id>Seaside.WAClassBrowserPane</class-id> <category>delegation</category>

<body package="SeasideAsync-Browser" selector="canRemoveSourceCode">canRemoveSourceCode
	^self main canRemoveSourceCode</body>

<body package="SeasideAsync-Browser" selector="canRenameSourceCode">canRenameSourceCode
	^self main canRenameSourceCode</body>

<body package="SeasideAsync-Browser" selector="canSaveSourceCode">canSaveSourceCode
	^self main canSaveSourceCode</body>

<body package="SeasideAsync-Browser" selector="classes">classes
	^self main classes</body>

<body package="SeasideAsync-Browser" selector="isReadOnly">isReadOnly
	^self main isReadOnly</body>

<body package="SeasideAsync-Browser" selector="isReadOnly:">isReadOnly: aBoolean
	^self main isReadOnly: aBoolean</body>

<body package="SeasideAsync-Browser" selector="listSize">listSize
	^self main listSize</body>

<body package="SeasideAsync-Browser" selector="package">package
	^self main package</body>

<body package="SeasideAsync-Browser" selector="package:">package: anObject
	^self main package: anObject</body>

<body package="SeasideAsync-Browser" selector="packages">packages
	^self main packages</body>

<body package="SeasideAsync-Browser" selector="pause">pause
	^self main pause</body>

<body package="SeasideAsync-Browser" selector="protocol">protocol
	^self main protocol</body>

<body package="SeasideAsync-Browser" selector="protocol:">protocol: anObject
	^self main protocol: anObject</body>

<body package="SeasideAsync-Browser" selector="protocols">protocols
	^self main protocols</body>

<body package="SeasideAsync-Browser" selector="selectedClass">selectedClass
	^self main selectedClass</body>

<body package="SeasideAsync-Browser" selector="selectedClass:">selectedClass: anObject
	^self main selectedClass: anObject</body>

<body package="SeasideAsync-Browser" selector="selector">selector
	^self main selector</body>

<body package="SeasideAsync-Browser" selector="selector:">selector: anObject
	^self main selector: anObject</body>

<body package="SeasideAsync-Browser" selector="selectors">selectors
	^self main selectors</body>

<body package="SeasideAsync-Browser" selector="sourceCode">sourceCode
	^self main sourceCode</body>

<body package="SeasideAsync-Browser" selector="sourceTitle">sourceTitle
	^self main sourceTitle</body>

<body package="SeasideAsync-Browser" selector="templateSourceCode">templateSourceCode
	^self main templateSourceCode</body>
</methods>

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

<body package="SeasideAsync-Browser" selector="componentName">componentName
	"Answer the value of componentName"

	^ componentName</body>

<body package="SeasideAsync-Browser" selector="componentName:">componentName: anObject
	"Set the value of componentName"

	componentName := anObject</body>

<body package="SeasideAsync-Browser" selector="main">main
	"Answer the value of main"

	^ main</body>

<body package="SeasideAsync-Browser" selector="main:">main: anObject
	"Set the value of main"

	main := anObject</body>
</methods>

<methods>
<class-id>Seaside.WAClassBrowserSourcePane</class-id> <category>button text</category>

<body package="SeasideAsync-Browser" selector="removeButtonText">removeButtonText
	^'Remove this ' , self main removeText , ' (Ctrl-X)'</body>

<body package="SeasideAsync-Browser" selector="renameButtonText">renameButtonText
	^'Rename this ' , self main renameText , ' (Ctrl-R)'</body>

<body package="SeasideAsync-Browser" selector="saveButtonText">saveButtonText
	^'Accept (Ctrl-S)'</body>
</methods>

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

<body package="SeasideAsync-Browser" selector="renderContentOn:">renderContentOn: html 
	self renderSourceOn: html</body>

<body package="SeasideAsync-Browser" selector="renderMessageOn:">renderMessageOn: html 
	main message notNil 
		ifTrue: 
			[(html div)
				id: 'message';
				with: main message]
		ifFalse: 
			[(html div)
				id: 'title';
				with: self sourceTitle]</body>

<body package="SeasideAsync-Browser" selector="renderReadOnlySourceOn:">renderReadOnlySourceOn: html 
	| stream lines |
	lines := OrderedCollection new.
	stream := sourceCode readStream.
	[stream atEnd]
		whileFalse: [lines add: stream nextLine].
	lines := lines readStream.
	html strong: lines next.
	[lines atEnd]
		whileFalse: [html break.
			stream := lines next readStream.
			[stream atEnd]
				whileFalse: [stream peek == Character tab
						ifTrue: [html space: 3.
							stream next]
						ifFalse: [html text: stream upToEnd]]]</body>

<body package="SeasideAsync-Browser" selector="renderRemoveButtonOn:">renderRemoveButtonOn: html 
	self canRemoveSourceCode ifTrue:
		[(html submitButton)
			addShortcut: 'Ctrl-X';
			addShortcut: 'Ctrl-x';
			callback: [main removeSourceCode];
			text: self removeButtonText]</body>

<body package="SeasideAsync-Browser" selector="renderRenameButtonOn:">renderRenameButtonOn: html 
	self canRenameSourceCode ifTrue:
		[(html submitButton)
			addShortcut: 'Ctrl-R';
			addShortcut: 'Ctrl-r';
			callback: [main renameSourceCode];
			text: self renameButtonText]</body>

<body package="SeasideAsync-Browser" selector="renderSaveButtonOn:">renderSaveButtonOn: html 
	self canSaveSourceCode ifTrue:
		[(html submitButton)
			addShortcut: 'Ctrl-S';
			addShortcut: 'Ctrl-s';
			callback: [main saveSourceCode: sourceCode];
			text: 'Accept (Ctrl-S)']</body>

<body package="SeasideAsync-Browser" selector="renderSourceCodeOn:">renderSourceCodeOn: html 
	sourceCode := self sourceCode ifNil: [^html space].
	self isReadOnly ifTrue: [^self renderReadOnlySourceOn: html].
	self renderMessageOn: html.
	html form: 
			[(html textArea)
				id: #contents;
				callback: [:v | sourceCode := v];
				value: sourceCode.
			self renderSaveButtonOn: html.
			self renderRenameButtonOn: html.
			self renderRemoveButtonOn: html.]
</body>

<body package="SeasideAsync-Browser" selector="renderSourceOn:">renderSourceOn: html 
	(html div)
		id: 'source';
		with: [self renderSourceCodeOn: html]</body>
</methods>

<methods>
<class-id>Seaside.WALiveDateInput</class-id> <category>private callbacks</category>

<body package="SeasideAsync-Renderers" selector="addDayCallbackToBrush:">addDayCallbackToBrush: aBrush
	super addDayCallbackToBrush: aBrush.
	self hasLiveCallback ifFalse: [^self].
	aBrush liveCallback:
		[:d :renderer |
		self day: d.
		self liveCallback value: self setValueWithNewDate value: renderer].


</body>

<body package="SeasideAsync-Renderers" selector="addMonthCallbackToBrush:">addMonthCallbackToBrush: aBrush
	super addMonthCallbackToBrush: aBrush.
	self hasLiveCallback ifFalse: [^self].
	aBrush liveCallback:
		[:m :renderer |
		self month: m.
		self liveCallback value: self setValueWithNewDate value: renderer].

</body>

<body package="SeasideAsync-Renderers" selector="addYearCallbackToBrush:">addYearCallbackToBrush: aBrush
	super addYearCallbackToBrush: aBrush.
	self hasLiveCallback ifFalse: [^self].
	aBrush liveCallback:
		[:y :renderer |
		self year: y.
		self liveCallback value: self setValueWithNewDate value: renderer].

</body>
</methods>

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

<body package="SeasideAsync-Browser" selector="component">component
	^ component</body>

<body package="SeasideAsync-Browser" selector="component:">component: anObject
	component := anObject</body>

<body package="SeasideAsync-Browser" selector="systemNavigation">systemNavigation
	</body>
</methods>

<methods>
<class-id>Seaside.WAPermissiveBrowser</class-id> <category>confirm</category>

<body package="SeasideAsync-Browser" selector="confirm:">confirm: aString
	^self component confirm: aString</body>

<body package="SeasideAsync-Browser" selector="confirmRemovalOf:on:">confirmRemovalOf: aSelector on: aClass
	^1</body>

<body package="SeasideAsync-Browser" selector="request:initialAnswer:">request: aString initialAnswer: anotherString
	^self component request: aString default: anotherString</body>
</methods>

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

<body package="SeasideAsync-Tests" selector="clearLog">clearLog
	log := OrderedCollection new.
</body>

<body package="SeasideAsync-Tests" selector="initialize">initialize
	super initialize.
	self clearLog.
	cbValue := false.
	radioValue := false</body>
</methods>

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

<body package="SeasideAsync-Tests" selector="renderContentOn:">renderContentOn: html 
	| group |
	html form
		with:
			[
			html textInput
				onFocusCallback: [:event | log add: 'Entry field' -&gt; event value];
				callback: [:v | ].
			html select
				list: #( a b c );
				onFocusCallback: [:event | log add: 'Select box' -&gt; event value];
				selected: selected.
			html checkbox
				onClickCallback: [:event | log add: 'Checkbox' -&gt; event value];
				value: cbValue;
				callback: [:v | cbValue := v].
			html span
				style: 'border: 1px dashed grey';
				with:
					[group := html radioGroup.
					html radioButton
						group: group;
						onFocusCallback: [:event | log add: 'radio(left)' -&gt; event value]; "Does not work in Safari 2.0.4"
						selected: radioValue;
						callback: [:v | radioValue := false].
					html radioButton
						group: group;
						onFocusCallback: [:event | log add: 'radio(right)' -&gt; event value]; "Does not work in Safari 2.0.4"
						selected: radioValue not;
						callback: [:v | radioValue := true].
					].
			html submitButton].
	html div: 'Radio buttons do not work with Safari, because Safari does not support onclick for radio buttons'.
	log notEmpty ifTrue: [self renderLogOn: html]</body>

<body package="SeasideAsync-Tests" selector="renderLogOn:">renderLogOn: html 
	html
		paragraph: [html text: 'Before button was clicked, field with focus was:';
				 break;
				 strong: log last key;
				 break;
				 text: 'At that time the field received the focus, its value was:';
				 break;
				 strong: log last value].
	html heading: 'Captured events' level: 5.
	log
		do: [:each | html text: each printString]
		separatedBy: [html break].
	self clearLog</body>
</methods>

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

<body package="SeasideAsync-Tests" selector="description">description
	^'How application can be aware of which entry item had the focus'</body>

<body package="SeasideAsync-Tests" selector="initialize">initialize
	self registerAsApplication: 'tests/async/focuscapture'.</body>
</methods>

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

<body package="SeasideAsync-Browser" selector="renderContentOn:">renderContentOn: html 
	self renderProtocolsOn: html.
	self renderSelectorsOn: html.</body>

<body package="SeasideAsync-Browser" selector="renderProtocolsListOn:">renderProtocolsListOn: html 
	(html select)
		size: self listSize;
		id: 'protocolList';
		selected: self protocol;
		list: self protocols;
		liveCallback:
			[:value :renderer |
			main selectProtocol: value on: renderer]</body>

<body package="SeasideAsync-Browser" selector="renderProtocolsOn:">renderProtocolsOn: html 
	(html div)
		id: 'protocols';
		with: [ self renderProtocolsListOn: html ].</body>

<body package="SeasideAsync-Browser" selector="renderSelectorsListOn:">renderSelectorsListOn: html 
	(html select)
		size: self listSize;
		id: 'selectorList';
		selected: self selector;
		list: self selectors;
		liveCallback:
			[:value :renderer |
			main selectSelector: value on: renderer]</body>

<body package="SeasideAsync-Browser" selector="renderSelectorsOn:">renderSelectorsOn: html 
	(html div)
		id: 'selectors';
		with: [ self renderSelectorsListOn: html ]</body>
</methods>

<methods>
<class-id>Seaside.WAFullClassBrowser</class-id> <category>model</category>

<body package="SeasideAsync-Browser" selector="canRemoveSourceCode">canRemoveSourceCode
	"May remove classes with this tool"
	^self selectedClass notNil.</body>

<body package="SeasideAsync-Browser" selector="canRenameSourceCode">canRenameSourceCode
	"May rename a method category"
	^self protocol notNil.</body>

<body package="SeasideAsync-Browser" selector="canSaveSourceCode">canSaveSourceCode
	"Can save new classes with this tool"
	^self package notNil</body>

<body package="SeasideAsync-Browser" selector="classes">classes
	^self browser classList</body>

<body package="SeasideAsync-Browser" selector="package">package
	self browser systemCategoryListIndex = 0 ifTrue: [^nil].
	^self packages at: self browser systemCategoryListIndex</body>

<body package="SeasideAsync-Browser" selector="package:">package: anObject
	^self browser systemCategoryListIndex: (self packages indexOf: anObject)</body>

<body package="SeasideAsync-Browser" selector="packages">packages
	^self browser systemCategoryList</body>

<body package="SeasideAsync-Browser" selector="protocol">protocol
	self browser messageCategoryListIndex = 0 ifTrue: [^nil].
	^self protocols at: self browser messageCategoryListIndex</body>

<body package="SeasideAsync-Browser" selector="protocol:">protocol: anObject
	^self browser messageCategoryListIndex: (self protocols indexOf: anObject)</body>

<body package="SeasideAsync-Browser" selector="protocols">protocols
	^self browser messageCategoryList</body>

<body package="SeasideAsync-Browser" selector="removeText">removeText
	self selector notNil
		ifTrue: [^'method'].
	self protocol notNil
		ifTrue: [^'method category'].
	self selectedClass notNil
		ifTrue: [^'class'].
</body>

<body package="SeasideAsync-Browser" selector="renameText">renameText
	self protocol notNil
		ifTrue: [^'method category'].
</body>

<body package="SeasideAsync-Browser" selector="selectedClass">selectedClass
	self browser classListIndex = 0 ifTrue: [^nil].
	^self classes at: self browser classListIndex</body>

<body package="SeasideAsync-Browser" selector="selectedClass:">selectedClass: anObject
	^self browser classListIndex: (self classes indexOf: anObject)</body>

<body package="SeasideAsync-Browser" selector="selector">selector
	self browser messageListIndex = 0 ifTrue: [^nil].
	^self selectors at: self browser messageListIndex</body>

<body package="SeasideAsync-Browser" selector="selector:">selector: anObject
	^self browser messageListIndex: (self selectors indexOf: anObject)</body>

<body package="SeasideAsync-Browser" selector="selectors">selectors
	self protocol isNil ifTrue: [^Array new].
	^self browser messageList</body>

<body package="SeasideAsync-Browser" selector="sourceCode">sourceCode
	^self contents</body>

<body package="SeasideAsync-Browser" selector="sourceTitle">sourceTitle
	self selector notNil 
		ifTrue: [^self selectedClass asString , ' &gt;&gt; ' , self selector].
	self protocol notNil 
		ifTrue: [^self selectedClass asString , ' &gt;&gt; template for new method'].
	self selectedClass notNil 
		ifTrue: [^self selectedClass asString , ' class definition'].
	self package notNil
		ifTrue: [^'Template for new class definition'].
	^nil</body>
</methods>

<methods>
<class-id>Seaside.WAFullClassBrowser</class-id> <category>browser callbacks</category>

<body package="SeasideAsync-Browser" selector="bindingOf:">bindingOf: aString
	"Here when an unknown variable is used in a method"
	(WAUnknownVariable new)
		varName: aString;
		signal</body>

<body package="SeasideAsync-Browser" selector="notify:at:in:">notify: aString at: location in: sourceStream
	"Here when there was a compile error"
	message := aString allButLast: 3</body>

<body package="SeasideAsync-Browser" selector="selectionInterval">selectionInterval
	^1 to: 1</body>

<body package="SeasideAsync-Browser" selector="update:">update: aSymbol
	aSymbol == #contents ifTrue:
		["Here when the source pane has changed"
		message := nil.
		self contents: self browser contents]
</body>
</methods>

<methods>
<class-id>Seaside.WAFullClassBrowser</class-id> <category>ajax updates</category>

<body package="SeasideAsync-Browser" selector="selectClass:on:">selectClass: aClass on: aRenderer
	self selectedClass: aClass.
	self updateProtocolsOn: aRenderer.
</body>

<body package="SeasideAsync-Browser" selector="selectPackage:on:">selectPackage: aPackage on: aRenderer
	self package: aPackage.
	self updateClassesOn: aRenderer.
</body>

<body package="SeasideAsync-Browser" selector="selectProtocol:on:">selectProtocol: aProtocol on: aRenderer
	self protocol: aProtocol.
	self updateSelectorsOn: aRenderer.
</body>

<body package="SeasideAsync-Browser" selector="selectSelector:on:">selectSelector: aSelector on: aRenderer
	self selector: aSelector.
	self updateSourceOn: aRenderer.
</body>

<body package="SeasideAsync-Browser" selector="updateClassesOn:">updateClassesOn: html 
	self pause.
	self leftComponent renderClassesOn: html.
	self updateProtocolsOn: html.</body>

<body package="SeasideAsync-Browser" selector="updateProtocolsOn:">updateProtocolsOn: html 
	self pause.
	self rightComponent renderProtocolsOn: html.
	self updateSelectorsOn: html.
</body>

<body package="SeasideAsync-Browser" selector="updateSelectorsOn:">updateSelectorsOn: html 
	self pause.
	self rightComponent renderSelectorsOn: html.
	self updateSourceOn: html.</body>

<body package="SeasideAsync-Browser" selector="updateSourceOn:">updateSourceOn: html 
	self pause.
	self bottomComponent renderSourceOn: html.</body>
</methods>

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

<body package="SeasideAsync-Browser" selector="bottom">bottom
	"Answer the value of bottom"

	^ bottom</body>

<body package="SeasideAsync-Browser" selector="bottom:">bottom: anObject
	"Set the value of bottom"

	bottom := anObject</body>

<body package="SeasideAsync-Browser" selector="browser">browser
	"Answer the value of browser"

	^ browser</body>

<body package="SeasideAsync-Browser" selector="browser:">browser: anObject
	"Set the value of browser"

	browser := anObject</body>

<body package="SeasideAsync-Browser" selector="contents">contents
	"Answer the value of contents"

	^ contents</body>

<body package="SeasideAsync-Browser" selector="contents:">contents: anObject
	"Set the value of contents"

	contents := anObject</body>

<body package="SeasideAsync-Browser" selector="isReadOnly">isReadOnly
	"Answer the value of isReadOnly"

	^ isReadOnly</body>

<body package="SeasideAsync-Browser" selector="isReadOnly:">isReadOnly: anObject
	"Set the value of isReadOnly"

	isReadOnly := anObject</body>

<body package="SeasideAsync-Browser" selector="left">left
	"Answer the value of left"

	^ left</body>

<body package="SeasideAsync-Browser" selector="left:">left: anObject
	"Set the value of left"

	left := anObject</body>

<body package="SeasideAsync-Browser" selector="leftComponents">leftComponents
	"Answer the value of leftComponents"

	^ leftComponents</body>

<body package="SeasideAsync-Browser" selector="leftComponents:">leftComponents: anObject
	"Set the value of leftComponents"

	leftComponents := anObject</body>

<body package="SeasideAsync-Browser" selector="message">message
	"Answer the value of message"

	^ message</body>

<body package="SeasideAsync-Browser" selector="message:">message: anObject
	"Set the value of message"

	message := anObject</body>

<body package="SeasideAsync-Browser" selector="model">model
	"Polymorphism with WABrowser"
	^self browser</body>

<body package="SeasideAsync-Browser" selector="right">right
	"Answer the value of right"

	^ right</body>

<body package="SeasideAsync-Browser" selector="right:">right: anObject
	"Set the value of right"

	right := anObject.
	self right = 'Class' 
		ifTrue: [self browser indicateClassMessages]
		ifFalse: [self browser indicateInstanceMessages].
</body>

<body package="SeasideAsync-Browser" selector="rightComponents">rightComponents
	"Answer the value of rightComponents"

	^ rightComponents</body>

<body package="SeasideAsync-Browser" selector="rightComponents:">rightComponents: anObject
	"Set the value of rightComponents"

	rightComponents := anObject</body>

<body package="SeasideAsync-Browser" selector="text">text
	^ Text fromString: ''</body>
</methods>

<methods>
<class-id>Seaside.WAFullClassBrowser</class-id> <category>navigation</category>

<body package="SeasideAsync-Browser" selector="bottomComponent">bottomComponent
	^bottom
		main: self;
		yourself</body>

<body package="SeasideAsync-Browser" selector="leftComponent">leftComponent
	^(leftComponents at: self left)
		main: self;
		componentName: self left;
		yourself</body>

<body package="SeasideAsync-Browser" selector="leftOptions">leftOptions
	^leftComponents keys</body>

<body package="SeasideAsync-Browser" selector="rightComponent">rightComponent
	^(rightComponents at: self right)
		main: self;
		componentName: self right;
		yourself</body>

<body package="SeasideAsync-Browser" selector="rightOptions">rightOptions
	^rightComponents keys</body>
</methods>

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

<body package="SeasideAsync-Browser" selector="removeSourceCode">removeSourceCode
	self selector notNil
		ifTrue: [^self browser removeMessage].
	self protocol notNil
		ifTrue: [^self browser removeMessageCategory].
	self selectedClass notNil
		ifTrue: [^self browser removeClass].
</body>

<body package="SeasideAsync-Browser" selector="renameSourceCode">renameSourceCode
	^self browser renameCategory</body>

<body package="SeasideAsync-Browser" selector="saveSourceCode:">saveSourceCode: aString 
	| saveProtocol saveSelector saveMessage |
	SeasidePlatformSupport ensureAuthorInitials: [self request: 'Please enter your initials:'].
	message := nil.
	saveProtocol := self protocol.
	saveSelector := self selector.
	[self browser contents: aString notifying: self]
		on: WAUnknownVariable
		do: [:error | message := error messageText].
	saveMessage := message.
	self protocol: saveProtocol.
	self selector: saveSelector.
	self contents: aString.
	message := saveMessage</body>
</methods>

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

<body package="SeasideAsync-Browser" selector="children">children
	^Array 
		with: self leftComponent
		with: self rightComponent
		with: self bottomComponent</body>

<body package="SeasideAsync-Browser" selector="renderContentOn:">renderContentOn: html
	(html div)
		id: 'class-browser';
		with: 
			[(html div)
				id: 'left';
				with: 
					[(html div)
						class: 'nav-options';
						id: 'left-options';
						with: [self renderLeftOptionsOn: html].
					html render: self leftComponent].
			(html div)
				id: 'right';
				with: 
					[(html div)
						class: 'nav-options';
						id: 'right-options';
						with: [self renderRightOptionsOn: html].
					html render: self rightComponent].	
		html div class: 'clear'.
		html render: self bottomComponent].</body>

<body package="SeasideAsync-Browser" selector="renderLeftOptionsOn:">renderLeftOptionsOn: html 
	(html unorderedList)
		list: self leftOptions;
		selected: self left;
		callback: [:v | self left: v]</body>

<body package="SeasideAsync-Browser" selector="renderRightOptionsOn:">renderRightOptionsOn: html 
	(html unorderedList)
		list: self rightOptions;
		selected: self right;
		callback: [:v | self right: v]</body>

<body package="SeasideAsync-Browser" selector="style">style
	^ '
div#class-browser {
	font-family: Verdana;
}
div#left, div#right {
	float: left;
	width: 49.9%;
}
div#packages, div#classes, div#protocols, div#selectors {
	float: left;
	width: 49.9%;
}
div.clear {
	clear: both;
	height: 1em;
}
div#packages select, div#classes select, div#protocols select, div#selectors select {
	width: 100%;
}
div#source {
	padding: 1em;
	border: 1px solid #dddddd;
	background-color: #f5f5f5;
}
textarea#contents {
	width: 100%;
	height: 20em;
	margin-top: 1em;
	margin-bottom: 1em;
}
div#message, div#title {
	font-weight: bold;
}
div#message {
	color: red;
}


div.nav-options {
	border-bottom : 1px solid #ccc;
	margin : 0;
	padding-bottom : 19px;
	padding-left : 10px;
}
div.nav-options ul, div.nav-options li	{
	display : inline;
	list-style-type : none;
	margin : 0;
	padding : 0;
}
div.nav-options a:link, div.nav-options a:visited	{
	background : #E8EBF0;
	border : 1px solid #ccc;
	color : #666;
	float : left;
	font-size : small;
	font-weight : normal;
	line-height : 14px;
	margin-right : 8px;
	padding : 2px 10px 2px 10px;
	text-decoration : none;
}

div.nav-options a:link.active, div.nav-options a:visited.active	{
	background : #fff;
	border-bottom : 1px solid #fff;
	color : #000;
}

div.nav-options ul a:hover	{
	color : #f00;
}

div.nav-options .option-selected a {
	background : #fff;
	border-bottom : 1px solid #fff;
	color : #000;
}


'</body>

<body package="SeasideAsync-Browser" selector="updateRoot:">updateRoot: anHtmlRoot 
	super updateRoot: anHtmlRoot.
	(self session application libraries includes: WAAsyncScripts)
		ifFalse: [WAAsyncScripts default updateRoot: anHtmlRoot]</body>
</methods>

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

<body package="SeasideAsync-Browser" selector="pause">pause
	"Activate this code to demo ajax interactivity"
	"(Delay forSeconds: 1) wait."</body>
</methods>

<methods>
<class-id>Seaside.WAFullClassBrowser</class-id> <category>lightbox</category>

<body package="SeasideAsync-Browser" selector="confirm:">confirm: aString
	^self lightbox: (WAYesOrNoDialog new addMessage: aString; yourself)</body>

<body package="SeasideAsync-Browser" selector="inform:">inform: aString
	self lightbox: (WAFormDialog new addMessage: aString; yourself)</body>

<body package="SeasideAsync-Browser" selector="lightbox:">lightbox: aComponent
	^(self class superclass canUnderstand: #lightbox:) ifTrue:
		[super lightbox: (aComponent addDecoration: WAClassBrowserDialogDecoration new; yourself)]
	ifFalse:
		[self call: aComponent].</body>

<body package="SeasideAsync-Browser" selector="request:label:default:">request: requestString label: labelString default: initialString
	^ self lightbox:
		((WAInputDialog new
			label: labelString;
			default: initialString;
			yourself)
				addMessage: requestString; yourself)</body>
</methods>

<methods>
<class-id>Seaside.WAFullClassBrowser</class-id> <category>initialize-release</category>

<body package="SeasideAsync-Browser" selector="initialize">initialize
	super initialize.
	self browser: WAPermissiveBrowser new.
	self browser component: self.
	self browser addDependent: self.
	self contents: self browser contents.
	isReadOnly := false.
	leftComponents := (Dictionary new)
				at: 'Categories' put: WAClassBrowserLeftPane new;
				yourself.
	self left: 'Categories'.
	rightComponents := (Dictionary new)
				at: 'Instance' put: WAClassBrowserRightPane new;
				at: 'Class' put: WAClassBrowserRightPane new;
				yourself.
	self right: 'Instance'.
	bottom := WAClassBrowserSourcePane new.</body>

<body package="SeasideAsync-Browser" selector="initialRequest:">initialRequest: aRequest
	| theClass |
	aRequest fields at: 'class' ifPresent:
		[:className | 
		Smalltalk at: className asSymbol ifPresent:
			[:class |
			theClass := (aRequest fields includesKey: 'meta')
					ifTrue: [class class]
					ifFalse: [class].
			self setClass: theClass selector: nil.
			aRequest fields at: 'method' ifPresent:
				[:selector |
				self setClass: theClass selector: selector asSymbol]]]</body>

<body package="SeasideAsync-Browser" selector="setClass:selector:">setClass: aClass selector: aSymbol
	self browser setClass: aClass selector: aSymbol.</body>
</methods>

<methods>
<class-id>Seaside.WAFullClassBrowser</class-id> <category>constants</category>

<body package="SeasideAsync-Browser" selector="listSize">listSize
	^15</body>
</methods>

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

<body package="SeasideAsync-Browser" selector="fullOnClass:">fullOnClass: aClass
	^self fullOnClass: aClass selector: nil</body>

<body package="SeasideAsync-Browser" selector="fullOnClass:selector:">fullOnClass: aClass selector: aSelector
	^(self new)
		setClass: aClass selector: aSelector;
		yourself</body>
</methods>

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

<body package="SeasideAsync-Browser" selector="canBeRoot">canBeRoot
	^true</body>
</methods>

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

<body package="SeasideAsync-Browser" selector="initialize">initialize
	self registerAsApplication: 'tools/classbrowser'</body>
</methods>

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

<body package="SeasideAsync-Browser" selector="description">description
	^'Ajax Smalltalk class browser (four panes)'</body>
</methods>

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

<body package="SeasideAsync-Browser" selector="renderContentOn:">renderContentOn: html
	self renderOwnerOn: html</body>

<body package="SeasideAsync-Browser" selector="style">style
	^'
div#lightbox {
	background-color: #edfced;
	border: 1px solid #e8a400;
	padding: 2em;
	width: 50%;
	font-family: Verdana;
}
div#lightbox h3 {
	font-weight: normal;
	font-size: 80%;
}
'</body>

<body package="SeasideAsync-Browser" selector="updateRoot:">updateRoot: anHtmlRoot 
	SeasidePlatformSupport ifDefined: #SULibrary do:
		[:suLibrary |
		(self session application libraries includes: suLibrary)
			ifFalse: 
				["Naughty, dirty, awful hack to make sure SULibrary javascripts
				are all inserted at the beginning"
				| save |
				save := OrderedCollection new.
				[anHtmlRoot scripts isEmpty]
					whileFalse: [save add: anHtmlRoot scripts removeFirst].
				suLibrary default updateRoot: anHtmlRoot.
				anHtmlRoot scripts addAll: save]].
	super updateRoot: anHtmlRoot</body>
</methods>

<methods>
<class-id>Seaside.WAAutoCompleteEntryField</class-id> <category>initialize-release</category>

<body package="SeasideAsync-Widgets" selector="initialize">initialize

	super initialize.
	stringsToObjects := Dictionary new.
	strings := #().
	prefix := ''.
	selectedString := nil.
	selectedObject := nil.
	listHeight := 5.
	listWidth := 30.</body>
</methods>

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

<body package="SeasideAsync-Widgets" selector="callback:">callback: aOneArgumentBlock
	"When a selection is made, aOneArgumentBlock is evaluated with the selected object"

	callback := aOneArgumentBlock</body>

<body package="SeasideAsync-Widgets" selector="listHeight:">listHeight: numberOfLines
	listHeight := numberOfLines</body>

<body package="SeasideAsync-Widgets" selector="listWidth:">listWidth: numberOfCharacters
	listWidth := numberOfCharacters</body>

<body package="SeasideAsync-Widgets" selector="name:">name: aString
	name := aString</body>

<body package="SeasideAsync-Widgets" selector="numberOfItems">numberOfItems
	^stringsToObjects size</body>

<body package="SeasideAsync-Widgets" selector="objects:strings:">objects: objects strings: objectLabels

	strings := objectLabels.
	stringsToObjects := Dictionary new: objects size.
	objectLabels with: objects
		do: [:label :object | stringsToObjects at: label put: object].
	prefix := ''.
	selectedString := nil.
	selectedObject := nil.</body>

<body package="SeasideAsync-Widgets" selector="selectedObject">selectedObject
	^selectedObject</body>

<body package="SeasideAsync-Widgets" selector="selectedObject:string:">selectedObject: anObject string: aString
	prefix := selectedString := aString.
	selectedObject := anObject.</body>
</methods>

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

<body package="SeasideAsync-Widgets" selector="renderAutoCompleteSuggestionListOn:">renderAutoCompleteSuggestionListOn: html 
	| labelsMatchingPrefix prefixPattern |
	html div id: 'D';
		with: 
			[(prefix isEmptyOrNil not and: [selectedString isNil]) 
				ifTrue: 
					[prefixPattern := prefix asUppercase , '*'.
					labelsMatchingPrefix := (strings 
								select: [:label | prefixPattern match: label asUppercase]) 
									asSortedCollection asArray.
					labelsMatchingPrefix isEmpty 
						ifTrue: 
							[selectedString := ''.
							selectedObject := nil]
						ifFalse: 
							[labelsMatchingPrefix size = 1 
								ifTrue: 
									[prefix := selectedString := labelsMatchingPrefix first.
									selectedObject := stringsToObjects at: selectedString].
							self renderSuggestionListLabels: labelsMatchingPrefix on: html]]]
	</body>

<body package="SeasideAsync-Widgets" selector="renderAutoCompleteTextFieldOn:">renderAutoCompleteTextFieldOn: html 
	html div class: 'autocomplete';
		 id: 'autocomplete';
		 style: 'width: ' , (listWidth + name size) printString , 'em';
		
		with: [html div class: 'label';
				 id: 'L';
				 with: name.
			html div class: 'input';
				 id: 'I';
				
				with: [html textInput attributeAt: #autocomplete put: 'off';
						 style: 'width: ' , listWidth printString , 'em';
						 value: prefix;
						
						callback: [:v | 
							prefix := v.
							callback value: selectedObject];
						
						liveCallback: [:v :h | 
							prefix := v.
							selectedString := nil.
							self renderAutoCompleteSuggestionListOn: h].
					self renderAutoCompleteSuggestionListOn: html]]</body>

<body package="SeasideAsync-Widgets" selector="renderContentOn:">renderContentOn: html 
	self numberOfItems &lt; listHeight
		ifTrue: ["When the list is small, i.e. smaller than the number of items to
			be shown,
			show a drop-down list"
			self renderSimpleDropDownOn: html]
		ifFalse: ["When the list is large, use anchors"
			self renderAutoCompleteTextFieldOn: html]</body>

<body package="SeasideAsync-Widgets" selector="renderSimpleDropDownOn:">renderSimpleDropDownOn: html 
	| objectsToLabels |
	objectsToLabels := IdentityDictionary new.
	stringsToObjects
		keysAndValuesDo: [:label :object | objectsToLabels at: object put: label].
	html div class: 'autocomplete';
		 id: 'autocomplete';
		
		with: [html div class: 'label';
				 id: 'L';
				
				with: [html text: name].
			html div
				class: 'input';
				id: 'I';
				with: [html select list: strings;
						 selected: strings first;
						
						callback: [:l | 
							selectedObject := stringsToObjects at: l.
							callback value: selectedObject]]]</body>

<body package="SeasideAsync-Widgets" selector="renderSuggestionListLabels:on:">renderSuggestionListLabels: labels on: html

	html div
		class: 'dropdown';
		with: 
			[html unorderedList with: 
				[(labels copyFrom: 1 to: (labels size min: listHeight))
					do: 
						[:label | 
						html listItem: 
							[html 
								anchor callback: [];
								liveCallback: 
									[:h | 
									selectedString := prefix := label.
									selectedObject := stringsToObjects at: label.
									callback value: selectedObject.
									self renderAutoCompleteTextFieldOn: h];
								with: label]]]]</body>
</methods>

<methods>
<class-id>Seaside.WAAutoCompleteEntryField</class-id> <category>css</category>

<body package="SeasideAsync-Widgets" selector="style">style
 	^'
	.autocomplete { font-family: Tahoma, Arial, Helvetica; font-size: 100%;  }
	.autocomplete .label { width: 10em; float: left; text-align: right; font-weight: bold;  }
	.autocomplete .input { float: left; margin-left: 1em; }

	.dropdown { overflow: hidden; border-width: 1px; border-style: solid; border-color: black; }
	.dropdown ul { list-style-type: none; margin: 0; padding: 0; }
	.dropdown ul li { clear: left; float: left; display: inline; width: 100%; line-height: 1.1em; }
	.dropdown ul li.selected { font-weight: bold; line-height: 1.1em; }

	.dropdown a { display: block; padding: 3px; background-color: #036; border-bottom: 1px solid #eee; }
	.dropdown a:link, .dropdown a:visited { color: #EEE; text-decoration: none; }
	.dropdown a:hover { background-color: #369; color: #fff; }
'</body>
</methods>

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

<body package="SeasideAsync-Rendering" selector="callbacks">callbacks
	^callbacks</body>

<body package="SeasideAsync-Rendering" selector="callbacks:">callbacks: anObject
	callbacks := anObject</body>

<body package="SeasideAsync-Rendering" selector="rendererClass">rendererClass
	^rendererClass
</body>

<body package="SeasideAsync-Rendering" selector="rendererClass:">rendererClass: anObject
	rendererClass := anObject</body>
</methods>

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

<body package="SeasideAsync-Rendering" selector="isEnabled">isEnabled
	^ true</body>
</methods>

<methods>
<class-id>Seaside.WALiveActionCallback</class-id> <category>responding</category>

<body package="SeasideAsync-Rendering" selector="evaluateWithArgument:">evaluateWithArgument: argument 
	| currentSession request response renderer document event xmlRoot |
	currentSession := WACurrentSession value.
	request := currentSession currentRequest.
	event := WALiveEvent newFromRequest: request.
	response := WAResponse new.
	response contentType: 'text/xml; charset=utf-8'.
	renderer := self rendererClass context: context copy callbacks: self callbacks.
	document := self newDocumentOn: response.
	renderer context document: document.
	xmlRoot := WAXmlRoot context: renderer context.
	document open: xmlRoot.
	block value: event value: renderer.
	document close.
	currentSession returnResponse: response</body>

<body package="SeasideAsync-Rendering" selector="newDocumentOn:">newDocumentOn: aResponse 
	^WAXmlStreamDocument new stream: aResponse stream.
</body>
</methods>

<methods>
<class-id>Seaside.WAXmlRoot</class-id> <category>constants</category>

<body package="SeasideAsync-Rendering" selector="contentType">contentType
	^'text/xml'</body>

<body package="SeasideAsync-Rendering" selector="writeHeadOn:">writeHeadOn: aDocument 
	aDocument nextPutAll: '&lt;?xml version="1.0" encoding="';
		 nextPutAll: WACurrentSession value charSet;
		 nextPutAll: '"?&gt;'.
	aDocument openTag: 'body' attributes: bodyAttrs.</body>
</methods>

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

<body package="SeasideAsync-Browser" selector="renderClassesListOn:">renderClassesListOn: html 
	(html select)
		size: self listSize;
		id: 'classList';
		selected: self selectedClass;
		list: self classes;
		liveCallback:
			[:value :renderer |
			main selectClass: value on: renderer].
</body>

<body package="SeasideAsync-Browser" selector="renderClassesOn:">renderClassesOn: html 
	(html div)
		id: 'classes';
		with: [ self renderClassesListOn: html ]</body>

<body package="SeasideAsync-Browser" selector="renderContentOn:">renderContentOn: html 
	self renderPackagesOn: html.
	self renderClassesOn: html.</body>

<body package="SeasideAsync-Browser" selector="renderPackagesListOn:">renderPackagesListOn: html 
	(html select)
		size: self listSize;
		id: 'packageList';
		selected: self package;
		list: self packages;
		liveCallback:
			[:value :renderer |
			main selectPackage: value on: renderer].
</body>

<body package="SeasideAsync-Browser" selector="renderPackagesOn:">renderPackagesOn: html 
	(html div)
		id: 'packages';
		with: [ self renderPackagesListOn: html ].</body>
</methods>

<methods>
<class-id>Seaside.WALiveTimeInput</class-id> <category>private callbacks</category>

<body package="SeasideAsync-Renderers" selector="addHoursCallbackToBrush:">addHoursCallbackToBrush: aBrush
	super addHoursCallbackToBrush: aBrush.
	self hasLiveCallback ifFalse: [^self].
	aBrush liveCallback:
		[:h :renderer |
		self hours: h.
		self liveCallback value: self setValueWithNewTime value: renderer].

</body>

<body package="SeasideAsync-Renderers" selector="addMinutesCallbackToBrush:">addMinutesCallbackToBrush: aBrush
	super addMinutesCallbackToBrush: aBrush.
	self hasLiveCallback ifFalse: [^self].
	aBrush liveCallback:
		[:m :renderer |
		self minutes: m.
		self liveCallback value: self setValueWithNewTime value: renderer].



</body>

<body package="SeasideAsync-Renderers" selector="addSecondsCallbackToBrush:">addSecondsCallbackToBrush: aBrush
	super addSecondsCallbackToBrush: aBrush.
	self hasLiveCallback ifFalse: [^self].
	aBrush liveCallback:
		[:s :renderer |
		self seconds: s.
		self liveCallback value: self setValueWithNewTime value: renderer].


</body>
</methods>

<methods>
<class-id>Seaside.WACallbackRegistry</class-id> <category>*seasideasync</category>

<body package="SeasideAsync-Extensions" selector="registerLiveActionCallback:renderer:">registerLiveActionCallback: aBlock renderer: aRenderer
	^self storeCallback: (Seaside.WALiveActionCallback new
		block: aBlock;
		rendererClass: aRenderer class;
		callbacks: self)</body>
</methods>

<methods>
<class-id>Seaside.WARadioButtonTag</class-id> <category>*seasideasync</category>

<body package="SeasideAsync-Extensions" selector="liveCallback:">liveCallback: liveBlock 
	| uri id |
	id := self ensureId.
	liveBlock fixCallbackTemps.
	uri := canvas
				urlForLiveAction: [:event :h | liveBlock value: event valueAsBoolean value: h].
	self session addLoadScript: 'document.getElementById(' , id asString printString , ').onclick = liveCheck(' , id asString printString , ',' , (canvas encode: uri) printString , ')'</body>
</methods>

<methods>
<class-id>Seaside.WASelectTag</class-id> <category>*seasideasync</category>

<body package="SeasideAsync-Extensions" selector="isMultiple">isMultiple
	^false</body>

<body package="SeasideAsync-Extensions" selector="liveCallback:">liveCallback: liveBlock 
	| uri id |
	id := self ensureId.
	liveBlock fixCallbackTemps.
	uri := canvas
				urlForLiveAction: [:event :h | 
					| adjustedList values value | 
					adjustedList := self isOptional
								ifTrue: [#(nil ) , list]
								ifFalse: [list].
					values := event value asArray
								collect: [:each | adjustedList at: each asInteger].
					self isMultiple
						ifTrue: [liveBlock value: values value: h]
						ifFalse: [value := values isEmpty
										ifFalse: [values first].
							liveBlock value: value value: h]].
	self session addLoadScript: 'document.getElementById(' , id asString printString , ').onchange = liveSelect(' , id asString printString , ',' , (canvas encode: uri) printString , ')'</body>
</methods>

<methods>
<class-id>Seaside.WACheckboxTag</class-id> <category>*seasideasync</category>

<body package="SeasideAsync-Extensions" selector="liveCallback:">liveCallback: liveBlock 
	| uri id |
	id := self ensureId.
	liveBlock fixCallbackTemps.
	uri := canvas
				urlForLiveAction: [:event :h | liveBlock value: event valueAsBoolean value: h].
	self session addLoadScript: 'document.getElementById(' , id asString printString , ').onclick = liveCheck(' , id asString printString , ',' , (canvas encode: uri) printString , ')'</body>
</methods>

<methods>
<class-id>Seaside.WARequest</class-id> <category>*SeasideAsync</category>

<body package="SeasideAsync-Extensions" selector="isLiveRequest">isLiveRequest
	^ (self headerAt: 'x-requested-by') = 'SeasideAsync'</body>
</methods>

<methods>
<class-id>Seaside.WACompound</class-id> <category>*seasideasync</category>

<body package="SeasideAsync-Extensions" selector="hasLiveCallback">hasLiveCallback
	^self liveCallback notNil</body>

<body package="SeasideAsync-Extensions" selector="liveCallback">liveCallback
	^properties at: #liveCallback ifAbsent: [nil]</body>

<body package="SeasideAsync-Extensions" selector="liveCallback:">liveCallback: liveBlock 
	liveBlock fixCallbackTemps.
	properties at: #liveCallback put: liveBlock</body>
</methods>

<methods>
<class-id>Seaside.WATagBrush</class-id> <category>*seasideasync</category>

<body package="SeasideAsync-Extensions" selector="forEvent:callback:">forEvent: aString callback: callback 
	| uri |
	callback fixCallbackTemps.
	uri := canvas
				urlForLiveAction: [:event :renderer | callback numArgs = 0
						ifTrue: [callback value]
						ifFalse: [callback numArgs = 1
								ifTrue: [callback value: event]
								ifFalse: [callback value: event value: renderer]]].
	self attributes
		at: aString
		append: 'liveEventTrackerUri(event,' , (canvas encode: uri) printString , ')'
		separator: ';'</body>

<body package="SeasideAsync-Extensions" selector="onClickCallback:">onClickCallback: aBlock
	self forEvent: 'onclick' callback: aBlock </body>

<body package="SeasideAsync-Extensions" selector="onFocusCallback:">onFocusCallback: aBlock
	self forEvent: 'onfocus' callback: aBlock </body>

<body package="SeasideAsync-Extensions" selector="refreshWith:every:">refreshWith: liveBlock every: aDuration 
	"I refresh myself every aDuration with aBlock.
	No overlapping executions will take place, the next refresh is only
	scheduled after the block finished executing"
	| uri id |
	id := self ensureId.
	liveBlock fixCallbackTemps.
	uri := canvas
				urlForLiveAction: [:event :renderer | 
					event type: 'refresh';
						 elementTagName: self tag;
						 elementType: self tag;
						 elementValue: aDuration;
						 elementId: id.
					(renderer tag: self tag) id: id;
						
						with: [liveBlock value: event value: renderer]].
	self session addLoadScript: 'timedUpdate(' , (canvas encode: uri) printString , ', ' , aDuration asMilliSeconds printString , ')'</body>
</methods>

<methods>
<class-id>Seaside.WAAnchorTag</class-id> <category>*seasideasync</category>

<body package="SeasideAsync-Extensions" selector="liveCallback:">liveCallback: liveBlock
	liveBlock fixCallbackTemps.
	self onClickCallback: [:event :h | liveBlock value: h].
	self onClick: 'return false'
</body>
</methods>

<methods>
<class-id>Seaside.WAHtmlRoot</class-id> <category>*seasideasync</category>

<body package="SeasideAsync-Extensions" selector="scripts">scripts
	^ scripts</body>
</methods>

<methods>
<class-id>Seaside.WABrowser class</class-id> <category>*seasideAsync</category>

<body package="SeasideAsync-Extensions" selector="fullOnClass:selector:">fullOnClass: aClass selector: aSelector
	"Substitute a more modern browser"
	^Seaside.WAFullClassBrowser fullOnClass: aClass selector: aSelector</body>
</methods>

<methods>
<class-id>Seaside.WAMultiSelectTag</class-id> <category>*seasideasync</category>

<body package="SeasideAsync-Extensions" selector="isMultiple">isMultiple
	^ true</body>
</methods>

<methods>
<class-id>Seaside.WAAbstractTextAreaTag</class-id> <category>*seasideasync</category>

<body package="SeasideAsync-Extensions" selector="liveCallback:">liveCallback: liveBlock 
	| uri id |
	id := self ensureId.
	liveBlock fixCallbackTemps.
	uri := canvas
				urlForLiveAction: [:event :h | liveBlock value: event value value: h].
	self session addLoadScript: 'liveSearch(' , id asString printString , ',' , (canvas encode: uri) printString , ')'</body>
</methods>

<methods>
<class-id>Seaside.WASubmitButtonTag</class-id> <category>*seasideasync</category>

<body package="SeasideAsync-Extensions" selector="liveCallback:">liveCallback: liveBlock 
	liveBlock fixCallbackTemps.
	self
		onClickCallback: [:event :h | liveBlock value: h].
	self onClick: 'return false'</body>
</methods>

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

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

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

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

<initialize>
<class-id>Seaside.WAFullClassBrowser</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>WAFileLibrary</name>
<environment>Seaside</environment>
<super>Seaside.WALibrary</super>
<private>false</private>
<indexed-type>none</indexed-type>
<inst-vars></inst-vars>
<class-inst-vars></class-inst-vars>
<imports></imports>
<category>Seaside-Libraries</category>
<attributes>
<package>Seaside-Libraries</package>
</attributes>
</class>

<class>
<name>WACompound</name>
<environment>Seaside</environment>
<super>Seaside.WABrush</super>
<private>false</private>
<indexed-type>none</indexed-type>
<inst-vars>callbackBlock value id properties </inst-vars>
<class-inst-vars></class-inst-vars>
<imports></imports>
<category>Seaside-Canvas-Tags</category>
<attributes>
<package>Seaside-Canvas-Tags</package>
</attributes>
</class>

<class>
<name>WATagBrush</name>
<environment>Seaside</environment>
<super>Seaside.WABrush</super>
<private>false</private>
<indexed-type>none</indexed-type>
<inst-vars>attributes </inst-vars>
<class-inst-vars></class-inst-vars>
<imports></imports>
<category>Seaside-Canvas</category>
<attributes>
<package>Seaside-Canvas</package>
</attributes>
</class>

<class>
<name>WACheckboxTag</name>
<environment>Seaside</environment>
<super>Seaside.WAFormInputTag</super>
<private>false</private>
<indexed-type>none</indexed-type>
<inst-vars>value callback </inst-vars>
<class-inst-vars></class-inst-vars>
<imports></imports>
<category>Seaside-Canvas-Tags</category>
<attributes>
<package>Seaside-Canvas-Tags</package>
</attributes>
</class>

<class>
<name>WAAnchorTag</name>
<environment>Seaside</environment>
<super>Seaside.WATagBrush</super>
<private>false</private>
<indexed-type>none</indexed-type>
<inst-vars>url </inst-vars>
<class-inst-vars></class-inst-vars>
<imports></imports>
<category>Seaside-Canvas-Tags</category>
<attributes>
<package>Seaside-Canvas-Tags</package>
</attributes>
</class>

<class>
<name>WARequest</name>
<environment>Seaside</environment>
<super>Core.Object</super>
<private>false</private>
<indexed-type>none</indexed-type>
<inst-vars>url fields headers cookies method nativeRequest responseStream </inst-vars>
<class-inst-vars></class-inst-vars>
<imports></imports>
<category>Seaside-HTTP</category>
<attributes>
<package>Seaside-HTTP</package>
</attributes>
</class>

<class>
<name>WAHtmlRoot</name>
<environment>Seaside</environment>
<super>Seaside.WARoot</super>
<private>false</private>
<indexed-type>none</indexed-type>
<inst-vars>context docType htmlAttrs headAttrs bodyAttrs headElements title styles scripts </inst-vars>
<class-inst-vars></class-inst-vars>
<imports></imports>
<category>Seaside-Document</category>
<attributes>
<package>Seaside-Document</package>
</attributes>
</class>

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

<class>
<name>WASelectTag</name>
<environment>Seaside</environment>
<super>Seaside.WACollectionTag</super>
<private>false</private>
<indexed-type>none</indexed-type>
<inst-vars>enabledBlock isOptional optionalLabel </inst-vars>
<class-inst-vars></class-inst-vars>
<imports></imports>
<category>Seaside-Canvas-Tags</category>
<attributes>
<package>Seaside-Canvas-Tags</package>
</attributes>
</class>

<class>
<name>WAActionCallback</name>
<environment>Seaside</environment>
<super>Seaside.WACallback</super>
<private>false</private>
<indexed-type>none</indexed-type>
<inst-vars>block </inst-vars>
<class-inst-vars></class-inst-vars>
<imports></imports>
<category>Seaside-Callbacks</category>
<attributes>
<package>Seaside-Callbacks</package>
</attributes>
</class>

<class>
<name>Error</name>
<environment>Core</environment>
<super>Core.Exception</super>
<private>false</private>
<indexed-type>none</indexed-type>
<inst-vars></inst-vars>
<class-inst-vars></class-inst-vars>
<imports></imports>
<category>Kernel-Exception Handling</category>
<attributes>
<package>Kernel-Exception Handling</package>
</attributes>
</class>

<class>
<name>WAAbstractTextAreaTag</name>
<environment>Seaside</environment>
<super>Seaside.WAFormInputTag</super>
<private>false</private>
<indexed-type>none</indexed-type>
<inst-vars></inst-vars>
<class-inst-vars></class-inst-vars>
<imports></imports>
<category>Seaside-Canvas-Tags</category>
<attributes>
<package>Seaside-Canvas-Tags</package>
</attributes>
</class>

<class>
<name>WATimeInput</name>
<environment>Seaside</environment>
<super>Seaside.WACompound</super>
<private>false</private>
<indexed-type>none</indexed-type>
<inst-vars>withSeconds hours minutes seconds </inst-vars>
<class-inst-vars></class-inst-vars>
<imports></imports>
<category>Seaside-Canvas-Tags</category>
<attributes>
<package>Seaside-Canvas-Tags</package>
</attributes>
</class>

<class>
<name>WARadioButtonTag</name>
<environment>Seaside</environment>
<super>Seaside.WAFormInputTag</super>
<private>false</private>
<indexed-type>none</indexed-type>
<inst-vars></inst-vars>
<class-inst-vars></class-inst-vars>
<imports></imports>
<category>Seaside-Canvas-Tags</category>
<attributes>
<package>Seaside-Canvas-Tags</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>WADateInput</name>
<environment>Seaside</environment>
<super>Seaside.WACompound</super>
<private>false</private>
<indexed-type>none</indexed-type>
<inst-vars>options month day year </inst-vars>
<class-inst-vars></class-inst-vars>
<imports></imports>
<category>Seaside-Canvas-Tags</category>
<attributes>
<package>Seaside-Canvas-Tags</package>
</attributes>
</class>

<class>
<name>WASubmitButtonTag</name>
<environment>Seaside</environment>
<super>Seaside.WAFormInputTag</super>
<private>false</private>
<indexed-type>none</indexed-type>
<inst-vars></inst-vars>
<class-inst-vars></class-inst-vars>
<imports></imports>
<category>Seaside-Canvas-Tags</category>
<attributes>
<package>Seaside-Canvas-Tags</package>
</attributes>
</class>

<class>
<name>WACallbackRegistry</name>
<environment>Seaside</environment>
<super>Core.Object</super>
<private>false</private>
<indexed-type>none</indexed-type>
<inst-vars>context owner </inst-vars>
<class-inst-vars></class-inst-vars>
<imports></imports>
<category>Seaside-Callbacks</category>
<attributes>
<package>Seaside-Callbacks</package>
</attributes>
</class>

<class>
<name>WAMultiSelectTag</name>
<environment>Seaside</environment>
<super>Seaside.WASelectTag</super>
<private>false</private>
<indexed-type>none</indexed-type>
<inst-vars></inst-vars>
<class-inst-vars></class-inst-vars>
<imports></imports>
<category>Seaside-Canvas-Tags</category>
<attributes>
<package>Seaside-Canvas-Tags</package>
</attributes>
</class>

<class>
<name>Browser</name>
<environment>Squeak</environment>
<super>Core.Object</super>
<private>false</private>
<indexed-type>none</indexed-type>
<inst-vars>systemCategories classNames methodCategories selectors contents displayOption isClassComment namespace </inst-vars>
<class-inst-vars></class-inst-vars>
<imports></imports>
<category>Squeak</category>
<attributes>
<package>Squeak-ClassBrowser</package>
</attributes>
</class>

<class>
<name>WAHtmlStreamDocument</name>
<environment>Seaside</environment>
<super>Seaside.WAHtmlDocument</super>
<private>false</private>
<indexed-type>none</indexed-type>
<inst-vars>stream htmlEncoder urlEncoder </inst-vars>
<class-inst-vars></class-inst-vars>
<imports></imports>
<category>Seaside-Document</category>
<attributes>
<package>Seaside-Document</package>
</attributes>
</class>

<class>
<name>WARenderCanvas</name>
<environment>Seaside</environment>
<super>Seaside.WAHtmlCanvas</super>
<private>false</private>
<indexed-type>none</indexed-type>
<inst-vars>context callbacks </inst-vars>
<class-inst-vars></class-inst-vars>
<imports></imports>
<category>Seaside-Canvas</category>
<attributes>
<package>Seaside-Canvas</package>
</attributes>
</class>

</st-source>
