Module "wsf"
============

WebSPL Forms Library

This module provides a frame work for doing application development
with WebSPL. The basic idea is to split down the user interface into
so-called components. Each component provides a part of the DOM tree
which is displayed in the browser window. There is a seperate program
task for each component - so they can act as independent as the
programmer wants.

This module provides WsfComponent, the base object for WSF Components,
and WsfDocument, the object which manages the interaction with the
Browser.

Other Modules provide additional WSF Components. E.g.:

	WsfDebug	WsfDialog
	WsfDisplay	WsfEdit
	WsfEditSql	WsfGraph
	WsfMenu		WsfSwitch

If the browser has support for it, WsfDocument does only send those
parts of the DOM tree to the browser which have actually changed and replace
them 'in place' in the current page using a little JavaScript hack.
 
function wsf_get_domupdate_status(@methods) ;
---------------------------------------------

Checks the HTTP Agent string and auto-detects if the browser is able
to synamically update the DOM tree.

It is possible to specify methods as arguments in the order of preference.
Then this methods are checked in that order. E.g.:

	var method = wsf_get_domupdate_status("iframe", "xmlhttprequest");

Will return "iframe", "xmlhttprequest" or "none".

If no arguments are given the function eighter returns "iframe" or
"none". The "xmlhttprequest" method is left out in this case.

Usually this is only used internally by the WsfDocument object to
initialize WsfDocument.domupdate and doesn't need to be called by the
user.
 

object WsfComponent
-------------------

The base WsfComponent object. All other Wsf Components are derived from
this Object.
 

static WsfComponent.id_counter = 0;
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

This counter is used by the constructor to create the id for
new instances of Wsf Components.
	 

var WsfComponent.id;
~~~~~~~~~~~~~~~~~~~~

The id of this component instance. It is set automatically by the
contructor and must be included as "id" attribute in the top element 
of the HTML tree returned by get_html().

This also is the name of the task created for this component by the
constructor.
	 

var WsfComponent.sid;
~~~~~~~~~~~~~~~~~~~~~

The sid (session id) for the task running this component. It must
be included as parameter 'sid' in all query strings. The methods
add_action(), add_href() and add_javascript() should
be used for creating links, etc.
	 

var WsfComponent.dirty = 0;
~~~~~~~~~~~~~~~~~~~~~~~~~~~

This variable must be set to 1 whenever it is neccessary to call
get_html() again and refresh the browser view of this component.

It is also possible to set this to 1 if there have been any changes
in the children array.
	 

var WsfComponent.children;
~~~~~~~~~~~~~~~~~~~~~~~~~~

An array of child components. The keys may be freely choosen. The
get_html() method must run get_html() for all children and
include the return value in its own output.
	 

var WsfComponent.main_task;
~~~~~~~~~~~~~~~~~~~~~~~~~~~

The name of the main task running the WsfDocument instance which
is responsible for this component. This is automatically set by
WsfDocument when checking for set dirty flags and by the
child_set() method.
	 

method WsfComponent.add_action(url);
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

Whenever a form is generated by get_html(), this method must be
used to create the "action" attribute in the <form> tag. A hidden
input field for the "sid" parameter mus also be generated. E.g.:

	<form id="$id" ${add_action(cgi.url)}>
	<input type="hidden" name="sid" value="${sid}" />
	...
	</form>
	 

method WsfComponent.add_href(url);
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

Whenever a HTML link is created by get_html(), this method
must be used to create the "href" attribute in the <a> tag. E.g.:

	<a ${add_href("${cgi.url}?sid=${sid}&foo=bar")}>Foobar</a>
	 

method WsfComponent.add_javascript(url);
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

Whenever JavaScript is used in the code created by get_html(),
this method must be used to create the statement which sets
location.href to the new value. E.g.:

	onClick="${ add_javascript("${cgi.url}?sid=${sid}&foo=bar") }"

the URL will be quoted with single quotes in the generated code. So
there is no problem with embedding it using "onFoobar" JavaScript
event handlers. No additional quoting is done. So something like that
for creating query string parameters with JavaScript is possible too:

	onClick="${ add_javascript("${cgi.url}?sid=${sid}&foo=' + (3+5) + '") }"
	 

method WsfComponent.get_html_children();
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

A simple method for calling get_html_cached() on all children
and concatenating the results.
	 

method WsfComponent.get_html_cached();
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

This method returns the HTML code for this component. If the
dirty flag is set, get_html() is called to generate
the HTML code. Otherwise a cached version of the HTML code is
returned.
	 

method WsfComponent.get_html();
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

