source: project/release/4/awful/trunk/awful.wiki @ 18540

Last change on this file since 18540 was 18540, checked in by Mario Domenech Goulart, 11 years ago

awful (trunk): added awful.wiki to document trunk changes.

File size: 47.9 KB
Line 
1== Awful
2
3[[toc:]]
4
5=== Description
6
7awful provides an application and an extension to ease the development of web-based applications.
8
9Here's a short summary of awful features:
10
11* Straightforward interface to databases (currently supported are postgresql and sqlite3)
12* Page dispatching via regular expressions
13* Easy access to query string and body request variables from HTTP requests
14* Ajax support via JQuery
15* Reasonably flexible (several configuration parameters)
16* Compiled pages made easy
17* Session inspector
18* Web REPL
19
20[[http://chicken.wiki.br/video/awful.ogv|Here's]] a 35 seconds video ([[http://en.wikipedia.org/wiki/Ogv|OGV]]) showing the deployment of awful and a "hello, world" example ([[http://chicken.wiki.br/video/awful.avi|here's]] the same video, but in [[http://en.wikipedia.org/wiki/Audio_Video_Interleave|AVI]]).
21
22
23=== Author
24
25[[http://chicken.wiki.br/users/mario-domenech-goulart|Mario Domenech Goulart]]
26
27
28=== Requirements
29
30The following eggs are required:
31
32* [[http://chicken.wiki.br/eggref/4/spiffy|spiffy]]
33* [[http://chicken.wiki.br/eggref/4/spiffy-request-vars|spiffy-request-vars]]
34* [[http://chicken.wiki.br/eggref/4/html-tags|html-tags]]
35* [[http://chicken.wiki.br/eggref/4/html-utils|html-utils]]
36* [[http://chicken.wiki.br/eggref/4/http-session|http-session]] (>= 2.0)
37
38=== Components
39
40awful is composed by two parts: an application, which can be thought as a web server; and an extension, which provides most of the supported features.
41
42=== A "Hello, world!" example
43
44Here's a "Hello, world!" example to be run by awful (hello-world.scm).
45
46<enscript highlight=scheme>
47(use awful)
48
49(define-page (main-page-path)
50  (lambda ()
51    "Hello, world!"))
52</enscript>
53
54To run this example, execute:
55
56  $ awful hello-world.scm
57
58Then access localhost:8080 using your favourite web browser.
59
60Without any configuration, awful listens on port 8080.  Since awful uses Spiffy behind the scenes, you can configure the web server parameters using Spiffy's.
61
62{{define-page}} is the primitive procedure to define pages.  In the simplest case, it takes as arguments a path to the page and a procedure to generate the page contents. The path to the page you use as the first argument is the same to be used as the path part of the URL you use to access the page.
63
64In the example we use the {{main-page-path}} parameter, which is one of the awful configuration parameters.  The default is {{"/main"}}.  So, when you access {{http://localhost:8080}} awful will take you to {{http://localhost:8080/main}}.
65
66If you look at the page source code, you'll see that awful created an HTML page for you.  Awful uses the [[http://chicken.wiki.br/eggref/4/html-utils|html-tags]]'s {{html-page}} procedure behind the scenes.  You can customize the page either by passing {{html-page}}'s keyword parameters to {{define-page}} or by setting the {{page-template}} parameter with your favourite procedure to generate pages (a one argument procedure which receives the page contents and returns a string representing the formatted contents). {{define-page}} would still pass the {{html-page}} keyword parameters, so you can make use of them.
67
68You can also use some global page-related parameters if all pages use the same CSS, doctype and charset ({{page-css}}, {{page-doctype}} and {{page-charset}}, respectively).
69
70
71An alternative way to write Awful '''scripts''' is by using the {{#!/path/to/awful}} shebang line.  Example:
72
73<enscript highlight=scheme>
74#! /usr/bin/awful
75
76(use awful)
77
78(define-page (main-page-path)
79  (lambda ()
80    "Hello, world!"))
81</enscript>
82
83Then you just need to run your script (assuming the file has execution permissions):
84
85  $ ./hello-world.scm
86
87
88=== Accessing request variables
89
90Awful provides a procedure ({{$}}) to access variables from the request, both from the query string (GET method) and from the request body (e.g., POST method).
91
92Here's a modified "Hello, world!" example to greet some person instead of the whole world:
93
94<enscript highlight=scheme>
95(use awful)
96
97(define-page (main-page-path)
98  (lambda ()
99    (++ "Hello, " ($ 'person "world") "!")))
100</enscript>
101
102The {{++}} procedure is an alias to {{string-append}} (name inspired by Haskell's operator to concatenate strings).
103
104So, restart the web server to reload the code, then access the main page using an argument, represented by the {{person}} query string variable: {{http://localhost:8080/main?person=Mario}}. You'll see a page showing {{Hello, Mario!}}.
105
106
107=== Re-evaluating the code by reloading the page
108
109When we upgraded our "Hello, world!" example to the improved one which can use an argument passed through the URL, we needed to modify the code and restart the web server to reload the application code.  Awful provides a way to reload the code via URL without restarting the server.  To do that, we can define a special page whose handler just reloads the code:
110
111<enscript highlight=scheme>
112(define-page "/reload"
113  (lambda ()
114    (load-apps (awful-apps))
115    "Reloaded"))
116</enscript>
117
118and restart the awful server.  Now, whenever you want to reload the application code, access {{http://localhost:8080/reload}}.
119
120You can control which IP numbers can access the reload page by using the {{page-access-control}} parameter.  For example, allowing only the localhost to reload the apps:
121
122<enscript highlight=scheme>
123(page-access-control
124 (lambda (path)
125   (if (equal? path "/reload")
126       (member (remote-address) '("127.0.0.1"))
127       #t)))
128</enscript>
129
130
131=== Using ajax
132
133Awful provides a way to (hopefully) make the use of ajax straightforward for web applications.
134
135By default, the ajax support is disabled, but it can be easily enabled by setting the {{enable-ajax}} parameter to {{#t}}.  When you enable ajax, all the pages defined via {{define-page}} will be linked to the JQuery javascript library. The URL of the JQuery file can be customized by setting the {{ajax-library}} parameter (the default is Google's API JQuery file version 1.4.2).
136
137When you have ajax enabled and you want to disable it for specific pages, you can pass {{#f}} as the value for the {{define-page}} keyword parameter {{no-ajax}}.
138
139So, if we now change our code to
140
141<enscript highlight=scheme>
142(use awful)
143
144(enable-ajax #t)
145
146(define-page (main-page-path)
147  (lambda ()
148    (++ "Hello, " ($ 'person "world") "!")))
149</enscript>
150
151and reload the application, we'll have our page linked to JQuery.
152
153Awful provides some procedures to do ajax.  We start by the more generic one ({{ajax}}) to reply the page greetings when we click "Hello, <person>!".
154
155<enscript highlight=scheme>
156(use awful html-tags)
157
158(enable-ajax #t)
159
160(define-page (main-page-path)
161  (lambda ()
162    (ajax "greetings" 'greetings 'click
163          (lambda ()
164            (<b> "Hello, awful!"))
165          target: "greetings-reply")
166    (++ (<a> href: "#"
167             id: "greetings"
168             (++ "Hello, " ($ 'person "world") "!"))
169        (<div> id: "greetings-reply"))))
170</enscript>
171
172The {{ajax}} procedure uses at least four arguments:
173
1741. The URL path to the server-side handler (a string).  This path is relative to {{ajax-namespace}} parameter (default is {{ajax}}.  So, in the example, we'll have "/ajax/greetings" as the ajax path to be generated if we pass "ajax" as the first argument.
175
1762. The ID of the DOM element to observe.
177
1783. The event to be handled
179
1804. The procedure to be run on the server-side.
181
182So, in the example, {{ajax}} will bind the fourth argument (the procedure) to the first argument (the path) on the server side. Then it will add javascript code to the page in order to wait for click events for the element of ID {{greetings}}.  When we click "Hello, <person>!", we'll get "Hello, awful!" printed on the page as reply.  {{ajax}} updates the DOM element whose id is the value of the {{target}} keyword parameter ({{"greetings-reply"}}, in the example).
183
184For the very specific case of creating links that execute server side code when clicked, awful provides the {{ajax-link}} procedure.  So our example could be coded like:
185
186<enscript highlight=scheme>
187(use awful)
188
189(enable-ajax #t)
190
191(define-page (main-page-path)
192  (lambda ()
193    (++ (ajax-link "greetings" 'greetings
194                   (lambda ()
195                     (<b> "Hello, awful!"))
196                   target: "greetings-reply")
197        (<div> id: "greetings-reply"))))
198</enscript>
199
200
201
202=== Adding arbitrary javascript code to pages
203
204Awful provides a procedure which can be used to add arbitrary javascript code to the page. It's called {{add-javascript}}.  Here's an example using javascript's {{alert}} and our "Hello, world!" example:
205
206<enscript highlight=scheme>
207(use awful)
208
209(enable-ajax #t)
210
211(define-page (main-page-path)
212  (lambda ()
213    (add-javascript "alert('Hello!');")
214    (++ (ajax-link "greetings" 'greetings
215                   (lambda ()
216                     (<b> "Hello, awful!"))
217                   target: "greetings-reply")
218        (<div> id: "greetings-reply"))))
219</enscript>
220
221
222
223=== Database access
224
225To access databases, you need some of the awful eggs which provide database access.  Currently, these are the possible options:
226
227* [[http://chicken.wiki.br/eggref/4/awful-postgresql|awful-postgresql]] (for Postgresql databases, using the [[http://chicken.wiki.br/eggref/4/postgresql|postgresql]] egg)
228
229* [[http://chicken.wiki.br/eggref/4/awful-sqlite3|awful-sqlite3]] (for Sqlite3 databases, using the [[http://chicken.wiki.br/eggref/4/sqlite3|sqlite3]] egg)
230* [[http://chicken.wiki.br/eggref/4/awful-sql-de-lite|awful-sql-de-lite]] (for Sqlite3 databases, using the [[http://chicken.wiki.br/eggref/4/sql-de-lite|sql-de-lite]] egg)
231
232As with ajax, database access is not enabled by default.  To enable it, you need to pick one the awful database support eggs and call the {{enable-db}} procedure.  Since version 0.10, and differently from the {{enable-*}} parameters, {{enable-db}} is a zero-argument procedure provided by each of awful database-support eggs.  So, if you use {{awful-postgresql}}, the {{enable-db}} procedure will automatically set up awful to use a postgresql database.
233
234Additionally, to access the db, you need to provide the credentials.  You can provide the credentials by setting the {{db-credentials}} parameter.  See the documentation for the eggs corresponding to the database type you are using ([[http://chicken.wiki.br/eggref/4/postgresql|postgresql]] for Postgresql and [[http://chicken.wiki.br/eggref/4/sqlite3|sqlite3]] or [[http://chicken.wiki.br/eggref/4/sql-de-lite|sql-de-lite]] for Sqlite3.)
235
236To actually query the database, there's the {{$db}} procedure, which uses as arguments a string representing the query and, optionally, a default value (a keyword parameter) to be used in case the query doesn't return any result. {{$db}} returns a list of lists. Below is an usage example:
237
238<enscript highlight=scheme>
239(use awful awful-postgresql)
240
241(enable-db)
242(db-credentials '((dbname . "my-db")
243                  (user . "mario")
244                  (password . "secret")
245                  (host . "localhost")))
246
247(define-page "db-example"
248  (lambda ()
249    (with-output-to-string
250      (lambda ()
251        (pp ($db "select full_name, phone from users"))))))
252</enscript>
253
254''Hint'': for Sqlite3 databases, {{db-credentials}} should be the path to the database file.
255
256There's also the {{$db-row-obj}} procedure for when you want to access the results of a query by row name.  {{$db-row-obj}} returns a procedure of two arguments: the name of the field and, optionally, a default value to be used in case the field value is {{#f}}.
257
258<enscript highlight=scheme>
259(define-page "db-example"
260  (lambda ()
261    (let ((& ($db-row-obj "select full_name, phone from users where user_id=1")))
262      (<p> "Full name: " (& 'full_name))
263      (<p> "Phone: " (& 'phone)))))
264</enscript>
265
266''Warning'': currently {{$db-row-obj}} is only implemented for Postgresql.
267
268If you need more flexibility to query the database, you can always use the {{(db-connection}}) parameter to get the database connection object and use it with the procedures available from the your favorite database egg API.
269
270
271=== Login pages and session
272
273Awful provides a very basic (awful?) support for creating authentication pages.
274
275The basic things you have to do is:
276
2771. Enable the use of sessions:
278
279<enscript highlight=scheme>
280(enable-session #t)
281</enscript>
282
2832. Set the password validation parameter.  This parameter is a two argument procedure (user and password) which returns a value (usually {{#t}} or {{#f}}) indicating whether the password is valid for the given user.  The default is a password which returns {{#f}}.  Let's set it to a procedure which returns {{#t}} is the user and the password are the same:
284
285<enscript highlight=scheme>
286(valid-password?
287  (lambda (user password)
288    (equal? user password)))
289</enscript>
290
2913. Define a login trampoline, which is an intermediate page accessed when redirecting from the login page to the main page.
292
293<enscript highlight=scheme>
294(define-login-trampoline "/login-trampoline")
295</enscript>
296
2974. Create a login page.  Awful provides a simple user/password login form ({{login-form}}), which we are going to use.  Here's our full example so far (using the basic "Hello, world!" as main page).
298
299<enscript highlight=scheme>
300(use awful)
301
302(enable-session #t)
303
304(define-login-trampoline "/login-trampoline")
305
306(valid-password?
307  (lambda (user password)
308    (equal? user password)))
309
310(define-page (main-page-path)
311  (lambda ()
312    "Hello world!"))
313
314(define-page (login-page-path)
315  (lambda ()
316    (login-form))
317  no-session: #t)
318</enscript>
319
320That's the very basic we need to set an auth page.  If the password is valid for the given user, awful will perform a redirect to the main page ({{main-page-path}} parameter) passing the {{user}} variable and its value in the query string .  If the password is not valid, awful will redirect to the login page ({{login-page-path}} parameter)) and pass the following variables and values:
321
322; {{reason}} : the reason why awful redirected to the login page. It may be {{invalid-password}}, for when the password is invalid for the given user; or {{invalid-session}} for when the session identifier is not valid (e.g., the session expired).
323
324; {{attempted-page}} : the URL path to page the user tried to access, but couldn't because either he/she was not loged in or he/she provided an invalid session identifier.
325
326; {{user}} : the user used for the form user field.
327
328Now we're gonna change our main page to store the user in the session and retrieve it to make the greetings message:
329
330<enscript highlight=scheme>
331(define-page (main-page-path)
332  (lambda ()
333    ($session-set! 'user ($ 'user))
334    (++ "Hello " ($session 'user "world") "!")))
335</enscript>
336
337Here we can see the two procedures to access the session: {{$session}} and {{$session-set!}}.
338
339{{$session-set!}} accepts two arguments: the first one is the name of the session variable and the second one is its value.
340
341{{$session}} takes the name of the session variable as argument and returns its session value.  We can optionally use a second argument to specify a default value, in case the session variable is not bound or is {{#f}}.
342
343
344=== Session inspector
345
346Awful provides a session inspector, so we can easily see the session contents for a given session identifier.  By default, the session inspector is disabled.  We can enabled it using the {{enable-session-inspector}} procedure, passing the session inspector URL path as argument:
347
348<enscript highlight=scheme>
349(enable-session-inspector "session-inspector")
350</enscript>
351
352Now, if you log in and try to access {{http://localhost:8080/session-inspector?sid=<paste the sid value here>}}, you'll get ... an access denied page.
353
354Awful provides a way to control access to the session inspector ({{session-inspector-access-control}} parameter).  The {{session-inspector-access-control}} parameter is an one-argument procedure which returns {{#f}} or some other value to indicate whether the access to the session inspector is allowed or not. By default, it blocks all access.  Let's configure it so we can access the session inspector from the local machine (whose IP number is 127.0.0.1):
355
356<enscript highlight=scheme>
357(session-inspector-access-control
358 (lambda ()
359   (member (remote-address) '("127.0.0.1"))))
360</enscript>
361
362Regarding to the access denied message, you can customize it by setting the {{session-inspector-access-denied-message}}.
363
364Now we can access {{http://localhost:8080/session-inspector?sid=<paste the sid value here>}} and see the session contents.
365
366
367=== Web REPL
368
369For further run-time, server-side web hacking, awful provides a REPL that you can use via web browser.  The activation and control access are basically the same as for the session inspector.  The relevant procedure and parameters are:
370
371* {{enable-web-repl}}
372* {{web-repl-access-control}}
373* {{web-repl-access-denied-message}}
374
375
376=== Pages access control
377
378To allow/deny access to pages, you can use the {{page-access-control}} parameter.  It's an one-argument procedure (the page path) which can be set to determine if the access to the page is allowed or not.
379
380The example bellow shows a very silly access control to the main page: it only allows the access when the value of the request variable {{user}} is {{"mario"}}:
381
382<enscript highlight=scheme>
383(use awful)
384
385(enable-session #t)
386
387(define-login-trampoline "/login-trampoline")
388
389(valid-password?
390 (lambda (user password)
391   (equal? user password)))
392
393(page-access-control
394 (lambda (path)
395   (or (member path `(,(login-page-path) "/login-trampoline")) ;; allow access to login-related pages
396       (and (equal? ($ 'user) "mario")
397            (equal? path (main-page-path))))))
398
399(define-page (main-page-path)
400  (lambda ()
401    "Hello world"))
402
403(define-page (login-page-path)
404  (lambda ()
405    (login-form))
406  no-session: #t)
407</enscript>
408
409You can customize the access denied message by setting the {{page-access-denied-message}} with an one-argument procedure (the page path).
410
411
412
413=== Compiled pages
414
415Since Chicken is a compiler and our pages are Chicken code, we can compile them to have faster pages.  We just need to compile our app and pass the generated {{.so}} to the {{awful}} application:
416
417  $ csc -s hello-world.scm
418  $ awful hello-world.so
419
420
421
422=== Multiple applications support
423
424To be able to deploy multiple awful applications with different configurations under the same server, use Spiffy access files.  See Spiffy's [[http://chicken.wiki.br/eggref/4/spiffy#access-files|access files documentation]] for further details.
425
426
427
428=== List of user configurable parameters
429
430<parameter>(debug-file [file path])</parameter>
431
432If {{#f}}, indicates that debugging should be disabled.  When set to a string, it should be the path to the file where the debug messages go (when {{debug}} or {{debug-pp}} is used.)
433
434The default value is {{#f}}.
435
436
437<parameter>(debug-db-query? [boolean])</parameter>
438
439When not {{#f}}, all queries passed to {{$db}} and to {{$db-row-obj}} are printed to the debug file.
440
441The default value is {{#f}}.
442
443
444<parameter>(debug-db-query-prefix [string])</parameter>
445
446Prefix to be used for queries debugging when {{debug-db-query}} is not {{#f}}.
447
448The default value is {{""}}.
449
450
451<parameter>(db-credentials [boolean or list])</parameter>
452
453Credentials to be used to access the database (see the [[http://chicken.wiki.br/eggref/4/postgresql|postgresql]] egg documentation.)  When {{#f}}, no database access is performed.
454
455The default value is {{#f}}.
456
457
458<parameter>(ajax-library [string])</parameter>
459
460URL or path to the ajax library (currently only [[http://jquery.com|JQuery]] is supported.)
461
462The default value is {{"http://ajax.googleapis.com/ajax/libs/jquery/1.4.2/jquery.min.js"}}
463
464
465<parameter>(enable-ajax [boolean])</parameter>
466
467When {{#t}}, makes {{define-page}} link the {{ajax-library}} to the generated page.
468
469The default value is {{#f}}
470
471
472<parameter>(ajax-namespace [string])</parameter>
473
474Name to be used as a namespace for ajax URL paths.
475
476The default value is {{"ajax"}}.
477
478
479<parameter>(enable-session [boolean])</parameter>
480
481When {{#t}}, session support is enabled.
482
483The default value is {{#f}}.
484
485
486<parameter>(page-access-control [procedure])</parameter>
487
488An one-argument (URL path of the current page) procedure which tells whether the access to the page is allowed or not.
489
490The default value is {{(lambda (path) #t)}}.
491
492
493<parameter>(page-access-denied-message [procedure])</parameter>
494
495An one-argument (URL path of the current page) procedure which returns the access denied message.
496
497The default value is {{(lambda (path) (<h3> "Access denied."))}}.
498
499
500<parameter>(page-doctype [string])</parameter>
501
502The doctype (see the [[http://chicken.wiki.br/eggref/4/doctype|doctype]] egg) to be applied to all pages defined by {{define-page}}.  Can be overwritten by {{define-page}}'s {{doctype}} keyword parameter.
503
504The default value is {{""}}.
505
506<parameter>(page-css [boolean or string])</parameter>
507
508The CSS file to be linked by all pages defined by {{define-page}}.  Can be overwritten by {{define-page}}'s {{css}} keyword parameter.  See [[http://chicken.wiki.br/eggref/4/html-utils|html-utils]]'s {{html-page}} procedure to know about the {{css}} keyword parameter syntax.
509
510The default value is {{#f}} (no CSS).
511
512<parameter>(page-charset [boolean or string])</parameter>
513
514The page charset to be used by all pages defined by {{define-page}}.  Can be overwritten by {{define-page}}'s {{charset}} keyword parameter.
515The default value is {{#f}} (no explicit charset).
516
517
518<parameter>(login-page-path [string])</parameter>
519
520The URL path for the login page.  When creating a login page, be sure to set the {{no-session}} keyword parameter for {{define-page}} to {{#t}}, otherwise you'll get an endless loop.
521
522The default value is {{"/login"}}.
523
524
525<parameter>(main-page-path [string])</parameter>
526
527The URL path to the app main page.
528
529The default value is {{"/main"}}.
530
531<parameter>(app-root-path [string])</parameter>
532
533The base path to be used by the application.  All the pages defined by {{define-page}} will use {{app-root-path}} as the base directory.  For example, if {{app-root-path}} is set to {{"/my-app"}} and {{"my-page"}} is used as first argument to {{define-page}}, the page would be available at {{http://<server>:<port>/my-app/my-page}}.
534
535The default value is {{"/"}}.
536
537<parameter>(valid-password? [procedure])</parameter>
538
539A two-argument (user and password) procedure which indicates whether the given password is valid for the given user.
540
541The default value is {{(lambda (user password) #f)}}.
542
543<parameter>(page-template [procedure])</parameter>
544
545An one-mandatory-argument procedure to be used by {{define-page}} (unless {{define-page}}'s {{no-template}} keyword parameter is set to {{#f}}) to generate HTML pages. Although this procedure can take only one mandatory argument, the following keyword arguments are passed:
546
547* css
548* title
549* doctype
550* headers
551* charset
552* no-ajax
553* no-template
554* no-session
555* no-db
556
557The default value is {{html-page}} (see the [[http://chicken.wiki.br/eggref/4/html-utils|html-utils]] egg documentation.)
558
559<parameter>(ajax-invalid-session-message [string])</parameter>
560
561The message to be used when attempting the make an ajax call using an invalid session identifier.
562
563The default value is {{"Invalid session}}.
564
565
566<parameter>(web-repl-access-control [procedure])</parameter>
567
568A no-argument procedure to control access to the web REPL.
569
570The default value is {{(lambda () #f)}}.
571
572
573<parameter>(web-repl-access-denied-message [string])</parameter>
574
575Message to be printed when the access to the web REPL is denied.
576
577The default value is {{(<h3> "Access denied.")}}.
578
579
580<parameter>(session-inspector-access-control [procedure])</parameter>
581
582A no-argument procedure to control access to the session inspector.
583
584The default value is {{(lambda () #f)}}.
585
586
587<parameter>(session-inspector-access-denied-message [string])</parameter>
588
589Message to be printed when the access to the session inspector is denied.
590
591The default value is {{(<h3> "Access denied.")}}.
592
593
594<parameter>(page-exception-message [procedure])</parameter>
595
596An one-argument procedure to be used when an exception occurs while {{define-page}} tries to evaluate its contents.
597
598The default value is {{(lambda (exn) (<h3> "An error has accurred while processing your request."))}}
599
600
601<parameter>(enable-javascript-compression [boolean])</parameter>
602
603Enable javascript compression support.  When enabled the compressor set by {{javascript-compressor}} is used.
604
605The default value is {{#f}}.
606
607
608<parameter>(javascript-compressor [procedure])</parameter>
609
610An one-argument procedure (the javascript code) which return the given javascript code compressed.  Only used when {{enable-javascript-compression}} is not {{#f}}.
611
612The default value is the {{identity}} procedure.
613
614A possible value for {{javascript-compressor}} is {{jsmin-string}} (see the [[http://chicken.wiki.br/eggref/4/jsmin|jsmin]] egg.)
615
616
617=== List of read-only parameters available to users
618
619Note: these parameters should not be explicitly set and when their use is needed, it's a string sign you're doing something you shouldn't (except for {{db-connection}}, which can be used by procedures from the [[http://chicken.wiki.br/eggref/4/postgresql|postgresql]] egg API).
620
621
622<parameter>(http-request-variables)</parameter>
623
624The per-request value returned by [[http://chicken.wiki.br/eggref/4/spiffy-request-vars|spiffy-request-vars]]'s {{request-vars}}.
625
626
627<parameter>(db-connection)</parameter>
628
629A per-request databaseconnection object.  The connection is automatically opened and closed by awful in a per-request basis (unless databases are not being used the {{no-db}} keyword parameter for {{define-page}} is {{#t}}.)
630
631
632<parameter>(page-javascript)</parameter>
633
634Javascript code to be added to the pages defined by {{define-page}}.
635
636
637<parameter>(sid)</parameter>
638
639The session identifier.
640
641
642<parameter>(awful-apps)</parameter>
643
644The list of awful applications, as given to the awful server when invoked from the command line.
645
646
647=== List of procedures
648
649<procedure>(++ string1 string2 ... stringn)</procedure>
650
651A shortcut to {{string-append}}.
652
653
654<procedure>(concat args #!optional (sep ""))</procedure>
655
656Convert {{args}} to string and intersperse the resulting strings with {{sep}}.
657
658
659<procedure>(include-javascript file)</procedure>
660
661A shortcut to {{(<script> type: "text/javascript" src: file)}}.
662
663
664<procedure>(add-javascript . code)</procedure>
665
666Add arbitrary javascript code to the pages defined by {{define-page}}.
667
668
669<procedure>(debug . args)</procedure>
670
671Print {{args}}, concatenated, to the file {{debug-file}}.
672
673
674<procedure>(debug-pp arg)</procedure>
675
676Pretty-print {{arg}} to the file {{debug-file}}.
677
678
679<procedure>($session var #!optional default)</procedure>
680
681Return the value of {{var}} in the session (or {{default}} if {{var}} does not exist or is {{#f}}).
682
683
684<procedure>($session-set! var #!optional val)</procedure>
685
686If {{var}} is a quoted symbol, set the value of {{var}} to {{val}}.  If {{val}} is not provided, {{var}} will have its value set to {{#f}}.
687
688{{var}} can be an alist mapping session variable names to their corresponding values.
689
690Examples:
691
692<enscript highlight=scheme>
693($session-set! 'foo "foo value")
694
695($session-set! '((foo . "foo value")
696                 (bar . "bar value")
697                 (baz . "baz value")))
698</enscript>
699
700
701<procedure>(link url text . rest)</procedure>
702
703Return a session-aware HTML code for a link, using the {{<nowiki>&lt;a&gt;</nowiki>}} procedure from [[http://chicken.wiki.br/eggref/4/html-tags|html-tags]].
704
705The {{rest}} arguments are the same as the ones for the {{<nowiki>&lt;a&gt;</nowiki>}} procedure from [[http://chicken.wiki.br/eggref/4/html-tags|html-tags]], plus the following:
706
707; {{no-session}} : a boolean.  If {{#t}}, forces {{link}} to ignore the session even when {{enable-session}} is {{#t}}.
708; {{arguments}} : an alist mapping variable names to their corresponding values, to be passed to uri-common's {{form-urlencode}} procedure.
709; {{separator}} : the value to the {{separator}} keyword argument to be passed to to uri-common's {{form-urlencode}} procedure.
710
711When {{enable-session}} is {{#t}}, {{link}} automatically encodes the session identifier in the URI (unless {{no-session}} is {{#t}}).
712
713
714<procedure>(form contents . rest)</procedure>
715
716Return a session-aware HTML code for a form, using the {{<form>}} procedure from [[http://chicken.wiki.br/eggref/4/html-tags|html-tags]].
717
718The {{rest}} arguments are the same as the ones for the {{<form>}} procedure from [[http://chicken.wiki.br/eggref/4/html-tags|html-tags]], plus {{no-session}}, a boolean.  If {{no-session}} is {{#t}}, it forces {{form}} to ignore the session even when {{enable-session}} is {{#t}}.
719
720When {{enable-session}} is {{#t}}, {{form}} automatically generates a hidden input field to pass the session identifier (unless {{no-session}} is {{#t}}).
721
722
723<procedure>($ var #!optional default converter)</procedure>
724
725Return the HTTP request value for the given variable {{var}}.  The variable is looked for in both the query string (GET method) and request body (e.g., POST method).
726
727
728<procedure>($db q #!key default values)</procedure>
729
730Execute the given query ({{q}}) on the database and return the result as a list of lists or {{default}} if the result set is empty.
731
732The {{values}} keyword parameter (a list) is a list of values to replace the placehoders in the query.
733
734Example:
735
736<enscript highlight=scheme>
737($db "insert into foo (bar, baz) values (?, ?)" values: '("bar-val" "baz-val"))
738</enscript>
739
740<procedure>($db-row-obj q)</procedure>
741
742Execute the given query {{q}} on the database and return an one-argument procedure which takes as argument the name of the database field to get the value.
743
744Example:
745
746<enscript highlight=scheme>
747(let ((& ($db-row-obj "select full_name, phone from users where user_id=1")))
748  (<p> "Full name: " (& 'full_name))
749  (<p> "Phone: " (& 'phone)))
750</enscript>
751
752''Warning'': currently {{$db-row-obj}} is only implemented for Postgresql databases.
753
754
755<procedure>(sql-quote . data)</procedure>
756
757Escape and quote the concatenation of {{data}} to be used in SQL queries.
758
759''Warning'': for Sqlite databases, {{sql-quote}} just replaces {{'}} by {{''}} and quotes the {{data}}.  For Postgresql, {{sql-quote}} quotes the result of {{escape-string}}.
760
761
762<procedure>(define-page path contents #!key css title doctype headers charset no-ajax no-template no-session no-db no-javascript-compression)</procedure>
763
764Define an awful page.
765
766{{path}} is the path to the page.  It can be represented by two types: a string and a regular expression object.  If it is a string, the path used in the URI will be bound to the given no-argument procedure {{contents}}.  If it is a regular expression object, any request whose URL path matches the regular expression will br handled by the one-argument procedure {{contents}}.  This procedure will be given the requested path.
767
768The {{css}}, {{title}}, {{doctype}}, {{headers}} and {{charset}} keyword parameters have the same meaning as [[http://chicken.wiki.br/eggref/4/html-utils]]'s {{html-page}}.
769
770If {{no-ajax}} is {{#t}}, it means that the page won't use ajax.
771
772If {{no-template}} is {{#t}}, it means that no page template (see the {{page-template}} parameter) should be used.
773
774If {{no-session}} is {{#t}}, it means that the page should not use session.
775
776If {{no-db}} is {{#t}}, it means that the page should not use the database, even when database usage is activated by {{enable-db}} and {{db-credentials}} is not {{#f}}.
777
778If {{no-javascript-compression}} is {{#t}} the javascript code for the page is not compressed, even when {{enable-javascript-compression}} is not {{#f}}.
779
780Examples:
781
782<enscript highlight=scheme>
783
784(use srfi-1 ;; for filter-map
785     regex) ;; for regexp
786
787;; http://host:port/foo => "bar"
788(define-page "/foo"
789  (lambda ()
790    "bar"))
791
792;; http://host:port/add/1/2/3 => 6
793(define-page (regexp "/add/.*")
794  (lambda (path)
795    (let ((numbers (filter-map string->number (string-split path "/"))))
796      (number->string (apply + numbers)))))
797
798</enscript>
799
800<procedure>(define-session-page path contents . rest)</procedure>
801
802Define a session-aware page.  When the page is accessed and a correponding session does not exist, it is created.  If the session already exists and is not valid, it is recreated.  If the session already exists and is valid, then it is refreshed.
803
804The {{rest}} parameters are the same as for {{define-page}}.
805
806Here's an example (the [[http://www.paulgraham.com/arcchallenge.html|arc challenge]]):
807
808<enscript highlight=scheme>
809(use awful html-utils spiffy-request-vars)
810
811(define-session-page "said"
812  (lambda ()
813    (with-request-vars $ (said)
814      (cond (said
815             ($session-set! 'said said)
816             (link "said" "click here"))
817            (($session 'said)
818             => (lambda (said)
819                  (++ "You said: " said)))
820            (else (form (++ (text-input 'said)
821                            (submit-input))
822                        action: "said"
823                        method: 'post))))))
824</enscript>
825
826
827<procedure>(ajax path id event proc #!key target (action 'html) (method 'POST) (arguments '()) js no-session no-db vhost-root-path live prelude)</procedure>
828
829Generate javascript code to be added to the page defined by {{define-page}}.  Return the generated javascript code (which usually is not useful, so should be discarded).
830
831{{path}} is the URL path (a string) of the server side handler. This path is placed under the {{(app-root-path)/(ajax-namespace)}} path.  So, if your {{app-root-path}} is {{"my-app"}}, your {{ajax-namespace}} is {{"ajax"}} and you use {{"do-something"}} as the first argument to {{ajax}}, the URL for the server side handler would be {{"/my-app/ajax/do-something"}}.
832
833{{id}} (a quoted symbol) is the id of the DOM element to be observed.
834
835{{event}} (a quoted symbol or a list) is the event(s) to be observed. If it is a quoted symbol (e.g., {{'click}}), only this event will be bound.  If {{event}} is a list of events, all the events from the list will be bound.
836
837{{proc}} is a no-argument procedure to be executed on the server side.
838
839The {{target}} keyword parameter is the id of the DOM element to be affected by the result of {{proc}}.
840
841The {{method}} (a quoted symbol, usually {{'GET}} or {{'POST}}) keyword parameter is the HTTP method to be used by the ajax request.
842
843The {{arguments}} keyword parameter is an alist mapping request variables (symbols) to their values (strings).  {{ajax}} uses these arguments to assembly the query string or the request body to send to the server when performing the ajax request.
844
845Example:
846
847<enscript highlight=scheme>
848arguments: '((var1 . "$('#var1').val()")
849             (var2 . "$('#var2').val()"))
850</enscript>
851
852If the {{no-session}} keyword parameter is {{#t}}, it means that no session should be considered ({{ajax}} implicit sends the session identifier when {{no-session}} is {{#f}}).
853
854If the {{no-db}} keyword parameter is {{#t}}, it means that the should be no attempt to connect the database, even when database usage is activated by {{enable-db}} and {{db-credentials}} is not {{#f}}.
855
856The {{vhost-root-path}} keyword parameter (a string) is the vhost root path.  It is useful for explicitly separate pages defined using the same path (see {{define-page}}) but for different vhosts.
857
858The {{live}} keyword parameter (boolean) indicates wheter ajax should use JQuery's live method (see [[http://api.jquery.com/live/]]).
859
860The {{prelude}} keyword parameter (string) is an arbitrary piece of javascript code to be placed right before the ajax request.
861
862The {{ajax}} procedure is session, HTTP request and database -aware.
863
864
865<procedure>(periodical-ajax path interval proc #!key target (action 'html) (method 'POST) (arguments '()) js no-session no-db vhost-root-path live prelude)</procedure>
866
867Periodically execute {{proc}} on the server side, using {{(app-root-path)/(ajax-namespace)/path}} as the URL path for the server side handler.
868
869{{interval}} (a number) is the interval between consecutive executions of {{proc}}, in milliseconds.
870
871The meaning of the keyword parameters is the same as for {{ajax}}'s.
872
873
874<procedure>(ajax-link path id text proc #!key target (action 'html) (method 'POST) (arguments '()) js no-session no-db (event 'click) vhost-root-path live class hreflang type rel rev charset coords shape accesskey tabindex a-target prelude)</procedure>
875
876A shortcut to
877
878<enscript highlight=scheme>
879(begin
880  (ajax path id 'click proc ...)
881  (<a> href: "#" [...other <a> keyword parameters...] id: id text))
882</enscript>
883
884The meaning of the {{target}}, {{action}}, {{method}}, {{arguments}}, {{js}}, {{no-session}}, {{no-db}}, {{event}}, {{vhost-root-path}} and {{live}} keyword parameters is the same as for {{ajax}}'s.
885
886The meaning of the {{class}}, {{hreflang}}, {{type}}, {{rel}}, {{rev}}, {{charset}}, {{coords}}, {{shape}}, {{accesskey}}, {{tabindex}} and {{a-target}} are the same as for [[http://chicken.wiki.br/eggref/4/html-tags]]' {{<nowiki>&lt;a&gt;</nowiki>}} procedure (except that {{a-target}} is {{<nowiki>&lt;a&gt;</nowiki>}}'s {{target}}, since {{ajax}} uses the {{target}} keyword parameter).
887
888The {{event}} keyword parameter syntax is the same for {{ajax}}'s {{event}} mandatory parameter.
889
890
891<procedure>(login-form #!key (user-label "User: ") (password-label "Password: ") (submit-label "Submit") (refill-user #t))</procedure>
892
893Return a user/password login form (e.g., for using in authentication pages).
894
895When the {{refill-user}} is {{#t}}, the User field is reffiled with the value from the {{user}} query string value when either the session or the password is invalid.
896
897The {{user-label}}, {{password-label}} and {{submit-label}} keyword parameters are labels to be used for the user, password and submit form widgets, respectively.
898
899
900<procedure>(enable-web-repl path #!key css title)</procedure>
901
902Enable the web REPL.  {{path}} is the URL path to the web REPL.
903
904The keyword parameter {{css}} is the CSS to be used the the web REPL page (see [[http://chicken.wiki.br/eggref/4/html-utils|html-utils]]'s {{html-page}} documentation for the {{css}} keyword parameter.)
905
906The keyword parameter {{title}} (a string) is the title for the web REPL page (see [[http://chicken.wiki.br/eggref/4/html-utils|html-utils]]'s {{html-page}} documentation for the {{title}} keyword parameter.)
907
908{{enable-web-repl}} automatically enables ajax (see {{enable-ajax}}.)
909
910<procedure>(enable-session-inspector path #!key css title)</procedure>
911
912Enable the session inspector.  {{path}} is the URL path to the session inspector.
913
914The keyword parameter {{css}} is the CSS to be used the the session inspector page (see [[http://chicken.wiki.br/eggref/4/html-utils|html-utils]]'s {{html-page}} documentation for the {{css}} keyword parameter.)
915
916The keyword parameter {{title}} (a string) is the title for the session inspector page (see [[http://chicken.wiki.br/eggref/4/html-utils|html-utils]]'s {{html-page}} documentation for the {{title}} keyword parameter.)
917
918{{enable-session-inspector}} automatically enables session (see {{enable-session}}.)
919
920<procedure>(define-login-trampoline path #!key vhost-root-path hook)</procedure>
921
922Define a trampoline -- an intermediate page accessed when redirecting from the login page to the main page.
923
924
925
926=== Tips and tricks
927
928==== Use {{link}} and {{form}} for links and forms
929
930Instead of using {{<nowiki>&lt;a&gt;</nowiki>}} and {{<form>}} for creating links and forms, respectively, consider using the {{link}} and {{form}} procedures instead.  They are specially useful when using sessions, since they transparently handle the session identifier for you.  Even if you don't use sessions, they may save you some work if one day you decide to use sessions (then you won't have do to anything regarding to links and forms).
931
932
933==== Use {{with-request-vars}} when referencing the same request variable multiple times
934
935When you need to access the same request variable more than once, consider using [[http://chicken.wiki.br/eggref/4/spiffy-request-vars|spiffy-request-vars]]' {{with-request-vars}}.
936
937For example, instead of:
938
939<enscript highlight=scheme>
940(use awful)
941
942(define-page "save-and-show-user"
943  (lambda ()
944    ($session-set! 'user ($ 'user))
945    (++ "Welcome " ($ 'user) "!")))
946</enscript>
947
948consider using something like:
949
950<enscript highlight=scheme>
951(use awful spiffy-request-vars)
952
953(define-page "save-and-show-user"
954  (lambda ()
955    (with-request-vars $ (user)
956      ($session-set! 'user user)
957      (++ "Welcome " user))))
958</enscript>
959
960
961==== Use the web REPL and the session inspector for debugging
962
963Here's a simple recipe to allow access for your local machine to the web REPL ({{/repl}}) and to the session inspector ({{/session-inspector}}).
964
965<enscript highlight=scheme>
966(session-inspector-access-control
967 (lambda ()
968   (member (remote-address) '("127.0.0.1"))))
969
970(enable-session-inspector "/session-inspector")
971
972
973(web-repl-access-control
974 (lambda ()
975   (member (remote-address) '("127.0.0.1"))))
976
977(enable-web-repl "/repl")
978</enscript>
979
980To access them, just point your browser to {{http://localhost:<port>/repl}} and {{http://localhost:<port>/session-inspector}}, respectively.
981
982
983==== Create custom page definers when {{page-template}} and/or plain {{define-page}} are not enough
984
985You can define your own page definers when {{page-template}} or the plain {{define-page}} is not enough for what you need.  Here's an example:
986
987<enscript highlight=scheme>
988#!/usr/bin/awful
989
990(use awful html-tags)
991
992(define (define-custom-page path contents)
993  (define-page path
994    (lambda ()
995      (<html> (<body> (contents))))
996    no-template: #t))
997
998(define-custom-page (main-page-path)
999  (lambda ()
1000    "Hey!"))
1001</enscript>
1002
1003If you access {{http://localhost:8080}} you'll get the following HTML code:
1004
1005  <html><body>Hey!</body></html>
1006
1007
1008==== Debugging: error messages on the browser window
1009
1010Error messages right on the browser window can be quite handy for debugging (although not for production environments).  Here's a way to accomplish that:
1011
1012<enscript highlight=scheme>
1013(use awful html-tags)
1014
1015(page-exception-message
1016 (lambda (exn)
1017   (<pre> convert-to-entities?: #t
1018          (with-output-to-string
1019            (lambda ()
1020              (print-call-chain)
1021              (print-error-message exn))))))
1022</enscript>
1023
1024
1025==== Run awful without arguments to quickly share a file
1026
1027When invoked without arguments, awful (the application) starts the web server using the current directory as root path and keeps listening on port 8080.  So, if you want to quickly share a file (or some files), change to the directory containing the files and execute {{awful}}.  The access {{http://<host>:8080/<the-file-you-want>}}.
1028
1029
1030==== Awful badge
1031
1032Here's a suggestion:  [[image:http://parenteses.org/mario/img/thats-awful.png|That's awful!]]
1033
1034=== The name
1035
1036Awful doesn't mean anything special.  It's just awful.  But folks on freenode's #chicken (IRC) have suggested some acronym expansions:
1037
1038* A Whole Freaking Universe of Lambdas
1039* Authored Without Full Understanding of Logic
1040* Another Web Framework Understating Logic
1041* All Worthless Frameworks Unchain Laziness
1042* Armed With Flimsy Utility Lisp
1043* Awful Will Fed Up Lispers
1044* Awful Wildly Finalizes Unfinished Loops
1045* Another Widely Foolish Unknown Language
1046* Ain't Work For Unpleasant Laywers
1047* Aliens Would Find it Utterly Lame
1048* Aren't We Funny and Uncaring Lurkers
1049* Awful Will F*** Up Logic
1050* Awful Will Fart Upon Leaving
1051* Again Web Frameworks Underscore Lameness
1052* Attention While Fully Utilizing Laziness
1053* Another Webserver F***ing Up the Line
1054* Again We Forget Unclosed Lambdas
1055* All Web Features Understood Losslessly
1056* Anything With Fully Universal Lambdas
1057* Again We Fail Under Load
1058* Apocalyptic Warthogs Find Undiscovered Lands
1059* Accessible Web Framework Using Lisp
1060* Another Weird Framework Using Lisp
1061* All Waffles Fear Unicorn Landings
1062* A Working Facility Underscoring Laziness
1063* Another Webbot Flapping Under Lines
1064* Anybody Will Fake Unrealistic Loveletters
1065* Armadillos Would First Use Legs
1066* Astonishing Whales Fill Up Lakes
1067* Alternative Way to F*** Up Lisp
1068* Another Way to Find Undressed Ladies
1069* Amazing! Wonderful! Fantastic! Unbelievable! Lame.
1070* All Wonders Feel Useless Later
1071* Amazingly Wonderful Feeling, Using Lambdas
1072* Alligators Will Fear Us, Lunatics
1073* All Wussies Fear Ultimate Lambda
1074* Animals Will Find Us Letal
1075* Advanced Web Framework: Ultimate Lucubration
1076* Awful Will Feed Urban Lethargy
1077* Argument With Focus Upon Labelling
1078* Another Word Faking Unpremeditated Label
1079* Again We Find it Utterly Useless
1080* Ain't Work For Unattractive Ladies
1081* A Way For Using Lambdas
1082* Awful Way For Using Lambdas
1083* Apparently We Freaks Understand Lambdas
1084* Again We Foolishly Use Lists
1085* At Work Fools Use Lisp
1086* Again We Foolishly Use Lisp
1087* Another Wimp Fall Upon Lisp
1088* Accepting Whatever Fools Undertake Lightly
1089* Absurd Word For Unnatural Lingo
1090* Alternative Word For Useless Loser
1091* Acronym With Filled Up Letters
1092* Acronym We Find Utterly Lame
1093* Another Webserver Functioning Until Launched
1094* Applications With Familiar, Understandable Language
1095* (Awful Words Forming Useless List)
1096* All Who Force Unusual Layout
1097* Again We Fear Undescribable Lamenting
1098* Awful Will Favour Ugly Layouts
1099* Apes With Frequent Uncontrolled Lunacy
1100
1101==== Acknowledgements (IRC nicknames on freenode's #chicken):
1102
1103
1104* C-Keen
1105* DerGuteMoritz
1106* elderK
1107* elf
1108* florz
1109* merlincorey
1110* sjamaan
1111
1112
1113=== License
1114
1115BSD
1116
1117
1118=== Version history
1119
1120; 0.22:
1121* bug fix: fixed unintended shadowing of {{js}} in ajax
1122* added the {{prelude}} keyword parameter for {{ajax}}, {{periodical-ajax}} and {{ajax-link}}
1123* {{$db}} supports the {{values}} keyword parameter (patch by Stephen Eilert)
1124* awful (the application) can now be invoked without arguments
1125* awful (the application) handles {{-h}} and {{--help}}
1126* dropped [[/eggref/4/jsmin|jsmin]] requirement
1127
1128; 0.21: ajax and main page redirection issues fixes
1129
1130; 0.20:
1131* {{page-access-control}} controls access to pages even when no session is in use
1132* '''Warning''': the following parameters have been removed: {{enable-reload}}, {{reload-path}} and {{reload-message}}.  Now the way to define reloaders is via {{define-page}}.
1133* new parameter: {{awful-apps}} (a list of awful applications as passed to the awful server)
1134
1135; 0.19: bug fix for {{(reload-path)}} handler
1136
1137; 0.18:
1138* support for regex-based page paths (see {{define-page}})
1139* {{define-page}} checks whether the second arg is a procedure.
1140* use {{-O3 -lambda-lift}} instead of {{-O2}} for compilation
1141* {{main-page-path}} redirection made with code stolen from [[http://chicken.wiki.br/eggref/4/spiffy|spiffy]]'s {{send-response}}
1142
1143; 0.17 : .meta bug fix.  postgresql is not required as a dependency (thanks to Stephen Pedrosa Eilert for pointing this issue).
1144; 0.16 :
1145* added {{define-session-page}}
1146* bug fix for {{link}}
1147
1148; 0.15 : jquery updated to 1.4.2 ({{ajax-library}}).
1149; 0.14 : {{link}}'s {{args}} keyword parameter renamed to {{arguments}} (the same as {{ajax}}'s).
1150; 0.13 : Session-aware {{link}} and {{form}} procedures.  Bug fix for {{ajax-link}} (was not passing the {{class}} keyword argument to <nowiki>&lt;a&gt;</nowiki>).
1151; 0.12 : Containers for user and password fields ({{login-form}})
1152; 0.11 : awful sets Spiffy's {{root-path}} to {{(current-directory)}}
1153; 0.10 :
1154* Multiple database support. Currently Postgresql (via [[http://chicken.wiki.br/eggref/4/postgresql|postgresql]] egg) and Sqlite3 (via [[http://chicken.wiki.br/eggref/4/sqlite3|sqlite3]] and [[http://chicken.wiki.br/eggref/4/sql-de-lite|sql-de-lite]] eggs) are supported.  See [[http://chicken.wiki.br/eggref/4/awful-postgresql|awful-postgresql]], [[http://chicken.wiki.br/eggref/4/sqlite3|sqlite3]] and [[http://chicken.wiki.br/eggref/4/sql-de-lite|sql-de-lite]] eggs.
1155
1156* Removed requirement for postgresql
1157
1158* {{enable-db}} is now a procedure (not a parameter as before) and accepts no arguments
1159
1160; 0.9 : {{login-form}} gets the {{user}} refilled when the session or passowrd is not valid.  This feature may be disabled by setting the {{refill-user}} keyword parameter for {{login-form}} to {{#f}} (default is {{#t}}).  Thanks to Arthur Maciel for suggesting this feature.
1161; 0.8 :
1162* jquery updated to 1.4.1 ({{ajax-library}}).
1163
1164* support for jquery's {{live}} method ({{live}} keyword parameter for {{ajax}}, {{ajax-link}} and {{periodical-ajax}}).  See [[http://api.jquery.com/live/]]
1165
1166* bug fixes: {{periodical-ajax}} and {{ajax-link}} propagate {{vhost-root-path}} to {{ajax}}
1167
1168* added {{awful-start}} and dropped spiffy requirement for awful (the server)
1169
1170* dropped requirement for miscmacros
1171
1172* added more ajax tests
1173
1174; 0.7 : {{ajax-link}} accepts all {{<nowiki>&lt;a&gt;</nowiki>}}'s keyword arguments
1175; 0.6 : Explicitly depends on [[http://chicken.wiki.br/eggref/4/http-session|http-session]] 2.0
1176; 0.5 : Reload handler register the reload path after reloading.
1177; 0.4 : {{disable-reload?}} renamed to {{enable-reload}}.  {{enable-reload}} is {{#f}} by default.
1178; 0.3 : {{awful}} (the server) allows applications to use Chicken syntax ({{use}}, {{include}} etc)
1179; 0.2 : Added javascript compression support
1180; 0.1 : Initial release
Note: See TracBrowser for help on using the repository browser.