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