The method for creating the HTML code. The top HTML element must
have the attribute "id" set to the value of the id member
variable. The default behavior is to simply return:

	'<div id="$id">\n' ~ get_html_children() ~ '</div>\n'
	 

method WsfComponent.main();
~~~~~~~~~~~~~~~~~~~~~~~~~~~

The main function for the task running this component. It is first
called by the constructor and is running until it calls
task_co_return().

After that, get_html() is called by the WsfDocument object
to create the HTML representation.

The task_co_return() function returns when the user has done
something in his browser window which effects this component; i.e.
has clicked a link or submitted a form generated by get_html().

Then this function can react to the event and call task_co_return()
again when it has finished processing this event. Don't forget to
set dirty to 1 if get_html() needs to be called again.

If this method does not call task_co_return(), the task will hang
in an endless loop. So don't forget to do that!
	 

method WsfComponent.child_set(name, obj);
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

Create (substitute) a child component.
The 1st parameter is the key in the children array, the 2nd
parameter the new component object.
	 

method WsfComponent.child_remove(name);
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

Remove a child component.
The parameter is the key in the children array.
	 

method WsfComponent.destroy();
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

The destructor. It needs to be called when the object isn't needed
anymore to kill the task assigned to that object. It also calls the
destroy method of all child components.

It is save to call that from the main() method. If you do so,
killing the task is postponed until main() calls task_co_return()
the next time. main() will then never return from this function
again.
	 

method WsfComponent.init();
~~~~~~~~~~~~~~~~~~~~~~~~~~~

The constructor.
	 

object WsfDocument
------------------

The WsfDocument object. There must be one WsfDocument object for
every browser window which is under control of WSF. Usually it
is instanciated and assigned to a variable called 'page', then
initialized and finally the main() method is called. E.g.:

	var page = new WsfDocument();
	page.title = "My Application Title";
	page.root = new MyFunnyRootWsfComponent();
	page.main();

The main() method never returns.
 

static WsfDocument.domupdate = wsf_get_domupdate_status();
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

This variable is automatically set when the module is loaded.
It contains the return code of wsf_get_domupdate_status().

It is possible to change that variable before instanciating
WsfDocument the first time. After that, the variable shouldn't
be touched anymore.

Additionally it is possible to change that variable by passing
a cgi query string parameter on program startup:

	wsf_domupdate={ iframe | xmlhttprequest | none }

If the domupdate mechanism is running in "iframe" mode,
the iframe can be set visible by passing the query string
parameter "wsf_showiframe".

The "xmlhttprequest" method is probably the best implementation,
but right now it is not possible to do file uploads using this
method.
	 

static WsfDocument.showiframe = 0;
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

If domupdate is set to "iframe" and this variable is set to 1,
the iframe used for the domupdate mechanism will be visible. This
is only of interest for debugging purposes.
	 

var WsfDocument.root;
~~~~~~~~~~~~~~~~~~~~~

This is the root component for this WsfDocument. It must be set
to an instance of WsfComponent (or any derived object) before
the main() method is called.
	 

var WsfDocument.title = "";
~~~~~~~~~~~~~~~~~~~~~~~~~~~

The content for the <title> tag generated by this object. This
can not be changed later, if domupdate is set to "iframe".
So it must be set before calling main(), or not at all.
	 

var WsfDocument.html_head = "";
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

HTML code to be included between <head> and </head>.
Must be set before calling main(), or not at all.
	 

var WsfDocument.body_attr = "";
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

HTML attributes to be set in the <body> tag.
Must be set before calling main(), or not at all.
	 

var WsfDocument.callbacks;
~~~~~~~~~~~~~~~~~~~~~~~~~~

A hash with arrays of callback functions. Use callback_add
and callback_del to maintain the entries.
	 

method WsfDocument.callback_add(type, func);
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

Add a callback function to the callbacks data structure.

The following callback types are called by this object:

	pre_update	called before the html (xml) output is created.
	post_update	called after the html (xml) output is created.
	 

method WsfDocument.callback_del(type, func);
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

Add a callback function from the callbacks data structure.
	 

method WsfDocument.callback_call(type, %options);
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

Call all callbacks of a type. The callback is passed the type as
first parameter and this WfsDocument object as 2nd parameter.
The named parameters are also passed thru to the callback functions.
	 

method WsfDocument.main();
~~~~~~~~~~~~~~~~~~~~~~~~~~

This method implements the main loop of a WsfDocument.
It must be called after setting up the variables described
below.

It handles the creation of HTML pages which are then passed
to the browser. Whenever the WsfComponent.main() method
calls task_co_return() after processing a user event, control
is passed back to this method so it can update the browser window.

This function does never return.
	 
