diff --git a/extra/html/components/components-tests.factor b/extra/html/components/components-tests.factor index 6ecd2b0fa6..0bd5410a3b 100644 --- a/extra/html/components/components-tests.factor +++ b/extra/html/components/components-tests.factor @@ -60,7 +60,7 @@ TUPLE: color red green blue ; [ ] [ [ - "green" ; ! Choice -TUPLE: choice size choices multiple ; +TUPLE: choice size multiple choices ; : ( -- choice ) choice new ; @@ -112,7 +112,7 @@ M: choice render* dup size>> [ number>string =size ] when* dup multiple>> [ "true" =multiple ] when select> - [ choices>> ] [ multiple>> ] bi + [ choices>> value ] [ multiple>> ] bi [ swap ] [ swap 1array ] if render-options ; diff --git a/extra/http/server/templating/chloe/chloe-tests.factor b/extra/html/templates/chloe/chloe-tests.factor similarity index 84% rename from extra/http/server/templating/chloe/chloe-tests.factor rename to extra/html/templates/chloe/chloe-tests.factor index 61f72a2f14..3c52153eee 100644 --- a/extra/http/server/templating/chloe/chloe-tests.factor +++ b/extra/html/templates/chloe/chloe-tests.factor @@ -1,8 +1,8 @@ -USING: http.server.templating http.server.templating.chloe -http.server.components http.server.boilerplate tools.test -io.streams.string kernel sequences ascii boxes namespaces xml +USING: html.templates html.templates.chloe +tools.test io.streams.string kernel sequences ascii boxes +namespaces xml splitting ; -IN: http.server.templating.chloe.tests +IN: html.templates.chloe.tests [ f ] [ f parse-query-attr ] unit-test @@ -26,7 +26,7 @@ IN: http.server.templating.chloe.tests "?>" split1 nip ; inline : test-template ( name -- template ) - "resource:extra/http/server/templating/chloe/test/" + "resource:extra/html/templates/chloe/test/" swap ".xml" 3append ; diff --git a/extra/http/server/templating/chloe/chloe.factor b/extra/html/templates/chloe/chloe.factor similarity index 80% rename from extra/http/server/templating/chloe/chloe.factor rename to extra/html/templates/chloe/chloe.factor index c3d93f5909..a01d424eb9 100644 --- a/extra/http/server/templating/chloe/chloe.factor +++ b/extra/html/templates/chloe/chloe.factor @@ -3,13 +3,14 @@ USING: accessors kernel sequences combinators kernel namespaces classes.tuple assocs splitting words arrays memoize io io.files io.encodings.utf8 io.streams.string -unicode.case tuple-syntax html html.elements +unicode.case tuple-syntax mirrors fry multiline xml xml.data xml.writer xml.utilities +html.elements +html.components http.server http.server.auth http.server.flows http.server.actions -http.server.components http.server.sessions http.server.templating http.server.boilerplate ; @@ -52,8 +53,11 @@ MEMO: chloe-name ( string -- name ) : optional-attr ( tag name -- value ) chloe-name swap at ; +: process-tag-children ( tag -- ) + [ process-template ] each ; + : children>string ( tag -- string ) - [ [ process-template ] each ] with-string-writer ; + [ process-tag-children ] with-string-writer ; : title-tag ( tag -- ) children>string set-title ; @@ -89,18 +93,6 @@ MEMO: chloe-name ( string -- name ) atom-feed get value>> second write ] if ; -: component-attr ( tag -- name ) - "component" required-attr ; - -: view-tag ( tag -- ) - component-attr component render-view ; - -: edit-tag ( tag -- ) - component-attr component render-edit ; - -: summary-tag ( tag -- ) - component-attr component render-summary ; - : parse-query-attr ( string -- assoc ) dup empty? [ drop f ] [ "," split [ dup value ] H{ } map>assoc ] if ; @@ -133,9 +125,6 @@ MEMO: chloe-name ( string -- name ) a> ] with-scope ; -: process-tag-children ( tag -- ) - [ process-template ] each ; - : a-tag ( tag -- ) [ a-start-tag ] [ process-tag-children ] @@ -156,7 +145,7 @@ MEMO: chloe-name ( string -- name ) form> ] [ hidden-form-field - "for" optional-attr [ component render-edit ] when* + "for" optional-attr [ hidden render ] when* ] bi ] with-scope ; @@ -180,9 +169,9 @@ STRING: button-tag-markup : button-tag ( tag -- ) button-tag-markup string>xml delegate { - [ >r tag-attrs chloe-attrs-only r> add-tag-attrs ] - [ >r tag-attrs non-chloe-attrs-only r> "button" tag-named add-tag-attrs ] - [ >r children>string 1array r> "button" tag-named set-tag-children ] + [ [ tag-attrs chloe-attrs-only ] dip add-tag-attrs ] + [ [ tag-attrs non-chloe-attrs-only ] dip "button" tag-named add-tag-attrs ] + [ [ children>string 1array ] dip "button" tag-named set-tag-children ] [ nip ] } 2cleave process-chloe-tag ; @@ -211,27 +200,58 @@ STRING: button-tag-markup : error-message-tag ( tag -- ) children>string render-error ; +: validation-messages-tag ( tag -- ) + drop render-validation-messages ; + +: singleton-component-tag ( tag class -- ) + [ "name" required-attr ] dip render ; + +: attrs>slots ( tag tuple -- ) + [ attrs>> ] [ ] bi* '[ swap tag>> , set-at ] assoc-each ; + +: tuple-component-tag ( tag class -- ) + [ drop "name" required-attr ] + [ new [ attrs>slots ] keep ] + 2bi render ; + : process-chloe-tag ( tag -- ) dup name-tag { - { "chloe" [ [ process-template ] each ] } + { "chloe" [ process-tag-children ] } + + ! HTML head { "title" [ title-tag ] } { "write-title" [ write-title-tag ] } { "style" [ style-tag ] } { "write-style" [ write-style-tag ] } { "atom" [ atom-tag ] } { "write-atom" [ write-atom-tag ] } - { "view" [ view-tag ] } - { "edit" [ edit-tag ] } - { "summary" [ summary-tag ] } + + ! HTML elements { "a" [ a-tag ] } - { "form" [ form-tag ] } { "button" [ button-tag ] } + + ! Components + { "label" [ label singleton-component-tag ] } + { "link" [ link singleton-component-tag ] } + { "html" [ html singleton-component-tag ] } + + ! Forms + { "form" [ form-tag ] } { "error-message" [ error-message-tag ] } - { "validation-message" [ drop render-validation-message ] } + { "validation-messages" [ validation-messages-tag ] } + { "hidden" [ hidden singleton-component-tag ] } + { "field" [ field tuple-component-tag ] } + { "password" [ password tuple-component-tag ] } + { "textarea" [ textarea tuple-component-tag ] } + { "choice" [ choice tuple-component-tag ] } + { "checkbox" [ checkbox tuple-component-tag ] } + + ! Control flow { "if" [ if-tag ] } { "comment" [ drop ] } { "call-next-template" [ drop call-next-template ] } - [ "Unknown chloe tag: " swap append throw ] + + [ "Unknown chloe tag: " prepend throw ] } case ; : process-tag ( tag -- ) diff --git a/extra/http/server/templating/chloe/test/test1.xml b/extra/html/templates/chloe/test/test1.xml similarity index 100% rename from extra/http/server/templating/chloe/test/test1.xml rename to extra/html/templates/chloe/test/test1.xml diff --git a/extra/http/server/templating/chloe/test/test2.xml b/extra/html/templates/chloe/test/test2.xml similarity index 100% rename from extra/http/server/templating/chloe/test/test2.xml rename to extra/html/templates/chloe/test/test2.xml diff --git a/extra/http/server/templating/chloe/test/test3-aux.xml b/extra/html/templates/chloe/test/test3-aux.xml similarity index 100% rename from extra/http/server/templating/chloe/test/test3-aux.xml rename to extra/html/templates/chloe/test/test3-aux.xml diff --git a/extra/http/server/templating/chloe/test/test3.xml b/extra/html/templates/chloe/test/test3.xml similarity index 100% rename from extra/http/server/templating/chloe/test/test3.xml rename to extra/html/templates/chloe/test/test3.xml diff --git a/extra/http/server/templating/chloe/test/test4.xml b/extra/html/templates/chloe/test/test4.xml similarity index 62% rename from extra/http/server/templating/chloe/test/test4.xml rename to extra/html/templates/chloe/test/test4.xml index dd9b232d73..55612360a5 100644 --- a/extra/http/server/templating/chloe/test/test4.xml +++ b/extra/html/templates/chloe/test/test4.xml @@ -2,7 +2,7 @@ - + True diff --git a/extra/http/server/templating/chloe/test/test5.xml b/extra/html/templates/chloe/test/test5.xml similarity index 62% rename from extra/http/server/templating/chloe/test/test5.xml rename to extra/html/templates/chloe/test/test5.xml index 3bd39e45bd..edcbe8f3b1 100644 --- a/extra/http/server/templating/chloe/test/test5.xml +++ b/extra/html/templates/chloe/test/test5.xml @@ -2,7 +2,7 @@ - + True diff --git a/extra/http/server/templating/chloe/test/test6.xml b/extra/html/templates/chloe/test/test6.xml similarity index 62% rename from extra/http/server/templating/chloe/test/test6.xml rename to extra/html/templates/chloe/test/test6.xml index 56234a5f0d..b3f649333f 100644 --- a/extra/http/server/templating/chloe/test/test6.xml +++ b/extra/html/templates/chloe/test/test6.xml @@ -2,7 +2,7 @@ - + True diff --git a/extra/http/server/templating/chloe/test/test7.xml b/extra/html/templates/chloe/test/test7.xml similarity index 62% rename from extra/http/server/templating/chloe/test/test7.xml rename to extra/html/templates/chloe/test/test7.xml index a4f8e06e7d..338595e556 100644 --- a/extra/http/server/templating/chloe/test/test7.xml +++ b/extra/html/templates/chloe/test/test7.xml @@ -2,7 +2,7 @@ - + True diff --git a/extra/http/server/templating/fhtml/authors.txt b/extra/html/templates/fhtml/authors.txt similarity index 100% rename from extra/http/server/templating/fhtml/authors.txt rename to extra/html/templates/fhtml/authors.txt diff --git a/extra/http/server/templating/fhtml/fhtml-tests.factor b/extra/html/templates/fhtml/fhtml-tests.factor similarity index 74% rename from extra/http/server/templating/fhtml/fhtml-tests.factor rename to extra/html/templates/fhtml/fhtml-tests.factor index 42bec43570..43ea28fa55 100755 --- a/extra/http/server/templating/fhtml/fhtml-tests.factor +++ b/extra/html/templates/fhtml/fhtml-tests.factor @@ -1,10 +1,10 @@ USING: io io.files io.streams.string io.encodings.utf8 -http.server.templating http.server.templating.fhtml kernel +html.templates html.templates.fhtml kernel tools.test sequences parser ; -IN: http.server.templating.fhtml.tests +IN: html.templates.fhtml.tests : test-template ( path -- ? ) - "resource:extra/http/server/templating/fhtml/test/" + "resource:extra/html/templates/fhtml/test/" prepend [ ".fhtml" append [ call-template ] with-string-writer diff --git a/extra/http/server/templating/fhtml/fhtml.factor b/extra/html/templates/fhtml/fhtml.factor similarity index 62% rename from extra/http/server/templating/fhtml/fhtml.factor rename to extra/html/templates/fhtml/fhtml.factor index 2cc053a0ca..74e5c37ef1 100755 --- a/extra/http/server/templating/fhtml/fhtml.factor +++ b/extra/html/templates/fhtml/fhtml.factor @@ -4,12 +4,10 @@ USING: continuations sequences kernel namespaces debugger combinators math quotations generic strings splitting accessors assocs fry -parser io io.files io.streams.string io.encodings.utf8 source-files -html html.elements -http.server.static http.server http.server.templating ; -IN: http.server.templating.fhtml - -: templating-vocab ( -- vocab-name ) "http.server.templating.fhtml" ; +parser io io.files io.streams.string io.encodings.utf8 +html.elements +html.templates ; +IN: html.templates.fhtml ! We use a custom lexer so that %> ends a token even if not ! followed by whitespace @@ -35,7 +33,7 @@ DEFER: <% delimiter : found-<% ( accum lexer col -- accum ) [ over line-text>> - >r >r column>> r> r> subseq parsed + [ column>> ] 2dip subseq parsed \ write-html parsed ] 2keep 2 + >>column drop ; @@ -62,37 +60,20 @@ DEFER: <% delimiter : parse-template ( string -- quot ) [ - use [ clone ] change - templating-vocab use+ + "quiet" on + parser-notes off + "html.templates.fhtml" use+ string-lines parse-template-lines - ] with-scope ; + ] with-file-vocabs ; -: eval-template ( string -- ) parse-template call ; - -: html-error. ( error -- ) -
 error. 
