factor/extra/http/server/components/components.factor

225 lines
4.8 KiB
Factor
Raw Normal View History

2008-03-05 22:38:15 -05:00
! Copyright (C) 2008 Slava Pestov
! See http://factorcode.org/license.txt for BSD license.
USING: html.elements http.server.validators accessors namespaces
kernel io math.parser assocs classes words classes.tuple arrays
2008-04-14 05:34:26 -04:00
sequences splitting mirrors hashtables fry combinators
continuations math ;
2008-03-05 22:38:15 -05:00
IN: http.server.components
2008-04-14 05:34:26 -04:00
! Renderer protocol
GENERIC: render-view* ( value renderer -- )
GENERIC: render-edit* ( value id renderer -- )
TUPLE: field type ;
C: <field> field
M: field render-view* drop write ;
M: field render-edit*
<input type>> =type [ =id ] [ =name ] bi =value input/> ;
: render-error ( message -- )
<span "error" =class span> write </span> ;
TUPLE: hidden < field ;
: hidden ( -- renderer ) T{ hidden f "hidden" } ; inline
M: hidden render-view* 2drop ;
! Component protocol
2008-03-05 22:38:15 -05:00
SYMBOL: components
2008-04-14 05:34:26 -04:00
TUPLE: component id required default renderer ;
2008-03-05 22:38:15 -05:00
: component ( name -- component )
dup components get at
[ ] [ "No such component: " prepend throw ] ?if ;
2008-03-05 22:38:15 -05:00
2008-04-14 05:34:26 -04:00
GENERIC: init ( component -- component )
M: component init ;
2008-03-11 04:39:09 -04:00
GENERIC: validate* ( value component -- result )
2008-04-14 05:34:26 -04:00
GENERIC: component-string ( value component -- string )
2008-03-05 22:38:15 -05:00
SYMBOL: values
: value values get at ;
2008-03-11 04:39:09 -04:00
: set-value values get set-at ;
2008-04-14 05:34:26 -04:00
: blank-values H{ } clone values set ;
2008-03-11 04:39:09 -04:00
2008-04-14 05:34:26 -04:00
: from-tuple <mirror> values set ;
2008-03-05 22:38:15 -05:00
2008-04-14 05:34:26 -04:00
: values-tuple values get mirror-object ;
2008-03-05 22:38:15 -05:00
2008-04-14 05:34:26 -04:00
: render-view ( component -- )
[ id>> value ] [ component-string ] [ renderer>> ] tri
render-view* ;
2008-03-11 04:39:09 -04:00
2008-04-14 05:34:26 -04:00
<PRIVATE
2008-03-11 04:39:09 -04:00
2008-04-14 05:34:26 -04:00
: render-edit-string ( string component -- )
[ id>> ] [ renderer>> ] bi render-edit* ;
2008-03-11 04:39:09 -04:00
2008-04-14 05:34:26 -04:00
: render-edit-error ( component -- )
[ id>> value ] keep
[ [ value>> ] dip render-edit-string ]
[ drop reason>> render-error ] 2bi ;
2008-03-11 04:39:09 -04:00
2008-04-14 05:34:26 -04:00
: value-or-default ( component -- value )
[ id>> value ] [ default>> ] bi or ;
2008-03-11 04:39:09 -04:00
2008-04-14 05:34:26 -04:00
: render-edit-value ( component -- )
[ value-or-default ]
[ component-string ]
[ render-edit-string ]
tri ;
2008-03-11 04:39:09 -04:00
2008-04-14 05:34:26 -04:00
PRIVATE>
2008-03-11 04:39:09 -04:00
2008-04-14 05:34:26 -04:00
: render-edit ( component -- )
dup id>> value validation-error?
[ render-edit-error ] [ render-edit-value ] if ;
2008-03-11 04:39:09 -04:00
2008-04-14 05:34:26 -04:00
: validate ( value component -- result )
'[
,
over empty? [
[ default>> [ v-default ] when* ]
[ required>> [ v-required ] when ]
bi
] [ validate* ] if
] with-validator ;
2008-03-05 22:38:15 -05:00
2008-04-14 05:34:26 -04:00
: new-component ( id class renderer -- component )
2008-04-14 05:42:43 -04:00
swap new
2008-04-14 05:34:26 -04:00
swap >>renderer
swap >>id
init ; inline
2008-03-11 04:39:09 -04:00
! String input fields
2008-04-14 05:34:26 -04:00
TUPLE: string < component one-line min-length max-length ;
2008-03-05 22:38:15 -05:00
2008-04-14 05:34:26 -04:00
: new-string ( id class -- component )
"text" <field> new-component
t >>one-line ; inline
2008-03-05 22:38:15 -05:00
2008-04-14 05:34:26 -04:00
: <string> ( id -- component )
string new-string ;
2008-03-05 22:38:15 -05:00
2008-04-14 05:34:26 -04:00
M: string validate*
[ one-line>> [ v-one-line ] when ]
[ min-length>> [ v-min-length ] when* ]
[ max-length>> [ v-max-length ] when* ]
tri ;
2008-03-05 22:38:15 -05:00
2008-04-14 05:34:26 -04:00
M: string component-string
drop ;
2008-03-05 22:38:15 -05:00
2008-03-11 04:39:09 -04:00
! Username fields
2008-04-14 05:34:26 -04:00
TUPLE: username < string ;
M: username init
2 >>min-length
20 >>max-length ;
2008-03-05 22:38:15 -05:00
2008-03-11 04:39:09 -04:00
: <username> ( id -- component )
2008-04-14 05:34:26 -04:00
username new-string ;
2008-03-05 22:38:15 -05:00
2008-03-11 04:39:09 -04:00
M: username validate*
2008-04-14 05:34:26 -04:00
call-next-method v-one-word ;
2008-03-05 22:38:15 -05:00
2008-03-11 04:39:09 -04:00
! E-mail fields
2008-04-14 05:34:26 -04:00
TUPLE: email < string ;
2008-03-05 22:38:15 -05:00
2008-03-11 04:39:09 -04:00
: <email> ( id -- component )
2008-04-14 05:34:26 -04:00
email new-string
2008-03-11 04:39:09 -04:00
5 >>min-length
60 >>max-length ;
M: email validate*
2008-04-14 05:34:26 -04:00
call-next-method dup empty? [ v-email ] unless ;
! Don't send passwords back to the user
TUPLE: password-renderer < field ;
: password-renderer T{ password-renderer f "password" } ;
: blank-password >r >r drop "" r> r> ;
M: password-renderer render-edit*
blank-password call-next-method ;
2008-03-05 22:38:15 -05:00
2008-03-11 04:39:09 -04:00
! Password fields
2008-04-14 05:34:26 -04:00
TUPLE: password < string ;
M: password init
6 >>min-length
60 >>max-length ;
2008-03-05 22:38:15 -05:00
2008-03-11 04:39:09 -04:00
: <password> ( id -- component )
2008-04-14 05:34:26 -04:00
password new-string
password-renderer >>renderer ;
2008-03-05 22:38:15 -05:00
2008-03-11 04:39:09 -04:00
M: password validate*
2008-04-14 05:34:26 -04:00
call-next-method v-one-word ;
2008-03-11 04:39:09 -04:00
! Number fields
2008-04-14 05:34:26 -04:00
TUPLE: number < string min-value max-value ;
2008-03-05 22:38:15 -05:00
2008-04-14 05:34:26 -04:00
: <number> ( id -- component )
number new-string ;
2008-03-05 22:38:15 -05:00
M: number validate*
2008-03-11 04:39:09 -04:00
[ v-number ] [
[ min-value>> [ v-min-value ] when* ]
[ max-value>> [ v-max-value ] when* ]
2008-04-14 05:34:26 -04:00
bi
2008-03-11 04:39:09 -04:00
] bi* ;
2008-03-05 22:38:15 -05:00
2008-04-14 05:34:26 -04:00
M: number component-string
drop dup [ number>string ] when ;
2008-03-05 22:38:15 -05:00
2008-04-14 05:34:26 -04:00
! Integer fields
TUPLE: integer < number ;
2008-03-05 22:38:15 -05:00
2008-04-14 05:34:26 -04:00
: <integer> ( id -- component )
integer new-string ;
2008-03-05 22:38:15 -05:00
2008-04-14 05:34:26 -04:00
M: integer validate*
call-next-method v-integer ;
2008-03-05 22:38:15 -05:00
2008-04-14 05:34:26 -04:00
! Simple captchas
TUPLE: captcha < string ;
2008-03-14 18:40:47 -04:00
2008-04-14 05:34:26 -04:00
: <captcha> ( id -- component )
captcha new-string ;
2008-03-14 18:40:47 -04:00
2008-04-14 05:34:26 -04:00
M: captcha validate*
drop v-captcha ;
2008-03-05 22:38:15 -05:00
2008-04-14 05:34:26 -04:00
! Text areas
TUPLE: textarea-renderer ;
2008-03-05 22:38:15 -05:00
2008-04-14 05:34:26 -04:00
: textarea-renderer T{ textarea-renderer } ;
2008-03-11 04:39:09 -04:00
2008-04-14 05:34:26 -04:00
M: textarea-renderer render-view*
drop write ;
2008-03-11 04:39:09 -04:00
2008-04-14 05:34:26 -04:00
M: textarea-renderer render-edit*
drop <textarea [ =id ] [ =name ] bi textarea> write </textarea> ;
2008-03-11 04:39:09 -04:00
2008-04-14 05:34:26 -04:00
TUPLE: text < string ;
2008-03-05 22:38:15 -05:00
2008-04-14 05:34:26 -04:00
: new-text ( id class -- component )
new-string
f >>one-line
textarea-renderer >>renderer ;
: <text> ( id -- component )
text new-text ;