source: project/wiki/eggref/4/waffle @ 37056

Last change on this file since 37056 was 37056, checked in by andyjpb, 9 months ago
File size: 5.6 KB
Line 
1[[tags: egg]]
2
3== waffle
4
5[[toc:]]
6
7=== Description
8
9WAFFLE - Widgets and Forms For Lisp Enthusiasts
10
11WAFFLE is a toolkit for building HTML and other XML based pages through
12composition of  discrete, user definable, widgets.
13Widgets comprise markup specified in SXML as well as a set of attributes
14which are rendered into the widget.
15
16WAFFLE handles the composition of multiple widgets of the same type
17containing HTML Form elements.
18If a widget is given a 'name' attribute then the value of this attribute
19propagates to child widgets and HTML Form elements. The values does not
20propagate to any other type of element. Name attributes in other types of
21element are ignored.
22
23The value propagates by being prepended to the name attribute of the
24child widgets or form elements.
25
26This allows multiple widgets containing form elements to be composed on the
27same page without their names clashing.
28
29
30WAFFLE is based on ideas in the following papers and essays:
31
32http://www.snell-pym.org.uk/archives/2006/12/17/the-implementation-of-web-applications
33http://www.snell-pym.org.uk/archives/2007/05/18/a-design-for-a-scheme-web-application-framework/
34http://www.snell-pym.org.uk/archives/2007/06/17/another-thing-i-hate-about-web-application-frameworks/
35http://pagesperso-systeme.lip6.fr/Christian.Queinnec/PDF/www.pdf
36
37
38=== Source Code
39
40[[https://bitbucket.org/andyjpb/waffle]]
41
42=== Author
43
44[[/users/andyjpb|Andy Bennett]]
45
46=== Requirements
47
48* [[sxml-transforms]] [[matchable]] [[uri-common]]
49
50=== API
51
52==== add-widget
53
54<procedure>(add-widget widget-name definition)</procedure>
55
56Makes the widget described by {{definition}} available as {{widget-name}}.
57
58<enscript highlight="scheme">
59(add-widget 'say-hello `((markup . (div "Hello " ,user)) (attributes . ((user #f)))))
60</enscript>
61
62==== load-widget
63
64<procedure>(load-widget widget-name filename)</procedure>
65
66Loads a widget from the specified {{filename}} and makes it available as {{widget-name}}.
67
68The files are similar to scheme source files and have {{markup}} and {{attribute}} sections thus:
69
70<enscript highlight="scheme">
71(markup . `(*TOP*
72  ,@(if user
73    `(div (img (@ (class user-avatar) (src "/face.svg")))
74          (span ,user)
75          (a (@ (href "/logout")) "Log out"))
76    `(a (@ (href "/login")) "Log in"))
77))
78(attributes . (
79  (user #f)
80))
81</enscript>
82
83The {{cdr}} of {{markup}} should evaluate to some sxml. You can use R5RS scheme and the variables listed in {{attributes}} to generate it. When the widget is called, if an attribute is specified then it is bound to that value otherwise it is bound to the default value specified in the {{attributes}} list.
84
85If the above code was placed in the {{user-menu.widget.scm}} file you could load it thus:
86
87<enscript highlight="scheme">
88(use waffle)
89(load-widget 'user-menu "user-menu.widget.scm")
90</enscript>
91
92
93==== load-widgets-from-directory
94
95<procedure>(load-widgets-from-directory dir extension #!optional prefix)</procedure>
96
97Loads a bunch of widgets from the specified {{dir}}.
98
99For example,
100
101<enscript highlight="scheme">
102(use waffle)
103(load-widgets-from-directory "./widgets" ".widget.scm")
104</enscript>
105
106...will load the files {{*.widget.scm}}. They will be automatically assigned widget names based on their filename. {{x.widget.scm}} will be named as if it has been loaded thus {{(load-widget 'x "x.widget.scm")}}.
107
108==== waffle-sxml->html
109
110<procedure>(waffle-sxml->html sxml)</procedure>
111
112Render the widget tree in {{sxml}} down to HTML on {{(current-output-port)}}.
113
114<enscript highlight="scheme">
115(use waffle)
116(load-widgets-from-directory "./widgets" ".widget.scm")
117
118(waffle-sxml->html
119  `(html (body (user-menu "Andy") (say-hello "Andy"))))
120</enscript>
121
122==== widget-rules
123
124<parameter>widget-rules</parameter>
125
126This is where the widgets end up after they've been added or loaded. If you want to use two or more distinct widget sets in the same process, you should {{parameterize}} this around your render pipeline.
127
128=== HTML Forms and the {{name}} attribute.
129
130waffle has knowledge of HTML Forms and makes it easy to compose widgets to make complex Forms.
131
132If a widget is given a {{name}} attribute then its value will propagate down dynamically to any HTML Form elements that end up in the sub-tree.
133
134For example, you might have some widgets that make up an invoice editor thus:
135
136<enscript highlight="scheme">
137(add-widget 'invoice-line
138            `((markup . (div (input (@ (name "line-item"))) (input (@ (name "cost")))))
139              (attributes . (()))))
140
141(add-widget 'invoice
142            `((markup . (div (h1 "Invoice" ,invoice-id)
143                             ,@contents
144                             (input (@ (type "submit") (name "ok")))))
145              (attributes . ((invoice-id "0")))))
146</enscript>
147
148...and you might want to compose them thus:
149
150<enscript highlight="scheme">
151`(invoice (@ (invoice-id "10000433"))
152   (invoice-line (@ (name "line1")))
153   (invoice-line (@ (name "line2")))
154   (invoice-line (@ (name "line3"))))
155</enscript>
156
157The inputs in the DOM will end up with the following names:
158<enscript highlight="scheme">
159line1/line-item
160line1/cost
161line2/line-item
162line2/cost
163line3/line-item
164line3/cost
165ok
166<enscript>
167
168This allows your rendering code to compose Form elements in a straightforward way and for the form handling code to work out the structure of the Form that was submitted.
169
170
171=== License
172
173  Copyright (C) 2012, Andy Bennett
174  All rights reserved.
175 
176  LGPL-2.1 https://www.gnu.org/licenses/old-licenses/lgpl-2.1.en.html
177
178=== Version History
179* 0.1, (2019/01/16) : I'm finally putting it into the CHICKEN coop! It's been available informally for ages but now I've done the tidying up work to be able to make it more widely available.
Note: See TracBrowser for help on using the repository browser.