File size: 8,659 Bytes
43203b4 | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 | \input texinfo @c -*-texinfo-*-
@comment $Id@w{$}
@comment %**start of header
@settitle CL-FORMS
@syncodeindex pg cp
@setfilename cl-forms.info
@include common-lisp.texi
@copying
Copyright @copyright{} 2021 Mariano Montone
@end copying
@dircategory Common Lisp
@direntry
* cl-forms: (cl-forms) Common Lisp web forms handling library.
@end direntry
@titlepage
@title CL-FORMS
@author Mariano Montone ( @email{marianomontone@@gmail.com} )
@page
@vskip 0pt plus 1filll
@insertcopying
@end titlepage
@contents
@node Top
@top Top
@cindex cl-forms
@menu
* Intro::
* Installation::
* Usage::
* API::
* Index::
@end menu
@node Intro
@chapter Introduction
@anchor{introduction}
CL-FORMS is a web forms handling library for Common Lisp.
Although it is potentially framework agnostic, it runs on top of Hunchentoot at the moment.
It features:
@itemize @bullet
@item
Several form field types: String, boolean, integer, email, password fields. And more.
@item Custom fields. CL-FORMS is extensible and it is possible to define new field types.
@item Server and client side validation
@item Rendering backends. Forms can be rendered via CL-WHO, or Djula, or something else; the backend is pluggable. The default renderer is CL-WHO.
@item Themes (like Bootstrap)
@item Control on rendering and layout.
@item Handling of form errors.
@item CSRF protection
@end itemize
@node Installation
@chapter Installation
@anchor{installation}
With Quicklisp:
@lisp
(ql:quickload "cl-forms")
@end lisp
When you want to use a form renderer such as @code{:who} or @code{:djula}, quickload the associated package: @code{cl-forms.who}, @code{cl-forms.who.bootstrap}, @code{cl-forms.djula}.
@node Usage
@chapter Usage
@anchor{usage}
@section Basics
Use @clref{CL-FORMS, DEFFORM, macro} to define a form. Example:
@lisp
(defform fields-form (:action "/fields-post")
((name :string :value "")
(ready :boolean :value t)
(sex :choice :choices (list "Male" "Female") :value "Male")
(submit :submit :label "Create")))
@end lisp
On your web handler, grab the form via @clref{CL-FORMS,FIND-FORM,function}, select a renderer with `with-form-renderer`and then render the form with @clref{CL-FORMS,RENDER-FORM,function}:
@lisp
(let ((form (forms:find-form 'fields-form)))
(forms:with-form-renderer :who
(forms:render-form form))
@end lisp
To handle the form, grab it via @clref{CL-FORMS,FIND-FORM,function} and then call @clref{CL-FORMS,HANDLE-REQUEST,function} (you should probably also call @clref{CL-FORMS,VALIDATE-FORM,function} after).
Then bind form fields via either @clref{CL-FORMS,WITH-FORM-FIELD-VALUES,macro}, that binds the form field values; or @clref{CL-FORMS,WITH-FORM-FIELDS,macro} that binds the form fields.
@lisp
(let ((form (forms:find-form 'fields-form)))
(forms:handle-request form)
(forms:with-form-field-values (name ready sex) form
(who:with-html-output (forms.who::*html*)
(:ul
(:li (who:fmt "Name: ~A" name))
(:li (who:fmt "Ready: ~A" ready))
(:li (who:fmt "Sex: ~A" sex))))))
@end lisp
To output HTML on the REPL, do:
@lisp
(with-output-to-string (forms.who:*html*)
(let ((form (forms:find-form 'fields-form)))
(forms:with-form-renderer :who
(forms:render-form form))))
@end lisp
Please have a look at the demo sources for more examples of how to use the library
@section Demo
There's a demo included. To run:
@lisp
(require :cl-forms.demo)
(forms.test:run-demo)
@end lisp
@subsection Basic example
Define a form. Render the form via CL-WHO backend, doing:
@lisp
(forms:with-form-renderer :who
(forms:render-form form))
@end lisp
Then handle and validate the form.
Source code:
@lisp
@include ../test/demo/fields.lisp
@end lisp
@subsection Validation
Example of forms validation.
Add Clavier constraints to the form. Then call @clref{CL-FORMS, VALIDATE-FORM, function} after @clref{CL-FORMS, HANDLE-REQUEST, function}.
@lisp
@include ../test/demo/validation.lisp
@end lisp
@subsection Client validation
To validate in the client, just set @code{:client-validation} to @code{T}.
@lisp
@include ../test/demo/client-validation.lisp
@end lisp
@subsection Models
Forms can be attached to model objects. Model objects are CLOS instances from where form values are read and written to.
To work with models, forms are defined via defform-builder instead of defform. A form-builder is a function that takes the model objects and attaches it to the form. The form needs to define the accessors to access the model for each form field.
@lisp
@include ../test/demo/models.lisp
@end lisp
@subsection Composition
It is possible to compose forms using the @code{subform} field type:
@lisp
@include ../test/demo/composition.lisp
@end lisp
@subsection Form templates
Form templates is an alternative way of defining and rendering forms. Instead of defining a form with defform and then specifiying a template and render it, forms templates allow to do all that at the same time.
@lisp
@verbatiminclude ../test/demo/form-templates.lisp
@end lisp
@subsection Renderers
@lisp
@include ../test/demo/renderers.lisp
@end lisp
@node Form rendering
@section Form rendering
A form can be rendered via different renderers and themes.
There are implemented renderers for CL-WHO and Djula.
The only theme at the moment is a Bootstrap theme that runs under CL-WHO.
To be able to render a form a form renderer needs to be bound first. Renderers are bound using @clref{CL-FORMS,WITH-FORM-RENDERER,macro} macro.
Similarly, to use a theme other than the default one, it needs to be bound using @clref{CL-FORMS,WITH-FORM-THEME,macro}.
@subsection Form rendering functions
Forms are renderer using @clref{CL-FORMS,RENDER-FORM,function} to render the whole form all at once, or via @clref{CL-FORMS,RENDER-FORM-START,function},@clref{CL-FORMS,RENDER-FORM-END,function},@clref{CL-FORMS,RENDER-FIELD,function},@clref{CL-FORMS,RENDER-FIELD-LABEL,function},@clref{CL-FORMS,RENDER-FIELD-WIDGET,function}, to only render specific parts of a form and have more control.
@node CL-WHO renderer
@subsection CL-WHO renderer
The CL-WHO renderer uses CL-WHO library for rendering forms.
Needs @code{cl-forms.who} ASDF system loaded.
To render a form using CL-WHO bind the renderer via @clref{CL-FORMS,WITH-FORM-RENDERER, macro}, bind @code{FORMS.WHO:*HTML*} variable, and then render the form:
@lisp
(let ((form (forms::find-form 'fields-form)))
(who:with-html-output (forms.who:*html*)
(forms:with-form-renderer :who
(forms:render-form form))))
@end lisp
@node Bootstrap theme
@subsection Bootstrap theme
There's a Bootstrap theme implemented for CL-WHO renderer.
Needs @code{cl-forms.who.bootstrap} ASDF system loaded.
Select the theme via @clref{CL-FORMS,WITH-FORM-THEME,macro}:
@lisp
(let ((form (forms::find-form 'bs-fields-form)))
(forms:with-form-theme 'forms.who::bootstrap-form-theme
(forms:with-form-renderer :who
(who:with-html-output (forms.who::*html*)
(forms:render-form form)))))
@end lisp
@node Djula
@subsection Djula
CL-FORMS integrates with Djula template system.
Needs @code{cl-forms.djula} ASDF system loaded.
Djula tags:
@itemize
@item @code{@{% form form %@}}. Renders a whole form.
@item @code{@{% form-start form %@}}. Renders the form start part.
@item @code{@{% form-end form %@}}. Renders the form end part.
@item @code{@{% form-row form field-name %@}}. Renders the row with label and widget for the form field.
@item @code{@{% form-field-label form field-name %@}}. Renders the form field label.
@item @code{@{% form-field-widget form field-name %@}}. Renders the form field widget.
@end itemize
Make sure to @code{@{% set-package %@}} at the beggining of your Djula template to the package where the form lives. Otherwise, Djula wont' be able to find form fields by name.
Examples:
A Djula template that renders a whole form:
@verbatim
{% form form %}
@end verbatim
A Djula template that renders a form by parts:
@verbatim
{% set-package forms.test %}
{% form-start form %}
{% form-row form name %}
{% form-row form ready %}
<div>
{% form-field-label form sex %}
{% form-field-widget form sex %}
</div>
{% form-row form avatar %}
{% form-row form disabled %}
{% form-row form disabled-checkbox %}
{% form-row form readonly-checkbox %}
{% form-row form submit %}
{% form-end form %}
@end verbatim
@node API
@chapter API
@anchor{api}
@menu
* CL-FORMS package::
@end menu
@node CL-FORMS package
@section CL-FORMS package
(@clpackage :cl-forms)
@node Index
@chapter Index
@printindex cp
@printindex vr
@printindex fn
@bye
|