1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251
|
WebSPL and WSF Tutorial
=======================
This is a short tutorial to WebSPL and WSF. It is not a reference manual, so
also have a look at the "wsf" module, the "cgi" module and related modules in
the module references.
If you have not yet set up your Web Server to handle webspl scripts, please
have a look at the README file or the 'What is SPL?' chapter in this manual.
WebSPL Introduction
-------------------
WebSPL is an SPL runtime for CGI programming. There are two implementations
of WebSPL: The CGI script "webspl.cgi", for integrating WebSPL with the
Apache webserver using an 'action-handler', and "webspld", a stand-alone HTTP
server.
The SPL sources inlcude an example "httpd.conf" file for using "webspl.cgi"
with the Apache webserver. The "webspld" program prints its own usage info
when called with '--help'.
The interesting thing about WebSPL is, that, other than usual CGI scripts, a
WebSPL script is not executed once for each HTTP request. Instead, there is
just one (virtual) SPL process for a session and the WebSPL script can pause
it's execution at any time, wait for the user to do something and continue
execution as soon as the webbrowser sends the next HTTP request for the
session.
This is a tutorial - so here is our first example program:
/* -- webspltut/webspltut00.webspl -- */
Whenever task_pause() is called, the program execution stops and what has
been written since the last task_pause() (or the beginning of the program
execution) is displayed in the web browser.
As soon as the user reacts (i.e. clicks on "next" in this example), the
execution of the program is continued and task_pause() returns. The query
string parameter 'sid' is special: It always contains the session id and must
not be used for anything else in WebSPL applications. If the script is using
SPL tasks, it is also possible to include the ID of the task which should be
woken up in the 'sid' parameter. E.g. WSF is doing that.
WSF Introduction
----------------
WSF (WebSPL Forms) is a library for doing web application development with
WebSPL. WSF provides a widget based interface and so allows the development
of web applications with a look&feel like normal GUI programs. But it is
a bad choice for creating dynamic webpages since example given the browser
back button must not be used in WSF applications. For this (and other)
reasons it is recommended to open WSF applications in browser popup windows
without browser toolbars.
There are two base classes in WSF: WsfComponent and WsfDocument.
The WsfDocument object handles a browser window. Usually there is only one
instance of that object in a program, but if you want to use WSF to manage
multiple windows, one WsfDocument instance per browser window is required.
This WsfDocument instance is usually (i.e. per convention, there is no
technical reason for doing so) assigned to a global variable named "page".
The content of a browser window is organised as a tree of WsfComponent objects.
The root component must be assigned to the "root" member variable of the
"page" object. The WsfComponent object itself has a member variable called
"children" which is an array/hash of the child components.
In most cases objects derived from WsfComponent are used instead of
WsfComponent directly. One of these derived objects is WsfDisplay from
the "wsf_display" module (WsfDocument and WsfComponent are declared in
the "wsf" module).
The HTML text which should be displayed in a WsfDisplay object is simply
passed to the constructor. So here is a very simple WSF "Hello World"
application:
/* -- webspltut/webspltut01.webspl -- */
The page.main() does never return.
The default behavior of the WsfComponent object is to simply print the html
content of all its children in its get_html() method. So it is pretty useful
as a simple container for other more complex objects derived from WsfComponent:
/* -- webspltut/webspltut02.webspl -- */
But this application doesn't do much. So, lets create our own object derived
from WsfComponent which implements a simple counter:
/* -- webspltut/webspltut03.webspl -- */
So, when creating your own WSF Components, you need to overload the get_html()
method with something which returns the HTML code for your component and
overload the main() method with the main program for the task managing this
component. The task executing the main() method is created automatically by
the object constructor (and killed by the destroy() method). The function
task_co_return() must be called by main() to wait for user events. The variable
'dirty' must be set to 1 when anything happend with an effect on the get_html()
output. The root element of the HTML code generated by get_html() must have its
'id' attribute set to the value of the 'id' variable. There are methods (such as
the add_href() used in the example) for creating links, formulas, etc.
Have a look at the module reference for the "wsf" module for a full overview
of the WsfDocument and the WsfComponent objects.
Adding Menus
~~~~~~~~~~~~
Applications always have some type of menu. There is a generic WSF component
called WsfMenu (from the "wsf_menu" module) which implements nice menus. The
menu entries are function pointers which are called when the entry has been
clicked:
/* -- webspltut/webspltut04.webspl -- */
The HTML code generated by WsfMenu should be the first real code in the
webpage. So the example is using a simple WsfComponent as root component and
WsfMenu as its first child (0). The 2nd child (1) is set to WsfDisplay objects
by the menu callbacks to display messages.
Example Application: A very simple CMS
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Now lets write a real application: a very simple CMS. Don't expect too much:
It is not much more than just a web-based file manager for HTML files. Do not
wonder: the login for the login screen is covered in the next section.
/* -- webspltut/webspltut05.webspl -- */
Please run the application before you continue reading this tutorial (just to
make sure you know what this is all about).
The application defines two Objects: Editpage for dialog which lets the user
edit a page and Newpage for the dialog which lets the user create new pages.
The application also defines the function create_menu() for (re-)creating the
menu.
The main program just creates the page object, the root component, calls
create_menu() and enters page.main().
The create_menu() function
..........................
This function creates the menu as child component of the root component. The
"Pages" menu is dynamically generated from the list of *.html files in the
current directory. Whenever files are added or removed, create_menu() must be
called in order to update this menu.
A closure is used to store the filename to be opened together with the callback
function which is called when an entry in the "Pages" menu is clicked.
The Editpage Object
...................
Editpage is directly dervied from WsfComponent. The filename of the file to be
edited is passed as an argument to the constructor and copied to the variable
'filename' there. The methods get_html() and main() are overloaded.
The get_html() method simply displays an HTML form for editing the page. The
page content is loaded from the HTML file. Note how the 'xml::' and 'js::'
encoding functions are used to ensure the correctness of the generated HTML
code.
The main() method simply writes back the data to the file, or removes the file
if the user clicked on the "Remove" button. Since main() is automatically
called in an endless-loop, I did not add the "while (1) { ... }" loop here
explicitly. When main() is removing the file, the menu is updated by calling
create_menu() and the Editpage component is replacing itself with a simple
WsfComponent instance.
The Newpage Object
..................
The Newpage opject (also directly dervied from WsfComponent) is even simpler.
get_html() just displays an HTML form again. When the form is submitted and
main() returns from task_co_return(), it simply creates the new page (after
cleaning up the filename), calls create_menu() and replaces itself with an
Editpage instance for the newly created file.
Note that a Here-Document with indenting character is used when creating the
HTML text for the new page. This avoids ugly leading blanks in the HTML file
while keeping the indenting in the program intact.
Login screen and opening a popup window
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
The last example is using a pretty nice mechanism for doing authentication and
opening a popup window. Before creating the 'page' object and passing control
to WSF, this code is executed:
/* -- webspltut/webspltut06.spl -- */
There is nothing wrong with already accepting parameters at program startup.
The program expects username and password in the query string parameters "user"
and "pass". If they are not present or wrong, the login screen will be printed
and the program exits.
Only if correct authentication tokens are passed, the program continues
execution and initializes the WSF framework. It has shown that this approach is
very useful and much easier than actually including this step in the
application itself. One of the benefits of this approach is that a developer
can pass the authentication tokens already in the query string and so bypass
the additional screen. That's very comfortable for testing the application
during the development. Some applications even allow 'deep-linking' to some
dialogs this way to make testing easier. This approach also allows to open the
application in a popup window easily.
Opening a popup window makes sense since we do not want the user to click on
the browser 'back' button or bookmark any deep links of the application. It
doesn't really prevent the user from doing such stuff - but it makes it hard
enough to avoid most of the troubles.
Opening the popup window is simply done by printing the javascript code and
then calling task_pause(). As soon as the the browser tries to load the content
of the popup window, the session is resumed and task_pause() returns.
W2T Introduction
----------------
The W2T (Web 2.0 Toolkit) module provides another framework for web application
development. W2T applications only send an initial XML document (usually XHTML
or SVG) to the browser and everything after is done using AJAX XML RPC calls.
The W2T module is basically a collection of SPL and JavaScript functions which
provide functionality for updating the XML DOM tree displayed in the browser
window from server-side SPL and call server-side SPL event callbacks from
browser-side JavaScript code.
Here is a small W2T example program which is using SVG. Note that at the time
of this writing Firefox 1.5 is the only browser which can be used as frontend
for W2T SVG programs:
/* -- webspl_demo/w2tdemo_svg.webspl -- */
The W2T module also includes some JavaScript helper functions for doing
animations and other funny stuff. W2T is under development and a more detailed
documentation will be provided when it is finished.
|