1 ! Copyright (C) 2003, 2008 Slava Pestov.
2 ! See http://factorcode.org/license.txt for BSD license.
3 USING: accessors arrays kernel combinators assocs
4 continuations namespaces sequences splitting words
5 vocabs.loader classes strings
6 fry urls multiline present
15 html.templates.chloe.syntax
18 http.server.redirection
21 QUALIFIED-WITH: assocs a
22 EXCLUDE: xml.utilities => children>string ;
25 : nested-responders ( -- seq )
26 responder-nesting get a:values ;
28 : each-responder ( quot -- )
29 nested-responders swap each ; inline
31 : base-path ( string -- pair )
32 dup responder-nesting get
33 [ second class word-name = ] with find nip
34 [ first ] [ "No such responder: " swap append throw ] ?if ;
36 : resolve-base-path ( string -- string' )
39 "/" split1 [ base-path [ "/" % % ] each "/" % ] dip %
43 : vocab-path ( vocab -- path )
44 dup vocab-dir vocab-append-path ;
46 : resolve-template-path ( pair -- path )
48 first2 [ word-vocabulary vocab-path % ] [ "/" % % ] bi*
51 GENERIC: modify-query ( query responder -- query' )
53 M: object modify-query drop ;
55 GENERIC: adjust-url ( url -- url' )
59 [ [ modify-query ] each-responder ] change-query
60 [ resolve-base-path ] change-path
63 M: string adjust-url ;
65 : <redirect> ( url -- response )
66 adjust-url request get method>> {
67 { "GET" [ <temporary-redirect> ] }
68 { "HEAD" [ <temporary-redirect> ] }
69 { "POST" [ <permanent-redirect> ] }
72 GENERIC: modify-form ( responder -- )
74 M: object modify-form drop ;
76 : request-params ( request -- assoc )
78 { "GET" [ url>> query>> ] }
79 { "HEAD" [ url>> query>> ] }
82 dup content-type>> "application/x-www-form-urlencoded" =
83 [ content>> ] [ drop f ] if
87 SYMBOL: exit-continuation
89 : exit-with ( value -- )
90 exit-continuation get continue-with ;
92 : with-exit-continuation ( quot -- )
93 '[ exit-continuation set @ ] callcc1 exit-continuation off ;
96 : parse-query-attr ( string -- assoc )
98 [ drop f ] [ "," split [ dup value ] H{ } map>assoc ] if ;
102 [ "href" required-attr ]
103 [ "query" optional-attr parse-query-attr ] tri
107 adjust-url relative-to-request
110 CHLOE: write-atom drop write-atom-feeds ;
112 GENERIC: link-attr ( tag responder -- )
114 M: object link-attr 2drop ;
116 : link-attrs ( tag -- )
117 '[ , _ link-attr ] each-responder ;
119 : a-start-tag ( tag -- )
123 dup "value" optional-attr [ value f ] [
124 [ "href" required-attr ]
125 [ "query" optional-attr parse-query-attr ]
131 adjust-url relative-to-request =href
137 [ process-tag-children ]
141 : hidden-form-field ( value name -- )
150 : form-nesting-key "__n" ;
152 : form-magic ( tag -- )
153 [ modify-form ] each-responder
154 nested-values get " " join f like form-nesting-key hidden-form-field
155 "for" optional-attr [ "," split [ hidden render ] each ] when* ;
157 : form-start-tag ( tag -- )
163 [ "action" required-attr resolve-base-path =action ]
164 [ tag-attrs non-chloe-attrs-only print-attrs ]
173 [ process-tag-children ]
177 STRING: button-tag-markup
178 <t:form class="inline" xmlns:t="http://factorcode.org/chloe/1.0">
179 <button type="submit"></button>
183 : add-tag-attrs ( attrs tag -- )
184 tag-attrs swap update ;
187 button-tag-markup string>xml delegate
189 [ [ tag-attrs chloe-attrs-only ] dip add-tag-attrs ]
190 [ [ tag-attrs non-chloe-attrs-only ] dip "button" tag-named add-tag-attrs ]
191 [ [ children>string 1array ] dip "button" tag-named set-tag-children ]
193 } 2cleave process-chloe-tag ;