; +: eval-template ( string -- ) + parse-template call ; TUPLE: fhtml path ; C: fhtml M: fhtml call-template* ( filename -- ) - '[ - , path>> [ - "quiet" on - parser-notes off - templating-vocab use+ - ! so that reload works properly - dup source-file file set - utf8 file-contents - [ eval-template ] [ html-error. drop ] recover - ] with-file-vocabs - ] assert-depth ; - -! file responder integration -: enable-fhtml ( responder -- responder ) - [ serve-template ] - "application/x-factor-server-page" - pick special>> set-at ; + '[ , path>> utf8 file-contents eval-template ] assert-depth ; INSTANCE: fhtml template diff --git a/extra/http/server/templating/fhtml/test/bug.fhtml b/extra/html/templates/fhtml/test/bug.fhtml similarity index 100% rename from extra/http/server/templating/fhtml/test/bug.fhtml rename to extra/html/templates/fhtml/test/bug.fhtml diff --git a/extra/http/server/templating/fhtml/test/bug.html b/extra/html/templates/fhtml/test/bug.html similarity index 100% rename from extra/http/server/templating/fhtml/test/bug.html rename to extra/html/templates/fhtml/test/bug.html diff --git a/extra/http/server/templating/fhtml/test/example.fhtml b/extra/html/templates/fhtml/test/example.fhtml similarity index 100% rename from extra/http/server/templating/fhtml/test/example.fhtml rename to extra/html/templates/fhtml/test/example.fhtml diff --git a/extra/http/server/templating/fhtml/test/example.html b/extra/html/templates/fhtml/test/example.html similarity index 100% rename from extra/http/server/templating/fhtml/test/example.html rename to extra/html/templates/fhtml/test/example.html diff --git a/extra/http/server/templating/fhtml/test/stack.fhtml b/extra/html/templates/fhtml/test/stack.fhtml similarity index 100% rename from extra/http/server/templating/fhtml/test/stack.fhtml rename to extra/html/templates/fhtml/test/stack.fhtml diff --git a/extra/http/server/templating/fhtml/test/stack.html b/extra/html/templates/fhtml/test/stack.html similarity index 100% rename from extra/http/server/templating/fhtml/test/stack.html rename to extra/html/templates/fhtml/test/stack.html diff --git a/extra/html/templates/templates.factor b/extra/html/templates/templates.factor new file mode 100644 index 0000000000..ed26c9b531 --- /dev/null +++ b/extra/html/templates/templates.factor @@ -0,0 +1,85 @@ +! Copyright (C) 2008 Slava Pestov. +! See http://factorcode.org/license.txt for BSD license. +USING: accessors kernel fry io io.encodings.utf8 io.files +debugger prettyprint continuations namespaces boxes sequences +arrays strings html.elements io.streams.string quotations ; +IN: html.templates + +MIXIN: template + +GENERIC: call-template* ( template -- ) + +M: string call-template* write ; + +M: callable call-template* call ; + +M: object call-template* output-stream get stream-copy ; + +ERROR: template-error template error ; + +M: template-error error. + "Error while processing template " write + [ template>> pprint ":" print nl ] + [ error>> error. ] + bi ; + +: call-template ( template -- ) + [ call-template* ] [ template-error ] recover ; + +SYMBOL: title + +: set-title ( string -- ) + title get >box ; + +: write-title ( -- ) + title get value>> write ; + +SYMBOL: style + +: add-style ( string -- ) + "\n" style get push-all + style get push-all ; + +: write-style ( -- ) + style get >string write ; + +SYMBOL: atom-feed + +: set-atom-feed ( title url -- ) + 2array atom-feed get >box ; + +: write-atom-feed ( -- ) + atom-feed get value>> [ + + ] when* ; + +SYMBOL: nested-template? + +SYMBOL: next-template + +: call-next-template ( -- ) + next-template get write-html ; + +M: f call-template* drop call-next-template ; + +: with-boilerplate ( body template -- ) + [ + title get [ title set ] unless + atom-feed get [ atom-feed set ] unless + style get [ SBUF" " clone style set ] unless + + [ + [ + nested-template? on + call-template + ] with-string-writer + next-template set + ] + [ call-template ] + bi* + ] with-scope ; inline + +: template-convert ( template output -- ) + utf8 [ call-template ] with-file-writer ; diff --git a/extra/http/server/templating/templating.factor b/extra/http/server/templating/templating.factor deleted file mode 100644 index 73f6095eae..0000000000 --- a/extra/http/server/templating/templating.factor +++ /dev/null @@ -1,27 +0,0 @@ -USING: accessors kernel fry io io.encodings.utf8 io.files -http http.server debugger prettyprint continuations ; -IN: http.server.templating - -MIXIN: template - -GENERIC: call-template* ( template -- ) - -ERROR: template-error template error ; - -M: template-error error. - "Error while processing template " write - [ template>> pprint ":" print nl ] - [ error>> error. ] - bi ; - -: call-template ( template -- ) - [ call-template* ] [ template-error ] recover ; - -M: template write-response-body* call-template ; - -: template-convert ( template output -- ) - utf8 [ call-template ] with-file-writer ; - -! responder integration -: serve-template ( template -- response ) - '[ , call-template ] ; diff --git a/extra/validators/validators.factor b/extra/validators/validators.factor index 9d6c4bed90..b03cc76444 100644 --- a/extra/validators/validators.factor +++ b/extra/validators/validators.factor @@ -122,12 +122,7 @@ C: validation-error [ swap validation-error-for f ] recover ; inline : validate-value ( value name validators -- result ) - '[ - , at { - { [ dup pair? ] [ first ] } - { [ dup quotation? ] [ ] } - } cond call - ] validate ; + '[ , at call ] validate ; : required-values ( assoc -- ) [ swap [ drop v-required ] validate drop ] assoc-each ;