Revert "html update"
[clinton/website/site/unknownlamer.org.git] / UCWNotes.html
CommitLineData
2aff8b5c 1<?xml version="1.0" encoding="utf-8" ?>
2<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
3 "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
4<html xmlns="http://www.w3.org/1999/xhtml">
5 <head>
6 <title>Roadmap to UCW Codebase</title>
7 <meta name="generator" content="muse.el" />
8 <meta http-equiv="Content-Type"
9 content="text/html; charset=utf-8" />
11f9bd69
CE
10 <meta name="viewport"
11 content="width=device-width, initial-scale=1.0" />
98266870 12 <link href="https://feeds.unknownlamer.org/rss/site-updates"
7404d4e1 13 rel="alternate" type="application/rss+xml" title="Updates Feed" />
14
15<link rel="stylesheet" href="default.css" />
2aff8b5c 16 </head>
17 <body>
18 <h1>Roadmap to UCW Codebase</h1>
19 <div class="contents">
20<dl>
21<dt>
22<a href="#sec1">Abstract</a>
23</dt>
24<dt>
25<a href="#sec2">Roadmap</a>
26</dt>
27<dd>
28<dl>
29<dt>
30<a href="#sec3">Applications</a>
31</dt>
32<dd>
33<dl>
34<dt>
35<a href="#sec4">Cookie</a>
36</dt>
37<dt>
38<a href="#sec5">L10n</a>
39</dt>
40<dt>
41<a href="#sec6">Secure</a>
42</dt>
43</dl>
44</dd>
45<dt>
46<a href="#sec7">Components</a>
47</dt>
48<dd>
49<dl>
50<dt>
51<a href="#sec8">Windows</a>
52</dt>
53<dt>
54<a href="#sec9">Containers</a>
55</dt>
56<dt>
57<a href="#sec10">Dialogs</a>
58</dt>
59<dt>
60<a href="#sec11">Forms</a>
61</dt>
62<dt>
63<a href="#sec12">Templates</a>
64</dt>
65<dt>
66<a href="#sec13">Utility Mixin Components</a>
67</dt>
68</dl>
69</dd>
70<dt>
71<a href="#sec14">Control Flow</a>
72</dt>
73<dd>
74<dl>
75<dt>
76<a href="#sec15">Calling</a>
77</dt>
78<dt>
79<a href="#sec16">Actions</a>
80</dt>
81<dt>
82<a href="#sec17">Entry Points</a>
83</dt>
84</dl>
85</dd>
86<dt>
87<a href="#sec18">Dispatching</a>
88</dt>
89<dd>
90<dl>
91<dt>
92<a href="#sec19">Simple Dispatcher</a>
93</dt>
94</dl>
95</dd>
96<dt>
97<a href="#sec20">Server</a>
98</dt>
99<dt>
100<a href="#sec21">Debugging</a>
101</dt>
102<dd>
103<dl>
104<dt>
105<a href="#sec22">Inspector</a>
106</dt>
107</dl>
108</dd>
109</dl>
110</dd>
111<dt>
112<a href="#sec23">Tips</a>
113</dt>
114<dd>
115<dl>
116<dt>
117<a href="#sec24">Getting dojo to load</a>
118</dt>
119<dt>
120<a href="#sec25">Specials Bound During Rendering</a>
121</dt>
122<dt>
123<a href="#sec26">Printing to the yaclml stream</a>
124</dt>
125</dl>
126</dd>
127</dl>
128</div>
129
130
11f9bd69
CE
131<!-- Page published by Emacs Muse begins here -->
132<h2><a name="sec1" id="sec1"></a>
2aff8b5c 133Abstract</h2>
134
135<p><a href="http://common-lisp.net/project/ucw/">UnCommon Web</a> is a very powerful and mature web framework for Common
136Lisp, but is a bit difficult to learn. It is documented
137extensively&mdash;in the form of docstrings. These are extremely helpful
138once you've figured out the rough structure of UCW, but they are of no
139help when first learning unless you just read most of the source. I
140ended up having to do that, and after some urging along by folks in
141<code>#ucw</code> I decided to clean up my planner notes and publish them for
142public consumption.</p>
143
144<p>The roadmap is presented with major sections ordered in a logical
145order for learning the framework. The sections are ordered internally
146in order of most immediately useful to least, but it may be worth
147hopping between major sections before reading all of the details. I
148have used abridged class definitions and docstrings with occasional
149commentary to clarify things.</p>
150
151
152<h2><a name="sec2" id="sec2"></a>
153Roadmap</h2>
154
155<h3><a name="sec3" id="sec3"></a>
156Applications</h3>
157
158<p class="first">Applications are a bundle of entry points. The base class is,
159naturally, <code>standard-application</code>, but you should instead derive your
160application class from <code>modular-application</code> and any standard or custom
161application mixins you find useful.</p>
162
163<p><a href="http://www.uncommon-web.com/darcsweb/darcsweb.cgi?r=ucw_dev;a=headblob;f=/src/rerl/standard-classes.lisp">src/rerl/standard-classes.lisp</a></p>
164
165<pre class="src">
7404d4e1 166(<span class="emacs-face-keyword">defclass</span> <span class="emacs-face-type">standard-application</span> (application)
167 ((url-prefix <span class="emacs-face-builtin">:initarg</span> <span class="emacs-face-builtin">:url-prefix</span>
4222507d 168 <span class="emacs-face-builtin">:documentation</span> <span class="emacs-face-doc">"A string specifying the
2aff8b5c 169start (prefix) of all the urls this app should handle.
170
171This value is used by the standard-server to decide what app a
172particular request is aimed at and for generating links to
173actions within the app. "</span>)
7404d4e1 174 (www-roots <span class="emacs-face-builtin">:initarg</span> <span class="emacs-face-builtin">:www-roots</span>
4222507d 175 <span class="emacs-face-builtin">:documentation</span> <span class="emacs-face-doc">"A list of directories (pathname
2aff8b5c 176specifiers) or cons-cell (URL-subdir . pathname) to use when looking for static files."</span>)
7404d4e1 177 (dispatchers <span class="emacs-face-builtin">:initarg</span> <span class="emacs-face-builtin">:dispatchers</span>
4222507d 178 <span class="emacs-face-builtin">:documentation</span> <span class="emacs-face-doc">"A list of request
2aff8b5c 179dispatchers. The user supplied list of dispatchers is extended
180with other dispatchers that are required for UCW to function
181properly (action-dispatcher, a parenscript-dispatcher, etc). If
182you want full control over the active dispatchers use the (setf
183application.dispatchers) accessor or, if you want control over
184the order of the dispathcers, (slot-value instance
185'dispatchers)."</span>))
4222507d 186 (<span class="emacs-face-builtin">:documentation</span> <span class="emacs-face-doc">"The default UCW application class."</span>))
2aff8b5c 187</pre>
188
189<p><a href="http://www.uncommon-web.com/darcsweb/darcsweb.cgi?r=ucw_dev;a=headblob;f=/src/rerl/modular-application/modular-application.lisp">src/rerl/modular-application/modular-application.lisp</a></p>
190
191<pre class="src">
7404d4e1 192(<span class="emacs-face-keyword">defclass</span> <span class="emacs-face-type">modular-application-mixin</span> ()
2aff8b5c 193 ()
4222507d 194 (<span class="emacs-face-builtin">:documentation</span> <span class="emacs-face-doc">"Superclass for all application mixins."</span>))
2aff8b5c 195
7404d4e1 196(<span class="emacs-face-keyword">defclass</span> <span class="emacs-face-type">modular-application</span> (standard-application modular-application-mixin)
2aff8b5c 197 ...)
198</pre>
199
200<h4><a name="sec4" id="sec4"></a>
201Cookie</h4>
202
203<p><a href="http://www.uncommon-web.com/darcsweb/darcsweb.cgi?r=ucw_dev;a=headblob;f=/src/rerl/modular-application/cookie-module.lisp">src/rerl/modular-application/cookie-module.lisp</a></p>
204
205<pre class="src">
7404d4e1 206(<span class="emacs-face-keyword">defclass</span> <span class="emacs-face-type">cookie-session-application-module</span> (modular-application-mixin)
4222507d 207 (<span class="emacs-face-builtin">:documentation</span> <span class="emacs-face-doc">"Class for applications which use cookies for sesion tracking.
2aff8b5c 208
209Cookie session applications work exactly like
210standard-applications except that when the session is not found
211using the standard mechanisms the id is looked for in a cookie."</span>))
212</pre>
213
214<p>This is the most useful of the application components. It makes your
215application urls readable by stashing the session id into a cookie
216rather than as a set of long and ugly GET parameters.</p>
217
218
219<h4><a name="sec5" id="sec5"></a>
220L10n</h4>
221
222<p><a href="http://www.uncommon-web.com/darcsweb/darcsweb.cgi?r=ucw_dev;a=headblob;f=/src/rerl/modular-application/l10n-module.lisp">src/rerl/modular-application/l10n-module.lisp</a></p>
223
224<pre class="src">
7404d4e1 225(<span class="emacs-face-keyword">defclass</span> <span class="emacs-face-type">l10n-application-module</span> (modular-application-mixin)
4222507d 226 (<span class="emacs-face-builtin">:documentation</span> <span class="emacs-face-doc">"Application class which can handle l10n requests."</span>))
2aff8b5c 227</pre>
228
229
230<h4><a name="sec6" id="sec6"></a>
231Secure</h4>
232
233<p><a href="http://www.uncommon-web.com/darcsweb/darcsweb.cgi?r=ucw_dev;a=headblob;f=/src/rerl/modular-application/security-module.lisp">src/rerl/modular-application/security-module.lisp</a></p>
234
235<pre class="src">
7404d4e1 236(<span class="emacs-face-keyword">defclass</span> <span class="emacs-face-type">secure-application-module</span> (modular-application-mixin)
237 (<span class="emacs-face-builtin">:documentation</span>
4222507d 238 <span class="emacs-face-doc">"Mixin class for applications which require authorized access.
2aff8b5c 239Concrete application must specialize the following methods:
240APPLICATION-FIND-USER (APPLICATION USERNAME)
241APPLICATION-CHECK-PASSWORD (APPLICATION USER PASSWORD)
242APPLICATION-AUTHORIZE-CALLZE-CALL (APPLICATION USER FROM-COMPONENT TO-COMPONENT)."</span>))
243</pre>
244
245
246
247<h3><a name="sec7" id="sec7"></a>
248Components</h3>
249
250<p class="first">A component is a special class that handles the complexities of
251continuation suspension and such for you. New components are derived
252from the existing ones by using <code>defcomponent</code> instead of <code>defclass</code>. This
253adds a few extra slot and class options, and ensures that the proper
254metaclass is set.</p>
255
256<p><a href="http://www.uncommon-web.com/darcsweb/darcsweb.cgi?r=ucw_dev;a=headblob;f=/src/rerl/standard-component/standard-component.lisp">src/rerl/standard-component/standard-component.lisp</a></p>
257
258<pre class="src">
7404d4e1 259(<span class="emacs-face-keyword">defmacro</span> <span class="emacs-face-function-name">defcomponent</span> (name supers slots <span class="emacs-face-type">&amp;rest</span> options)
260 <span class="emacs-face-doc">"Macro for defining a component class.
2aff8b5c 261
262This macro is used to create component classes and provides
263options for easily creating the methods which often accompany a
264component definition.
265
266NAME, SUPERS and SLOTS as treated as per defclass. The following
267extra options are allowed:
268
269 (:ENTRY-POINT url (&amp;key application class)) - Define an
270 entry-point on the url URL which simply calls an instance of
271 this component. Any request parameters passed to the entry-point
272 are used to initialize the slots in the component. This option
273 may appear multiple times.
274
275 (:DEFAULT-BACKTRACK function-designator) - Unless the slots
276 already have a :backtrack option FUNCTION-DESIGNATOR is
277 added. As with the 'regular' :backtrack options if you pass T
278 here it is assumed to mean #'IDENTITY.
279
280 (:RENDER (&amp;optional COMPONENT) &amp;body BODY) - Generate a render
281 method specialized to COMPONENT. COMPONENT may be a symbol, in
282 which case the method will be specialized on the componnet
283 class. If COMPONNET is omited the component is bound to a
284 variable with the same name as the class.
285
286 (:ACTION &amp;optional NAME) - Generate a defaction form named
287 NAME (which defaults to the name of the component) which simply
288 CALL's this component class passing all the arguments passed to
289 the action as initargs."</span>)
290
7404d4e1 291<span class="emacs-face-comment-delimiter">;;; </span><span class="emacs-face-comment">Extra Slot Options
292</span><span class="emacs-face-string">"Other than the initargs for standard slots the following
2aff8b5c 293options can be passed to component slots:
294
295:backtrack [ T | NIL | FUNCTION-NAME ] - Specify that this slot
296should be backtracked (or not if NIL is passed as the value). If
297the value is neither T nor NIL then it must be a function which
298will be used as the copyer.
299
300:component [ TYPE | ( TYPE &amp;rest INITARGS ) ] - Specify that this
301slot is actually a nested component of type TYPE. When instances
302of the class are created this slot will be set to an instance of
303type TYPE and it's place will be set to this slot. If a list is
304passed to :component then TYPE (which isn't evaluated) will be
305passed as the first argument to make-instance. The INITARGS will
306be eval'd and apply'd to make-instance. The result of this call
307to make-instance will be used as the effective component
308object."</span>
309</pre>
310
311<h4><a name="sec8" id="sec8"></a>
312Windows</h4>
313
314<p class="first">A window-component represents a top level browser window, naturally.</p>
315
316<p><a href="http://www.uncommon-web.com/darcsweb/darcsweb.cgi?r=ucw_dev;a=headblob;f=/src/components/window.lisp">src/components/window.lisp</a></p>
317
318<pre class="src">
7404d4e1 319(<span class="emacs-face-keyword">defclass</span> <span class="emacs-face-type">window-component</span> ()
2aff8b5c 320 ((content-type)))
321
7404d4e1 322(<span class="emacs-face-keyword">defclass</span> <span class="emacs-face-type">simple-window-component</span> (window-component)
2aff8b5c 323 ((title)
324 (stylesheet)
4222507d 325 (javascript <span class="emacs-face-builtin">:documentation</span> <span class="emacs-face-doc">"List of javascript includes.
2aff8b5c 326
327Each element must be a list whose first value is either the
328symbol :SRC or :JS.
329
330 (:SRC url) - writes &lt;script src=\"URL\"&gt;&lt;/script&gt; tag.
331 (:JS form) - equivalent to (:SCRIPT (js:js* form))
332 (:SCRIPT string) - write &lt;script&gt;STRING&lt;/script&gt;.
333
334The elements will be rendered in order."</span>)
335 ...))
336</pre>
337
338<p><code>window-component</code> could be useful for doing things like dumping binary
339data to the user, or just deriving your own funky top level window
340type.</p>
341
342<p><code>simple-window-component</code> is the easiest for displaying standard
343webpage. It provides a wrapping method on render that displays the
344html boilerplate based on your component slot values which is what one
345wants most of the time. The initargs to <code>simple-window-component</code> have
346the same names as the slots.</p>
347
348<h5>Status Bar</h5>
349
350<p><a href="http://www.uncommon-web.com/darcsweb/darcsweb.cgi?r=ucw_dev;a=headblob;f=/src/components/status-bar.lisp">src/components/status-bar.lisp</a></p>
351
352<p>There is a generic status bar interface. Messages severity is one of
353<code>(:error :warn :info)</code>. Note that the default status bar render method
354just shows a div with status messages. A derivative could be defined
355to insert messages into the browser status bar.</p>
356
357<pre class="src">
358(defcomponent status-bar ()
4222507d 359 ((messages <span class="emacs-face-builtin">:documentation</span> <span class="emacs-face-doc">"An ALIST of the messages to
2aff8b5c 360show. Each element is a cons of the form (SEVERITY .
361MESSAGE). SEVERITY is one of :ERROR, :WARN, :INFO and MESSAGE is
362a string which will be html-escaped."</span>)
363 ...)
4222507d 364 (<span class="emacs-face-builtin">:documentation</span> <span class="emacs-face-doc">"Stateless status bar to display messages."</span>))
2aff8b5c 365
7404d4e1 366(<span class="emacs-face-keyword">defgeneric</span> <span class="emacs-face-function-name">add-message</span> (status-bar msg <span class="emacs-face-type">&amp;key</span> severity <span class="emacs-face-type">&amp;allow-other-keys</span>)
4222507d 367 (<span class="emacs-face-builtin">:documentation</span> <span class="emacs-face-doc">"Add the message text MSG to STATUS-BAR with
2aff8b5c 368severity SEVERITY."</span>))
369</pre>
370
371<pre class="src">
372(defcomponent status-bar-mixin ()
7404d4e1 373 ((status-bar <span class="emacs-face-builtin">:accessor</span> status-bar
374 <span class="emacs-face-builtin">:initarg</span> status-bar
375 <span class="emacs-face-builtin">:component</span> (status-bar))))
2aff8b5c 376
7404d4e1 377(<span class="emacs-face-keyword">defmethod</span> <span class="emacs-face-function-name">show-status-bar</span> ((win status-bar-mixin))
2aff8b5c 378 (render (status-bar win)))
379
7404d4e1 380(<span class="emacs-face-keyword">defgeneric</span> <span class="emacs-face-function-name">show-message</span> (msg <span class="emacs-face-type">&amp;key</span> severity <span class="emacs-face-type">&amp;allow-other-keys</span>)
4222507d 381 (<span class="emacs-face-builtin">:documentation</span> <span class="emacs-face-doc">"Show a message in the status bar. Only works if
2aff8b5c 382 current window is a status-bar-mixin"</span>))
383</pre>
384
385
386<h5>Redirect</h5>
387
388<p><a href="http://www.uncommon-web.com/darcsweb/darcsweb.cgi?r=ucw_dev;a=headblob;f=/src/components/redirect.lisp">src/components/redirect.lisp</a></p>
389
390<pre class="src">
7404d4e1 391(<span class="emacs-face-keyword">defclass</span> <span class="emacs-face-type">redirect-component</span> ()
392 ((target <span class="emacs-face-builtin">:accessor</span> target <span class="emacs-face-builtin">:initarg</span> <span class="emacs-face-builtin">:target</span>))
393 (<span class="emacs-face-builtin">:metaclass</span> standard-component-class)
4222507d 394 (<span class="emacs-face-builtin">:documentation</span> <span class="emacs-face-doc">"Send a client redirect.
2aff8b5c 395
396This component, which must be used as a window-component,
397redirects the client to the url specified in the target slot. A
398302 (as opposed to 303) response code is sent to ensure
399compatability with older browsers.
400
401The redirect component never answers."</span>))
402</pre>
403
404<p>There is also a <code>meta-refresh</code> procedure.</p>
405
406<pre class="src">
407(defun/cc meta-refresh ()
7404d4e1 408 <span class="emacs-face-string">"Cause a meta-refresh (a freshly got (GET) url) at this point.
2aff8b5c 409This is useful in order to have a GET url after a form POST's
410actions have completed running. The user can then refresh to his
411heart's content."</span>)
412</pre>
413
414
415
416<h4><a name="sec9" id="sec9"></a>
417Containers</h4>
418
419<p><a href="http://www.uncommon-web.com/darcsweb/darcsweb.cgi?r=ucw_dev;a=headblob;f=/src/components/container.lisp">src/components/container.lisp</a></p>
420
421<pre class="src">
7404d4e1 422(<span class="emacs-face-keyword">defclass</span> <span class="emacs-face-type">container</span> ()
2aff8b5c 423 (...)
7404d4e1 424 (<span class="emacs-face-builtin">:metaclass</span> standard-component-class)
4222507d 425 (<span class="emacs-face-builtin">:documentation</span> <span class="emacs-face-doc">"Allow multiple components to share the same place.
2aff8b5c 426
427The container component serves to manage a set of components.
428It does not provide any render impementation, which is the
429resposibility of the subclasses (e.g. switching-container or
430list-container).
431
432Each contained component has a \"key\" associated with it which
433is used to retrieve a particular component. Keys are compared with
434container.key-test.
435
436The :contents inintarg, if provided, must be either a list of (key .
437component) or a list of components. In the latter case it will
438be converted into (component . component) form."</span>))
439</pre>
440
441<h5>Protocol</h5>
442
443<ul>
444<li><code>child-components</code></li>
445<li><code>find-component CONTAINER KEY</code></li>
446<li><code>remove-component</code></li>
447<li><code>(setf find-component CONTAINER KEY) COMPONENT</code> -&gt;
448<code>add-component CONTAINER COMPONENT KEY</code></li>
449</ul>
450
451
452<h5>Switching Container</h5>
453
454<p><a href="http://www.uncommon-web.com/darcsweb/darcsweb.cgi?r=ucw_dev;a=headblob;f=/src/components/container.lisp">src/components/container.lisp</a></p>
455
456<pre class="src">
7404d4e1 457(<span class="emacs-face-keyword">defclass</span> <span class="emacs-face-type">switching-container</span> ...
4222507d 458 (<span class="emacs-face-builtin">:documentation</span> <span class="emacs-face-doc">"A simple renderable container component.
2aff8b5c 459
460This component is like the regular CONTAINER but serves to manage a set
461of components which share the same place in the UI. Therefore it provides
462an implementation of RENDER which simply renders its current component.
463
464The switching-container component class is generally used as the super
465class for navigatation components and tabbed-pane like
466components."</span>))
467</pre>
468
469<p>Subclass and <code>(defmethod render :around ...)</code> to render navigation using
470<code>(call-next-method)</code> to render the selected component.</p>
471
472<h5>Protocol</h5>
473
474<ul>
475<li><code>container.current-component COMPONENT</code></li>
476<li><code>(setf container.current-component CONTAINER) COMPONENT</code></li>
477</ul>
478
479
480
481<h5>Tabbed Pane</h5>
482
483<p><a href="http://www.uncommon-web.com/darcsweb/darcsweb.cgi?r=ucw_dev;a=headblob;f=/src/components/tabbed-pane.lisp">src/components/tabbed-pane.lisp</a></p>
484
485<pre class="src">
486(defcomponent tabbed-pane (switching-container)
4222507d 487 (<span class="emacs-face-builtin">:documentation</span> <span class="emacs-face-doc">"Component for providing the user with a standard \"tabbed pane\" GUI widget."</span>))
2aff8b5c 488</pre>
489
490<p>Provides a generic tabbed pane that renders a nested div split into a
491naviation and content box. The navigation box is a set of styled divs
492containing the navigation links.</p>
493
494
495
496<h4><a name="sec10" id="sec10"></a>
497Dialogs</h4>
498
499<p class="first">A few convenience dialogs are provided for grabbing data from the
500user.</p>
501
502<h5>login</h5>
503
504<p><a href="http://www.uncommon-web.com/darcsweb/darcsweb.cgi?r=ucw_dev;a=headblob;f=/src/components/login.lisp">src/components/login.lisp</a></p>
505
506<pre class="src">
7404d4e1 507(<span class="emacs-face-keyword">defclass</span> <span class="emacs-face-type">login</span> ()
2aff8b5c 508 ((username) (password) (message))
4222507d 509 (<span class="emacs-face-builtin">:documentation</span> <span class="emacs-face-doc">"Generic login (input username and password) component.
2aff8b5c 510
511This component, which must be embedded in another component,
512presents the user with a simple two fielded login form.
513
514When the user attempts a login the action try-login is called,
515try-login calls the generic function check-credentials passing it
516the login component. If check-credentials returns true then the
517login-successful action is called, otherwise the message slot of
518the login component is set (to a generic \"bad username\"
519message).
520
521The default implementaion of login-successful simply answers t,
522no default implementation of check-credentials is
523provided. Developers should use sub-classes of login for which
524all the required methods have been definined."</span>)
7404d4e1 525 (<span class="emacs-face-builtin">:metaclass</span> standard-component-class))
2aff8b5c 526</pre>
527
528<pre class="src">
7404d4e1 529(<span class="emacs-face-keyword">defgeneric</span> <span class="emacs-face-function-name">check-credentials</span> (login)
4222507d 530 (<span class="emacs-face-builtin">:documentation</span> <span class="emacs-face-doc">"Returns T if LOGIN is valid."</span>))
2aff8b5c 531
532(defaction login-successful ((l login))
533 (answer t))
534</pre>
535
536<p><a href="http://www.uncommon-web.com/darcsweb/darcsweb.cgi?r=ucw_dev;a=headblob;f=/src/components/user-login.lisp">src/components/user-login.lisp</a></p>
537
538<pre class="src">
539(defcomponent user-login (simple-window-component status-bar-mixin)
540 ((username string-field) (password password-field)))
541</pre>
542
543<p>Used by <code>secure-application-module</code> to provide a user login. Relevant
544protocol details follow.</p>
545
546<pre class="src">
7404d4e1 547(<span class="emacs-face-keyword">defmethod</span> <span class="emacs-face-function-name">check-credentials</span> ((self user-login))
548 (<span class="emacs-face-keyword">let*</span> ((username (value (username self)))
2aff8b5c 549 (password (value (password self)))
550 (user (find-application-user username)))
f6d19803 551 (<span class="emacs-face-keyword">when</span> (and user (<span class="emacs-face-warning">check-user-password</span> user password))
2aff8b5c 552 user)))
553
7404d4e1 554(<span class="emacs-face-keyword">defgeneric</span> <span class="emacs-face-function-name">application-find-user</span> (application username)
4222507d 555 (<span class="emacs-face-builtin">:documentation</span> <span class="emacs-face-doc">"Find USER by USERNAME for APPLICATION."</span>))
2aff8b5c 556</pre>
557
558
559<h5>error</h5>
560
561<p><a href="http://www.uncommon-web.com/darcsweb/darcsweb.cgi?r=ucw_dev;a=headblob;f=/src/components/error.lisp">src/components/error.lisp</a></p>
562
563<pre class="src">
7404d4e1 564(<span class="emacs-face-keyword">defclass</span> <span class="emacs-face-type">error-message</span> (simple-window-component)
565 ((message <span class="emacs-face-builtin">:accessor</span> message <span class="emacs-face-builtin">:initarg</span> <span class="emacs-face-builtin">:message</span> <span class="emacs-face-builtin">:initform</span> <span class="emacs-face-string">"ERROR [no message specified]"</span>))
4222507d 566 (<span class="emacs-face-builtin">:documentation</span> <span class="emacs-face-doc">"Generic component for showing server side
2aff8b5c 567 error messages."</span>)
7404d4e1 568 (<span class="emacs-face-builtin">:metaclass</span> standard-component-class))
2aff8b5c 569
7404d4e1 570(<span class="emacs-face-keyword">defclass</span> <span class="emacs-face-type">error-component</span> (error-message)
571 ((condition <span class="emacs-face-builtin">:accessor</span> error.condition <span class="emacs-face-builtin">:initarg</span> <span class="emacs-face-builtin">:condition</span> <span class="emacs-face-builtin">:initform</span> nil)
572 (backtrace <span class="emacs-face-builtin">:accessor</span> error.backtrace <span class="emacs-face-builtin">:initarg</span> <span class="emacs-face-builtin">:backtrace</span>))
4222507d 573 (<span class="emacs-face-builtin">:documentation</span> <span class="emacs-face-doc">"Generic component for showing server side
2aff8b5c 574 error conditions. Unlike ERROR-MESSAGE this component also
575 attempts to display a backtrace."</span>)
7404d4e1 576 (<span class="emacs-face-builtin">:metaclass</span> standard-component-class))
2aff8b5c 577</pre>
578
579
580<h5>message</h5>
581
582<p><a href="http://www.uncommon-web.com/darcsweb/darcsweb.cgi?r=ucw_dev;a=headblob;f=/src/components/message.lisp">src/components/message.lisp</a></p>
583
584<pre class="src">
7404d4e1 585(<span class="emacs-face-keyword">defclass</span> <span class="emacs-face-type">info-message</span> ()
586 ((message <span class="emacs-face-builtin">:initarg</span> <span class="emacs-face-builtin">:message</span> <span class="emacs-face-builtin">:accessor</span> message)
587 (ok-text <span class="emacs-face-builtin">:initarg</span> <span class="emacs-face-builtin">:ok-text</span> <span class="emacs-face-builtin">:accessor</span> ok-text <span class="emacs-face-builtin">:initform</span> <span class="emacs-face-string">"Ok."</span>))
4222507d 588 (<span class="emacs-face-builtin">:documentation</span> <span class="emacs-face-doc">"Component for showing a message to the user.
2aff8b5c 589
590If the OK-TEXT slot is non-NIL component will use that as the
591text for a link which, when clicked, causes the component to
592answer. It follows that if OK-TEXT is NIL this component will
593never answer."</span>)
7404d4e1 594 (<span class="emacs-face-builtin">:metaclass</span> standard-component-class))
2aff8b5c 595</pre>
596
597
598<h5>option-dialog</h5>
599
600<p><a href="http://www.uncommon-web.com/darcsweb/darcsweb.cgi?r=ucw_dev;a=headblob;f=/src/components/option-dialog.lisp">src/components/option-dialog.lisp</a></p>
601
602<pre class="src">
7404d4e1 603(<span class="emacs-face-keyword">defclass</span> <span class="emacs-face-type">option-dialog</span> (template-component)
2aff8b5c 604 ((message) (options) (confirm))
7404d4e1 605 (<span class="emacs-face-builtin">:default-initargs</span> <span class="emacs-face-builtin">:template-name</span> <span class="emacs-face-string">"ucw/option-dialog.tal"</span>)
4222507d 606 (<span class="emacs-face-builtin">:documentation</span> <span class="emacs-face-doc">"Component for querying the user.
2aff8b5c 607
608The value of the slot MESSAGE is used as a general heading.
609
610The OPTIONS slot must be an alist of (VALUE . LABEL). LABEL (a
611string) will be used as the text of a link which, when clikced,
612will answer VALUE.
613
614If the CONFIRM slot is T the user will be presented with a second
615OPTION-DIALOG asking the user if they are sure they want to
616submit that value."</span>)
7404d4e1 617 (<span class="emacs-face-builtin">:metaclass</span> standard-component-class))
2aff8b5c 618</pre>
619
620<p>A macro to present an option dialog is provided.</p>
621
622<pre class="src">
7404d4e1 623(<span class="emacs-face-keyword">defmacro</span> <span class="emacs-face-function-name">option-dialog</span> ((message-spec <span class="emacs-face-type">&amp;rest</span> message-args) <span class="emacs-face-type">&amp;body</span> options)
2aff8b5c 624 ...)
625</pre>
626
627<p><code>message-spec</code> is passed to <code>format</code> if <code>message-args</code> are supplied, and
628used as a string literal otherwise. This does not provide a way to set
629the confirm property which makes the macro not so generally useful.</p>
630
631
632
633<h4><a name="sec11" id="sec11"></a>
634Forms</h4>
635
636<p class="first">Reasonably useful forms library that integrates easily with TAL.</p>
637
638<p><a href="http://www.uncommon-web.com/darcsweb/darcsweb.cgi?r=ucw_dev;a=headblob;f=/src/components/form.lisp">src/components/form.lisp</a></p>
639
640<pre class="src">
7404d4e1 641(<span class="emacs-face-keyword">defclass</span> <span class="emacs-face-type">form-field</span> ()
4222507d 642 ((validators <span class="emacs-face-builtin">:documentation</span> <span class="emacs-face-doc">"List of validators which will be
2aff8b5c 643 applied to this field."</span>)
4222507d 644 (initially-validate <span class="emacs-face-builtin">:documentation</span> <span class="emacs-face-doc">"When non-NIL the
2aff8b5c 645 validators will be run as soon as the page
646 is rendered."</span>)))
647
7404d4e1 648(<span class="emacs-face-keyword">defgeneric</span> <span class="emacs-face-function-name">value</span> (form-field)
4222507d 649 (<span class="emacs-face-builtin">:documentation</span> <span class="emacs-face-doc">"The lispish translated value that represents the form-field."</span>))
7404d4e1 650
4222507d 651(<span class="emacs-face-keyword">defgeneric</span> (<span class="emacs-face-function-name">setf value</span>) (new-value form-field)
652 (<span class="emacs-face-builtin">:documentation</span> <span class="emacs-face-doc">"Set the value of a form-field with translation to client."</span>))
7404d4e1 653
654(<span class="emacs-face-keyword">defclass</span> <span class="emacs-face-type">generic-html-input</span> (form-field html-element)
655 ((client-value <span class="emacs-face-builtin">:accessor</span> client-value <span class="emacs-face-builtin">:initarg</span> <span class="emacs-face-builtin">:client-value</span>
656 <span class="emacs-face-builtin">:initform</span> <span class="emacs-face-string">""</span>
4222507d 657 <span class="emacs-face-builtin">:documentation</span> <span class="emacs-face-doc">"The string the client submitted along with this field."</span>)
7404d4e1 658 (name <span class="emacs-face-builtin">:accessor</span> name <span class="emacs-face-builtin">:initarg</span> <span class="emacs-face-builtin">:name</span> <span class="emacs-face-builtin">:initform</span> nil)
659 (accesskey <span class="emacs-face-builtin">:accessor</span> accesskey <span class="emacs-face-builtin">:initarg</span> <span class="emacs-face-builtin">:accesskey</span> <span class="emacs-face-builtin">:initform</span> nil)
660 (tooltip <span class="emacs-face-builtin">:accessor</span> tooltip <span class="emacs-face-builtin">:initarg</span> <span class="emacs-face-builtin">:tooltip</span> <span class="emacs-face-builtin">:initform</span> nil)
661 (tabindex <span class="emacs-face-builtin">:accessor</span> tabindex <span class="emacs-face-builtin">:initarg</span> <span class="emacs-face-builtin">:tabindex</span> <span class="emacs-face-builtin">:initform</span> nil))
662 (<span class="emacs-face-builtin">:default-initargs</span> <span class="emacs-face-builtin">:dom-id</span> (js:gen-js-name-string <span class="emacs-face-builtin">:prefix</span> <span class="emacs-face-string">"_ucw_"</span>)))
2aff8b5c 663</pre>
664
665<p>Fields are rendered into the extended <code>&lt;ucw:input</code> yaclml tag which
666supports a few fancy features. The <code>:accessor</code> for all form elements is
667set to <code>(client-value FIELD)</code>, and you should use <code>value</code> to access the
668Lisp value associated with it.</p>
669
670<pre class="src">
7404d4e1 671(deftag-macro &lt;ucw:input (<span class="emacs-face-type">&amp;attribute</span> accessor action reader writer name id (default nil)
672 <span class="emacs-face-type">&amp;allow-other-attributes</span> others)
673 <span class="emacs-face-string">"Generic INPUT tag replacement.
2aff8b5c 674
675If the ACCESSOR attribute is specified then it must be a PLACE
676and it's value will be used to fill the input, when the form is
677submitted it will be set to the new value.
678
679If ACTION is specefied then when the form is submitted via this
680input type=\"submit\" tag the form will be eval'd. when the
681submit (or image) is clicked. DEFAULT means that the ACTION
682provided for this input tag will be the default action of the
683form when pressing enter in a form field. If more then one, then
684the latest wins."</span>)
685</pre>
686
687<p>Validation of form fields are supported by adding to the validators
688list.</p>
689
690<pre class="src">
7404d4e1 691(<span class="emacs-face-keyword">defclass</span> <span class="emacs-face-type">validator</span> ()
692 ((message <span class="emacs-face-builtin">:accessor</span> message <span class="emacs-face-builtin">:initarg</span> <span class="emacs-face-builtin">:message</span> <span class="emacs-face-builtin">:initform</span> nil)))
2aff8b5c 693
7404d4e1 694(<span class="emacs-face-keyword">defgeneric</span> <span class="emacs-face-function-name">validate</span> (field validator)
4222507d 695 (<span class="emacs-face-builtin">:documentation</span> <span class="emacs-face-doc">"Validate a form-field with a validator."</span>))
2aff8b5c 696
7404d4e1 697(<span class="emacs-face-keyword">defgeneric</span> <span class="emacs-face-function-name">javascript-check</span> (field validator)
4222507d 698 (<span class="emacs-face-builtin">:documentation</span> <span class="emacs-face-doc">"Generate javascript code for checking FIELD against VALIDATOR.
2aff8b5c 699
700This is the convenience entry point to generate-javascript-check,
701methods defined on this generic funcition should return a list of
702javascript code (as per parenscript) which tests against the
703javascript variable value."</span>))
704
7404d4e1 705(<span class="emacs-face-keyword">defgeneric</span> <span class="emacs-face-function-name">javascript-invalid-handler</span> (field validator)
4222507d 706 (<span class="emacs-face-builtin">:documentation</span> <span class="emacs-face-doc">"The javascript code body for when a field is invalid."</span>))
2aff8b5c 707
7404d4e1 708(<span class="emacs-face-keyword">defgeneric</span> <span class="emacs-face-function-name">javascript-valid-handler</span> (field validator)
4222507d 709 (<span class="emacs-face-builtin">:documentation</span> <span class="emacs-face-doc">"Generate the javascript body for when a field is valid."</span>))
2aff8b5c 710</pre>
711
712<h5>Standard Form Fields</h5>
713
714<pre class="src">
7404d4e1 715(<span class="emacs-face-keyword">defclass</span> <span class="emacs-face-type">string-field</span> (generic-html-input)
2aff8b5c 716 ((input-size) (maxlength)))
717
7404d4e1 718(<span class="emacs-face-keyword">defclass</span> <span class="emacs-face-type">password-field</span> (string-field))
719(<span class="emacs-face-keyword">defclass</span> <span class="emacs-face-type">number-field</span> (string-field))
720(<span class="emacs-face-keyword">defclass</span> <span class="emacs-face-type">integer-field</span> (number-field))
2aff8b5c 721
7404d4e1 722(<span class="emacs-face-keyword">defclass</span> <span class="emacs-face-type">in-field-string-field</span> (string-field)
4222507d 723 ((in-field-label <span class="emacs-face-builtin">:documentation</span> <span class="emacs-face-doc">"This slot, if non-NIL, will be
2aff8b5c 724 used as an initial field label. An initial
725 field label is a block of text which is placed
726 inside the input element and removed as soon
727 as the user edits the field. Obviously this
728 field is overidden by an initial :client-value
729 argument."</span>)))
730
7404d4e1 731(<span class="emacs-face-keyword">defclass</span> <span class="emacs-face-type">textarea-field</span> (generic-html-input)
2aff8b5c 732 ((rows) (cols)))
733
7404d4e1 734(<span class="emacs-face-keyword">defclass</span> <span class="emacs-face-type">date-field</span> (form-field widget-component)
2aff8b5c 735 ((year) (month) (day)))
736
7404d4e1 737(<span class="emacs-face-keyword">defclass</span> <span class="emacs-face-type">dmy-date-field</span> (date-field)
4222507d 738 (<span class="emacs-face-builtin">:documentation</span> <span class="emacs-face-doc">"Date fields which orders the inputs day/month/year"</span>))
7404d4e1 739(<span class="emacs-face-keyword">defclass</span> <span class="emacs-face-type">mdy-date-field</span> (date-field))
2aff8b5c 740
7404d4e1 741(<span class="emacs-face-keyword">defclass</span> <span class="emacs-face-type">select-field</span> (generic-html-input)
4222507d 742 ((data-set <span class="emacs-face-builtin">:documentation</span> <span class="emacs-face-doc">"The values this select chooses
2aff8b5c 743 from."</span>))
4222507d 744 (<span class="emacs-face-builtin">:documentation</span> <span class="emacs-face-doc">"Form field used for selecting one value from a
2aff8b5c 745 list of available options."</span>))
746
7404d4e1 747(<span class="emacs-face-keyword">defgeneric</span> <span class="emacs-face-function-name">render-value</span> (select-field value)
4222507d 748 (<span class="emacs-face-builtin">:documentation</span> <span class="emacs-face-doc">"This function will be passed each value in the field's
2aff8b5c 749 data-set and must produce the body of the corresponding
750 &lt;ucw:option tag."</span>))
751
7404d4e1 752(<span class="emacs-face-keyword">defclass</span> <span class="emacs-face-type">mapping-select-field</span> (select-field)
4222507d 753 (<span class="emacs-face-builtin">:documentation</span> <span class="emacs-face-doc">"Class used when we want to chose the values of
2aff8b5c 754 a certain mapping based on the keys. We render the keys in the
755 select and return the corresponding value from the VALUE
756 method."</span>))
757
7404d4e1 758(<span class="emacs-face-keyword">defclass</span> <span class="emacs-face-type">hash-table-select-field</span> (mapping-select-field))
759(<span class="emacs-face-keyword">defclass</span> <span class="emacs-face-type">alist-select-field</span> (mapping-select-field))
760(<span class="emacs-face-keyword">defclass</span> <span class="emacs-face-type">plist-select-field</span> (mapping-select-field))
2aff8b5c 761
7404d4e1 762(<span class="emacs-face-keyword">defclass</span> <span class="emacs-face-type">radio-group</span> (generic-html-input)
2aff8b5c 763 ((value-widgets)))
764
7404d4e1 765(<span class="emacs-face-keyword">defclass</span> <span class="emacs-face-type">radio-button</span> (generic-html-input)
2aff8b5c 766 ((value)
4222507d 767 (group <span class="emacs-face-builtin">:documentation</span> <span class="emacs-face-doc">"The RADIO-GROUP this button is a part
2aff8b5c 768 of."</span>))
4222507d 769 (<span class="emacs-face-builtin">:documentation</span> <span class="emacs-face-doc">"A widget representing a single radio
2aff8b5c 770 button. Should be used in conjunction with a RADIO-GROUP."</span>))
771
7404d4e1 772(<span class="emacs-face-keyword">defmethod</span> <span class="emacs-face-function-name">add-value</span> ((group radio-group) value)
4222507d 773 <span class="emacs-face-doc">"Adds radio-button with value to group"</span>)
2aff8b5c 774
7404d4e1 775(<span class="emacs-face-keyword">defclass</span> <span class="emacs-face-type">checkbox-field</span> (generic-html-input))
776(<span class="emacs-face-keyword">defclass</span> <span class="emacs-face-type">file-upload-field</span> (generic-html-input))
777(<span class="emacs-face-keyword">defclass</span> <span class="emacs-face-type">submit-button</span> (generic-html-input)
2aff8b5c 778 ((label)))
779</pre>
780
781<h5>File Upload Field</h5>
782
783<p>Calling <code>value</code> on a <code>file-upload-field</code> returns a mime encoded body
784part. <code>(mime-part-body (value FIELD))</code> will return a <strong>binary stream</strong>
785attached to the contents of the file. The <code>Content-Type</code> header should
786be set to the MIME type of the file being uploaded.</p>
787
788<pre class="src">
7404d4e1 789(<span class="emacs-face-keyword">defgeneric</span> <span class="emacs-face-function-name">mime-part-headers</span> (mime-part)
4222507d 790 (<span class="emacs-face-builtin">:documentation</span> <span class="emacs-face-doc">"Returns an alist of the headers of MIME-PART.
2aff8b5c 791
792The alist must be of the form (NAME . VALUE) where both NAME and
793VALUE are strings."</span>))
794
7404d4e1 795(<span class="emacs-face-keyword">defgeneric</span> <span class="emacs-face-function-name">mime-part-body</span> (mime-part)
4222507d 796 (<span class="emacs-face-builtin">:documentation</span> <span class="emacs-face-doc">"Returns the body of MIME-PART."</span>))
2aff8b5c 797</pre>
798
799
800
801<h5>Standard Validators</h5>
802
803<pre class="src">
7404d4e1 804(<span class="emacs-face-keyword">defclass</span> <span class="emacs-face-type">not-empty-validator</span> (validator))
2aff8b5c 805
7404d4e1 806(<span class="emacs-face-keyword">defclass</span> <span class="emacs-face-type">value-validator</span> (validator)
4222507d 807 (<span class="emacs-face-builtin">:documentation</span> <span class="emacs-face-doc">"Validators that should only be applied if there is a value.
2aff8b5c 808That is, they always succeed on nil."</span>))
809
7404d4e1 810(<span class="emacs-face-keyword">defclass</span> <span class="emacs-face-type">length-validator</span> (value-validator)
811 ((min-length <span class="emacs-face-builtin">:accessor</span> min-length <span class="emacs-face-builtin">:initarg</span> <span class="emacs-face-builtin">:min-length</span>
812 <span class="emacs-face-builtin">:initform</span> nil)
813 (max-length <span class="emacs-face-builtin">:accessor</span> max-length <span class="emacs-face-builtin">:initarg</span> <span class="emacs-face-builtin">:max-length</span>
814 <span class="emacs-face-builtin">:initform</span> nil)))
2aff8b5c 815
7404d4e1 816(<span class="emacs-face-keyword">defclass</span> <span class="emacs-face-type">string=-validator</span> (validator)
817 ((other-field <span class="emacs-face-builtin">:accessor</span> other-field <span class="emacs-face-builtin">:initarg</span> <span class="emacs-face-builtin">:other-field</span>))
4222507d 818 (<span class="emacs-face-builtin">:documentation</span> <span class="emacs-face-doc">"Ensures that a field is string= to another one."</span>))
2aff8b5c 819
7404d4e1 820(<span class="emacs-face-keyword">defclass</span> <span class="emacs-face-type">regex-validator</span> (value-validator)
821 ((regex <span class="emacs-face-builtin">:accessor</span> regex <span class="emacs-face-builtin">:initarg</span> <span class="emacs-face-builtin">:regex</span> <span class="emacs-face-builtin">:initform</span> nil)))
2aff8b5c 822
7404d4e1 823(<span class="emacs-face-keyword">defclass</span> <span class="emacs-face-type">e-mail-address-validator</span> (regex-validator))
2aff8b5c 824
7404d4e1 825(<span class="emacs-face-keyword">defclass</span> <span class="emacs-face-type">phone-number-validator</span> (regex-validator))
2aff8b5c 826
7404d4e1 827(<span class="emacs-face-keyword">defclass</span> <span class="emacs-face-type">is-a-number-validator</span> (value-validator))
828(<span class="emacs-face-keyword">defclass</span> <span class="emacs-face-type">is-an-integer-validator</span> (is-a-number-validator))
2aff8b5c 829
7404d4e1 830(<span class="emacs-face-keyword">defclass</span> <span class="emacs-face-type">number-range-validator</span> (is-a-number-validator)
831 ((min-value <span class="emacs-face-builtin">:accessor</span> min-value <span class="emacs-face-builtin">:initarg</span> <span class="emacs-face-builtin">:min-value</span> <span class="emacs-face-builtin">:initform</span> nil)
832 (max-value <span class="emacs-face-builtin">:accessor</span> max-value <span class="emacs-face-builtin">:initarg</span> <span class="emacs-face-builtin">:max-value</span> <span class="emacs-face-builtin">:initform</span> nil)))
2aff8b5c 833</pre>
834
835
836<h5>Simple Form Helper</h5>
837
838<p>UCW provides a helper class for developing forms. Subclass and add the
839elements you wish to include in the form. A <code>:wrapping</code> method renders
840the form boilerplate and then calls your <code>render</code>.</p>
841
842<pre class="src">
843(defcomponent simple-form (html-element)
7404d4e1 844 ((submit-method <span class="emacs-face-builtin">:accessor</span> submit-method
845 <span class="emacs-face-builtin">:initform</span> <span class="emacs-face-string">"post"</span>
846 <span class="emacs-face-builtin">:initarg</span> <span class="emacs-face-builtin">:submit-method</span>)
847 (dom-id <span class="emacs-face-builtin">:accessor</span> dom-id
848 <span class="emacs-face-builtin">:initform</span> (js:gen-js-name-string <span class="emacs-face-builtin">:prefix</span> <span class="emacs-face-string">"_ucw_simple_form_"</span>)
849 <span class="emacs-face-builtin">:initarg</span> <span class="emacs-face-builtin">:dom-id</span>))
850 (<span class="emacs-face-builtin">:default-initargs</span> <span class="emacs-face-builtin">:dom-id</span> <span class="emacs-face-string">"ucw-simple-form"</span>))
2aff8b5c 851</pre>
852
853
854
855<h4><a name="sec12" id="sec12"></a>
856Templates</h4>
857
858<p><a href="http://www.uncommon-web.com/darcsweb/darcsweb.cgi?r=ucw_dev;a=headblob;f=/src/components/template.lisp">src/components/template.lisp</a></p>
859
860<p>Infrastructure for loading TAL templates as a view of a component.</p>
861
862<pre class="src">
7404d4e1 863(<span class="emacs-face-keyword">defclass</span> <span class="emacs-face-type">template-component</span> (component))
2aff8b5c 864(defcomponent simple-template-component (template-component)
7404d4e1 865 ((environment <span class="emacs-face-builtin">:initarg</span> <span class="emacs-face-builtin">:environment</span> <span class="emacs-face-builtin">:initform</span> nil)))
2aff8b5c 866
7404d4e1 867(<span class="emacs-face-keyword">defgeneric</span> <span class="emacs-face-function-name">template-component-environment</span> (component)
4222507d 868 (<span class="emacs-face-builtin">:documentation</span> <span class="emacs-face-doc">"Create the TAL environment for rendering COMPONENT's template.
2aff8b5c 869
870Methods defined on this generic function must return a TAL
871environment: a list of TAL binding sets (see the documentation
872for YACLML:MAKE-STANDARD-ENVIRONMENT for details on TAL
873environments.)"</span>)
7404d4e1 874 (<span class="emacs-face-builtin">:method-combination</span> nconc))
2aff8b5c 875
7404d4e1 876(<span class="emacs-face-keyword">defmethod</span> <span class="emacs-face-function-name">template-component-environment</span> nconc ((component template-component))
877 <span class="emacs-face-string">"Create the basic TAL environment.
2aff8b5c 878
879Binds the symbol ucw:component to the component object itself,
880also puts the object COMPONENT on the environment (after the
881binding of ucw:component) so that slots are, by default,
882visable."</span>
883 (make-standard-environment `((component . ,component)) component))
884
7404d4e1 885(<span class="emacs-face-keyword">defmethod</span> <span class="emacs-face-function-name">render</span> ((component template-component))
4222507d 886 <span class="emacs-face-doc">"Render a template based component.
2aff8b5c 887
888Calls the component's template. The name of the template is the
889value returned by the generic function
890template-component.template-name, the template will be rendered
891in the environment returned by the generic function
892template-component-environment."</span>
893 (render-template *context*
894 (template-component.template-name component)
895 (template-component-environment component)))
896
897</pre>
898
899<p>Subclass and override methods. <code>simple-template-component</code> only provides
900the ability to set environment variables in initarg. Subclass to
901provide automagic template file name generation and such.</p>
902
903
904<h4><a name="sec13" id="sec13"></a>
905Utility Mixin Components</h4>
906
907<h5>Range View</h5>
908
909<p><a href="http://www.uncommon-web.com/darcsweb/darcsweb.cgi?r=ucw_dev;a=headblob;f=/src/components/range-view.lisp">src/components/range-view.lisp</a></p>
910
911<pre class="src">
7404d4e1 912(<span class="emacs-face-keyword">defclass</span> <span class="emacs-face-type">range-view</span> (template-component)
913 (<span class="emacs-face-builtin">:default-initargs</span> <span class="emacs-face-builtin">:template-name</span> <span class="emacs-face-string">"ucw/range-view.tal"</span>)
4222507d 914 (<span class="emacs-face-builtin">:documentation</span> <span class="emacs-face-doc">"Component for showing the user a set of data one \"window\" at a time.
2aff8b5c 915
916The data set is presented one \"window\" at a time with links to
917the the first, previous, next and last window. Each window shows
918at most WINDOW-SIZE elements of the data. The data is passed to
919the range-view at instance creation time via the :DATA initarg.
920
921The generic function RENDER-RANGE-VIEW-ITEM is used to render
922each item of DATA.
923
924In order to change the rendering of the single elements of a
925range view developer's should create a sub class of RANGE-VIEW
926and define their RENDER-RANGE-VIEW-ITEM methods on that."</span>)
7404d4e1 927 (<span class="emacs-face-builtin">:metaclass</span> standard-component-class))
2aff8b5c 928</pre>
929
930<pre class="src">
7404d4e1 931(<span class="emacs-face-keyword">defgeneric</span> <span class="emacs-face-function-name">render-range-view-item</span> (range-view item)
4222507d 932 (<span class="emacs-face-builtin">:documentation</span> <span class="emacs-face-doc">"Render a single element of a range-view."</span>)
7404d4e1 933 (<span class="emacs-face-builtin">:method</span> ((range-view range-view) (item t))
934 <span class="emacs-face-string">"Standard implementation of RENDER-RANGE-VIEW-ITEM. Simply
2aff8b5c 935applies ITEM to princ (via &lt;:as-html)."</span>
7404d4e1 936 (<span class="emacs-face-keyword">declare</span> (ignore range-view))
2aff8b5c 937 (&lt;:as-html item)))
938</pre>
939
940
941<h5>Widget</h5>
942
943<p>Mixin with existing component to wrap in a div or span. This is handy
944for defining lightweight widgets embedded within other components.</p>
945
946<p><a href="http://www.uncommon-web.com/darcsweb/darcsweb.cgi?r=ucw_dev;a=headblob;f=/src/components/html-element.lisp">src/components/html-element.lisp</a></p>
947
948<pre class="src">
7404d4e1 949(<span class="emacs-face-keyword">defclass</span> <span class="emacs-face-type">html-element</span> (component)
2aff8b5c 950 ((css-class)
951 (dom-id)
952 (css-style)
953 (extra-tags)
954 (events))
4222507d 955 (<span class="emacs-face-builtin">:documentation</span> <span class="emacs-face-doc">"An HTML element.
2aff8b5c 956
957HTML elements control aspects that are relevant to almost all tags.
958
959Firstly they provide a place to store the class, id, and style of the
960component. The specific render methods of the components themselves
961must pass these values to whatever code is used to render the actual
962tag.
963
964Secondly, they allow javascript event handlers to be registered for a
965tag. The events slot can be filled with a list of lists in the form
966
967 (event parenscript-statement*)
968
969For example (\"onclick\" (alert \"You clicked!\") (return nil)). If
970the element has a dom-id, these event handlers are automatically
971added."</span>))
972</pre>
973
974<p><a href="http://www.uncommon-web.com/darcsweb/darcsweb.cgi?r=ucw_dev;a=headblob;f=/src/components/widget.lisp">src/components/widget.lisp</a></p>
975
976<pre class="src">
7404d4e1 977(<span class="emacs-face-keyword">defclass</span> <span class="emacs-face-type">widget-component</span> (html-element)
2aff8b5c 978 ()
4222507d 979 (<span class="emacs-face-builtin">:documentation</span> <span class="emacs-face-doc">"A widget which should be wrapped in a &lt;div&gt;."</span>))
2aff8b5c 980
7404d4e1 981(<span class="emacs-face-keyword">defclass</span> <span class="emacs-face-type">inline-widget-component</span> (html-element)
2aff8b5c 982 ()
4222507d 983 (<span class="emacs-face-builtin">:documentation</span> <span class="emacs-face-doc">"A widget which should be wrapped in &lt;span&gt; and not &lt;div&gt;"</span>))
2aff8b5c 984
7404d4e1 985(<span class="emacs-face-keyword">defmethod</span> <span class="emacs-face-function-name">render</span> <span class="emacs-face-builtin">:wrap-around</span> ((widget widget-component)))
986(<span class="emacs-face-keyword">defmethod</span> <span class="emacs-face-function-name">render</span> <span class="emacs-face-builtin">:wrap-around</span> ((widget inline-widget-component)))
2aff8b5c 987</pre>
988
989
990<h5>Transactions</h5>
991
992<p>A mixin to provide transactions. <code>(open-transaction component)</code> and
993<code>(close-transaction component)</code> open and closed nested
994transactions. After a transaction has been closed an attempt to
995backtrack into a step inside the transaction will result in jumping up
996one level of transactions (or out of the transaction entirely if at
997the top level). This ensures that the transaction is only run once,
998naturally.</p>
999
1000<p><a href="http://www.uncommon-web.com/darcsweb/darcsweb.cgi?r=ucw_dev;a=headblob;f=/src/components/transaction-mixin.lisp">src/components/transaction-mixin.lisp</a></p>
1001
1002<pre class="src">
1003(defcomponent transaction-mixin ()
1004 (...))
1005
1006(defmethod/cc open-transaction ((comp transaction-mixin)))
1007(defmethod/cc close-transaction ((comp transaction-mixin)))
1008</pre>
1009
1010
1011<h5>Task</h5>
1012
1013<p><code>(defaction start ...)</code> on subclass to run a series of actions bundled
1014into a task.</p>
1015
1016<p><a href="http://www.uncommon-web.com/darcsweb/darcsweb.cgi?r=ucw_dev;a=headblob;f=/src/components/task.lisp">src/components/task.lisp</a></p>
1017
1018<pre class="src">
7404d4e1 1019(<span class="emacs-face-keyword">defclass</span> <span class="emacs-face-type">task-component</span> (standard-component)
2aff8b5c 1020 (...)
4222507d 1021 (<span class="emacs-face-builtin">:documentation</span> <span class="emacs-face-doc">"A controller for a single task or operation to
2aff8b5c 1022 be performed by the user.
1023
1024 A task component's START action is called as soon as the
1025component is instantiated. Task components do not have their own
1026RENDER method, in fact they have no graphical representation but
1027serve only to order a sequence of other components."</span>))
1028
1029(defgeneric/cc start (task)
4222507d 1030 (<span class="emacs-face-builtin">:documentation</span> <span class="emacs-face-doc">"action which gets called automatically when
2aff8b5c 1031task-component is active. Use defaction to define your own
1032\"start\" action"</span>))
1033</pre>
1034
1035
1036<h5>Cached</h5>
1037
1038<p><a href="http://www.uncommon-web.com/darcsweb/darcsweb.cgi?r=ucw_dev;a=headblob;f=/src/components/cached.lisp">src/components/cached.lisp</a></p>
1039
1040<pre class="src">
1041(defcomponent cached-component ()
7404d4e1 1042 ((cached-output <span class="emacs-face-builtin">:accessor</span> cached-output <span class="emacs-face-builtin">:initform</span> nil
4222507d 1043 <span class="emacs-face-builtin">:documentation</span> <span class="emacs-face-doc">"A string holding the output to
2aff8b5c 1044 use for this component. This string will be
1045 written directly to the html stream and is
1046 changed by the REFRESH-COMPONENT-OUTPUT
1047 method."</span> )
7404d4e1 1048 (timeout <span class="emacs-face-builtin">:accessor</span> timeout <span class="emacs-face-builtin">:initarg</span> <span class="emacs-face-builtin">:timeout</span>
4222507d 1049 <span class="emacs-face-builtin">:documentation</span> <span class="emacs-face-doc">"An value specifying how often this
2aff8b5c 1050 component needs to be refreshed. The exact
1051 interpretation of the value depends on the type of
1052 caching used class."</span>))
4222507d 1053 (<span class="emacs-face-builtin">:documentation</span> <span class="emacs-face-doc">"Component which caches its output.
2aff8b5c 1054
1055The component caching API is built around the generic functions
1056COMPONENT-DIRTY-P and REFRESH-COMPONENT-OUTPUT and a method on
1057RENDER, see the respective docstrings for more details.
1058
1059Do not use CACHED-COMPONENT directly, use one its subclasses."</span>))
1060
7404d4e1 1061(<span class="emacs-face-keyword">defgeneric</span> <span class="emacs-face-function-name">component-dirty-p</span> (component)
4222507d 1062 (<span class="emacs-face-builtin">:documentation</span> <span class="emacs-face-doc">"Returns T is COMPONENT's cache is invalid."</span>))
2aff8b5c 1063
7404d4e1 1064(<span class="emacs-face-keyword">defgeneric</span> <span class="emacs-face-function-name">update-cache</span> (component)
4222507d 1065 (<span class="emacs-face-builtin">:documentation</span> <span class="emacs-face-doc">"Update COMPONENT's cache variables after a refresh."</span>))
2aff8b5c 1066
1067(defcomponent timeout-cache-component (cached-component)
7404d4e1 1068 ((last-refresh <span class="emacs-face-builtin">:accessor</span> last-refresh <span class="emacs-face-builtin">:initform</span> nil
4222507d 1069 <span class="emacs-face-builtin">:documentation</span> <span class="emacs-face-doc">"The time, exrpessed as a
2aff8b5c 1070 universal time, when the component was last rendered."</span>))
7404d4e1 1071 (<span class="emacs-face-builtin">:default-initargs</span>
1072 <span class="emacs-face-builtin">:timeout</span> (* 30 60 60))
4222507d 1073 (<span class="emacs-face-builtin">:documentation</span> <span class="emacs-face-doc">"Render the component at most every TIMEOUT seconds."</span>))
2aff8b5c 1074
1075(defcomponent num-hits-cache-component (cached-component)
7404d4e1 1076 ((hits-since-refresh <span class="emacs-face-builtin">:accessor</span> hits-since-refresh
1077 <span class="emacs-face-builtin">:initform</span> nil
4222507d 1078 <span class="emacs-face-builtin">:documentation</span> <span class="emacs-face-doc">"Number of views since last refresh."</span>))
7404d4e1 1079 (<span class="emacs-face-builtin">:default-initargs</span> <span class="emacs-face-builtin">:timeout</span> 10)
4222507d 1080 (<span class="emacs-face-builtin">:documentation</span> <span class="emacs-face-doc">"Render the component every TIMEOUT views."</span>))
2aff8b5c 1081</pre>
1082
1083<p>Subclass and override <code>component-dirty-p</code> to do something useful
1084(e.g. flip mark bit when object being presented changes).</p>
1085
1086
1087
1088
1089<h3><a name="sec14" id="sec14"></a>
1090Control Flow</h3>
1091
1092<p><a href="http://www.uncommon-web.com/darcsweb/darcsweb.cgi?r=ucw_dev;a=headblob;f=/src/rerl/standard-component/control-flow.lisp">src/rerl/standard-component/control-flow.lisp</a></p>
1093
1094<p><a href="http://www.uncommon-web.com/darcsweb/darcsweb.cgi?r=ucw_dev;a=headblob;f=/src/rerl/standard-action.lisp">src/rerl/standard-action.lisp</a></p>
1095
1096<h4><a name="sec15" id="sec15"></a>
1097Calling</h4>
1098
1099<p class="first">Most of what you do in UCW will be calling components so this is a bit
1100important. Note that calling interrupts the current control flow so if
1101you want to render a component in place as part of another component
1102just call <code>render</code> on it instead.</p>
1103
1104<pre class="src">
7404d4e1 1105(<span class="emacs-face-keyword">defmacro</span> <span class="emacs-face-function-name">call</span> (component-type <span class="emacs-face-type">&amp;rest</span> component-init-args)
1106 <span class="emacs-face-doc">"Stop the execution of the current action and pass control to
2aff8b5c 1107a freshly created component of type COMPONENT-TYPE.
1108
1109COMPONENT-INIT-ARGS are passed directly to the underlying
1110make-instance call. This form will return if and when the call'd
1111component calls answer, the value returned by this form is
1112whatever the call'd component passed to answer.
1113
1114Notes:
1115
1116This macro assumes that the lexcial variable UCW:SELF is bound to
1117the calling component."</span>)
1118
4222507d 1119(answer VAL) <span class="emacs-face-comment">; answer parent component ONLY IN ACTIONS
2aff8b5c 1120</span>
4222507d 1121(ok SELF VAL) <span class="emacs-face-comment">; Used to answer a component anywhere and what answer
1122</span> <span class="emacs-face-comment">; expands into
2aff8b5c 1123</span>
4222507d 1124(jump COMPONENT-NAME <span class="emacs-face-type">&amp;REST</span> ARGS) <span class="emacs-face-comment">; is similar to call, but replaces
1125</span> <span class="emacs-face-comment">; the current component with the new
1126</span> <span class="emacs-face-comment">; one and drops any backtracks (back
1127</span> <span class="emacs-face-comment">; button will no longer work)
2aff8b5c 1128</span></pre>
1129
1130<p><code>(call COMPONENT-NAME &amp;ARGS INIT-ARGS)</code> calls <code>COMPONENT-NAME</code> and returns
1131the value returned by <code>(ok SELF RETURN-VALUE)</code> called from within
1132<code>COMPONENT-NAME</code></p>
1133
1134
1135<h4><a name="sec16" id="sec16"></a>
1136Actions</h4>
1137
1138<p class="first">Actions are methods on components. The first argument <strong>must</strong> be a
1139component for most of UCW to work.</p>
1140
1141<pre class="src">
1142(defaction NAME (first ...) ...)
4222507d 1143 <span class="emacs-face-comment">; (roughly) expands into
2aff8b5c 1144</span>(defmethod/cc NAME (first ...)
7404d4e1 1145 (<span class="emacs-face-keyword">let</span> ((self first))
2aff8b5c 1146 ...))
1147</pre>
1148
1149<p><code>Self</code> being bound in the current lexical environment is required for
1150most UCW control flow things to work. <code>defaction</code> hides this from you,
1151and was a big source of confusion for me early on (mostly &quot;hmm, why is
1152this not working ... where did that come from in the
1153macroexpansion!&quot;).</p>
1154
1155
1156<h4><a name="sec17" id="sec17"></a>
1157Entry Points</h4>
1158
1159<pre class="src">
7404d4e1 1160(defentry-point url (<span class="emacs-face-builtin">:application</span> APPLICATION
1161 <span class="emacs-face-builtin">:class</span> DISPATCHER-CLASS)
4222507d 1162 (PARAM1 ... PARAMN) <span class="emacs-face-comment">; GET / POST vars, bound in body
2aff8b5c 1163</span> body)
1164</pre>
1165
1166<p>An entry point is what it sounds like: a static URL matched using the
1167mater of <code>DISPATCHER-CLASS</code> that enters into <code>APPLICATION</code> running the
1168code in <code>body</code>. An example from a test program I have written
1169follows. The entry point allows files to be streamed to user when the
1170url audio.ucw?file=FOO is used.</p>
1171
1172<pre class="src">
7404d4e1 1173(defentry-point <span class="emacs-face-string">"^(audio.ucw|)$"</span> (<span class="emacs-face-builtin">:application</span> *golf-test-app*
1174 <span class="emacs-face-builtin">:class</span> regexp-dispatcher)
2aff8b5c 1175 (file)
1176 (call 'audio-file-window
7404d4e1 1177 <span class="emacs-face-builtin">:audio-file</span> (make-instance 'audio-file
1178 <span class="emacs-face-builtin">:type</span> <span class="emacs-face-builtin">:vorbis</span>
1179 <span class="emacs-face-builtin">:data</span> (file-&gt;bytes (open
2aff8b5c 1180 file
7404d4e1 1181 <span class="emacs-face-builtin">:element-type</span> 'unsigned-byte)))))
2aff8b5c 1182</pre>
1183
1184
1185
1186<h3><a name="sec18" id="sec18"></a>
1187Dispatching</h3>
1188
1189<p><a href="http://www.uncommon-web.com/darcsweb/darcsweb.cgi?r=ucw_dev;a=headblob;f=/src/rerl/standard-dispatcher.lisp">src/rerl/standard-dispatcher.lisp</a></p>
1190
1191<pre class="src">
7404d4e1 1192(<span class="emacs-face-keyword">defgeneric</span> <span class="emacs-face-function-name">matcher-match</span> (matcher application context)
4222507d 1193 (<span class="emacs-face-builtin">:documentation</span> <span class="emacs-face-doc">"Abstract method for subclasses to implement a
2aff8b5c 1194matcher. This method would return multiple-values according to
1195matcher internal nature.
1196
1197No methods defined on this function may rebind *context*, nor
1198change CONTEXT's application. Only if the method matches the
1199request, it is allowed to modify CONTEXT or APPLICATION, even in
1200that case methods defined on this function must not modify
1201CONTEXT's application nor rebind *context*."</span>))
1202
7404d4e1 1203(<span class="emacs-face-keyword">defgeneric</span> <span class="emacs-face-function-name">handler-handle</span> (handler application context matcher-result)
4222507d 1204 (<span class="emacs-face-builtin">:documentation</span> <span class="emacs-face-doc">"Abstract function for handler classes to
2aff8b5c 1205implement in order to handle a request matched by relevant
1206matcher.
1207
1208These methods may modify context as they wish since they'r
1209matched, request will be closed after this method is run."</span>))
1210
7404d4e1 1211(<span class="emacs-face-keyword">defgeneric</span> <span class="emacs-face-function-name">dispatch</span> (dispatcher application context)
4222507d 1212 (<span class="emacs-face-builtin">:documentation</span> <span class="emacs-face-doc">"Entry point into a dispatcher. Must return T
2aff8b5c 1213 if the context has been handled or NIL if it hasn't.
1214
1215No methods defined on this function may rebind *context*, nor
1216change CONTEXT's application. Only if the method returns T is it
1217allowed to modify CONTEXT or APPLICATION, even in that case
1218methods defined on this function must not modify CONTEXT's
1219application nor rebind *context*."</span>))
1220</pre>
1221
1222<pre class="src">
7404d4e1 1223(<span class="emacs-face-keyword">defclass</span> <span class="emacs-face-type">my-matcher</span> (abstract-matcher) ...)
1224(<span class="emacs-face-keyword">defclass</span> <span class="emacs-face-type">my-handler</span> (abstract-handler) ...)
1225(<span class="emacs-face-keyword">defclass</span> <span class="emacs-face-type">my-dispatcher</span> (abstract-dispatcher my-matcher my-handler)
2aff8b5c 1226 ...)
1227</pre>
1228
1229<h4><a name="sec19" id="sec19"></a>
1230Simple Dispatcher</h4>
1231
1232<pre class="src">
4222507d 1233(<span class="emacs-face-builtin">:documentation</span> <span class="emacs-face-doc">"This class of dispatchers avoids all of UCW's
2aff8b5c 1234 standard call/cc (and therefore frame/backtracking/component)
1235 mechanism.
1236
1237Unlike all other UCW dispatchers a simple-dispatcher must not use
1238CALL, and must perform the rendering directly within the handler."</span>)
1239</pre>
1240
1241
1242
1243<h3><a name="sec20" id="sec20"></a>
1244Server</h3>
1245
1246<p><a href="http://www.uncommon-web.com/darcsweb/darcsweb.cgi?r=ucw_dev;a=headblob;f=/src/control.lisp">src/control.lisp</a></p>
1247
1248<pre class="src">
7404d4e1 1249(<span class="emacs-face-keyword">defun</span> <span class="emacs-face-function-name">create-server</span> (<span class="emacs-face-type">&amp;key</span>
1250 (backend `(,*ucw-backend-type* <span class="emacs-face-builtin">:host</span> ,*ucw-backend-host*
1251 <span class="emacs-face-builtin">:port</span> ,*ucw-backend-port*))
2aff8b5c 1252 (applications *ucw-applications*)
1253 (start-p t)
1254 (server-class *ucw-server-class*)
1255 (log-root-directory (truename *ucw-log-root-directory*))
1256 (log-level *ucw-log-level*))
7404d4e1 1257 <span class="emacs-face-doc">"Creates and returns a UCW server according to SERVER-CLASS, HOST and
2aff8b5c 1258PORT. Affects *DEFAULT-SERVER*.
1259
1260BACKEND is a list of (BACKEND-TYPE &amp;rest INITARGS). BACKEND-TYPE
1261may be :HTTPD, :MOD-LISP, :ASERVE, :ARANEIDA, an existing
1262backend, an existing UCW server backend or :DEFAULT in which case
1263it attempts to return a sane default from the UCW backends loaded
1264and available, or any other value for which a valid MAKE-BACKEND
1265method has been defined. INITARGS will be passed, unmodified, to
1266MAKE-BACKEND.
1267
1268APPLICATIONS is a list of defined applications to be loaded into the
1269server.
1270
1271Logs are generated in verbosity defined by LOG-LEVEL and directed to
1272LOG-ROOT-DIRECTORY if defined."</span>
1273 ...
4222507d 1274 server) <span class="emacs-face-comment">; return server, naturally
2aff8b5c 1275</span></pre>
1276
1277
1278<h3><a name="sec21" id="sec21"></a>
1279Debugging</h3>
1280
1281<h4><a name="sec22" id="sec22"></a>
1282Inspector</h4>
1283
1284<p><a href="/home/clinton/src/ucw/darcs/ucw_dev/src/components/ucw-inspector.lisp">/home/clinton/src/ucw/darcs/ucw_dev/src/components/ucw-inspector.lisp</a></p>
1285
1286<pre class="src">
1287(defaction call-inspector ((component component) datum)
7404d4e1 1288 <span class="emacs-face-string">"Call an inspector for DATUM on the component COMPONENT."</span>
1289 (call 'ucw-inspector <span class="emacs-face-builtin">:datum</span> datum))
2aff8b5c 1290</pre>
1291
1292
1293
1294
1295<h2><a name="sec23" id="sec23"></a>
1296Tips</h2>
1297
1298<h3><a name="sec24" id="sec24"></a>
1299Getting dojo to load</h3>
1300
1301<p class="first">I had some trouble getting dojo to work properly with UCW. The way
1302that the <code>:www-roots</code> option for an application works is a bit
1303confusing, and it is unforgiving if you mess the pathname up. A
1304directory <strong>must</strong> have a <code>/</code> at the end, and the directory you are serving
1305must also have the <code>/</code> (which is counterintuitive given the behavior of
1306most unix things that don't want the <code>/</code> at the end of the name).</p>
1307
1308<pre class="src">
7404d4e1 1309<span class="emacs-face-builtin">:www-roots</span> (list '(<span class="emacs-face-string">"dojo/"</span> .
1310 #P<span class="emacs-face-string">"/home/clinton/src/ucw/darcs/ucw_dev/wwwroot/dojo/"</span>))
2aff8b5c 1311</pre>
1312
1313
1314<h3><a name="sec25" id="sec25"></a>
1315Specials Bound During Rendering</h3>
1316
1317<p class="first">The current request context is bound to <code>ucw:*context*</code>, and the current
1318component is bound to <code>ucw:*current-component*</code> in the dynamic extent of
1319<code>render</code>.</p>
1320
1321
1322<h3><a name="sec26" id="sec26"></a>
1323Printing to the yaclml stream</h3>
1324
1325<p class="first">Occasionally it can be useful to do something like write a byte array
1326as an ascii string to the client. Inside of <code>render</code> the variable
1327<code>yaclml:*yaclml-stream*</code> is bound to the stream that you can write to if
1328you wish to have content interspersed with yaclml tags.</p>
1329
1330
1331
1332 <!-- Page published by Emacs Muse ends here -->
1333
1334 <p class="cke-buttons">
1335 <!-- validating badges, any browser, etc -->
98266870
CE
1336 <a href="https://validator.w3.org/check/referer"><img
1337 src="https://www.w3.org/Icons/valid-xhtml10"
2aff8b5c 1338 alt="Valid XHTML 1.0!" /></a>
1339
98266870 1340 <a href="https://www.anybrowser.org/campaign/"><img
2aff8b5c 1341 src="img/buttons/w3c_ab.png" alt="[ Viewable With Any Browser
1342 ]" /></a>
1343
98266870 1344 <a href="https://www.debian.org/"><img
2aff8b5c 1345 src="img/buttons/debian.png" alt="[ Powered by Debian ]" /></a>
1346
98266870 1347 <a href="https://hcoop.net/">
2aff8b5c 1348 <img src="img/buttons/hcoop.png"
1349 alt="[ Hosted by HCoop]" />
1350 </a>
1351
98266870 1352 <a href="https://www.fsf.org/register_form?referrer=114">
2aff8b5c 1353 <img src="img/buttons/fsf_member.png"
1354 alt="[ FSF Associate Member ]" />
1355 </a>
1356 </p>
1357
11f9bd69 1358<p class="cke-footer">If nothing in the world can change our children will inherit nothing
2aff8b5c 1359</p>
1360<p class="cke-timestamp">Last Modified:
f6d19803 1361 January 21, 2013</p>
2aff8b5c 1362 </body>
1363</html>