1 ! Copyright (C) 2008 Slava Pestov.
2 ! See http://factorcode.org/license.txt for BSD license.
3 USING: accessors kernel sequences combinators kernel namespaces
4 classes.tuple assocs splitting words arrays memoize
5 io io.files io.encodings.utf8 io.streams.string
6 unicode.case tuple-syntax mirrors fry math urls present
7 multiline xml xml.data xml.writer xml.utilities
12 html.templates.chloe.syntax ;
13 IN: html.templates.chloe
15 ! Chloe is Ed's favorite web designer
22 DEFER: process-template
24 : chloe-attrs-only ( assoc -- assoc' )
25 [ drop url>> chloe-ns = ] assoc-filter ;
27 : non-chloe-attrs-only ( assoc -- assoc' )
28 [ drop url>> chloe-ns = not ] assoc-filter ;
30 : chloe-tag? ( tag -- ? )
31 dup xml? [ body>> ] when
33 { [ dup tag? not ] [ f ] }
34 { [ dup url>> chloe-ns = not ] [ f ] }
38 : process-tag-children ( tag -- )
39 [ process-template ] each ;
41 CHLOE: chloe process-tag-children ;
43 : children>string ( tag -- string )
44 [ process-tag-children ] with-string-writer ;
46 CHLOE: title children>string set-title ;
50 "head" tag-stack get member?
51 "title" tag-stack get member? not and
52 [ <title> write-title </title> ] [ write-title ] if ;
55 dup "include" optional-attr dup [
56 swap children>string empty? [
57 "style tag cannot have both an include attribute and a body" throw
65 drop <style> write-style </style> ;
67 CHLOE: even "index" value even? [ process-tag-children ] [ drop ] if ;
69 CHLOE: odd "index" value odd? [ process-tag-children ] [ drop ] if ;
71 : (bind-tag) ( tag quot -- )
73 [ "name" required-attr ] keep
74 '[ , process-tag-children ]
77 CHLOE: each [ with-each-value ] (bind-tag) ;
79 CHLOE: bind-each [ with-each-object ] (bind-tag) ;
81 CHLOE: bind [ with-form ] (bind-tag) ;
83 : error-message-tag ( tag -- )
84 children>string render-error ;
88 CHLOE: call-next-template drop call-next-template ;
90 : attr>word ( value -- word/f )
91 ":" split1 swap lookup ;
93 : if-satisfied? ( tag -- ? )
94 [ "code" optional-attr [ attr>word dup [ execute ] when ] [ t ] if* ]
95 [ "value" optional-attr [ value ] [ t ] if* ]
98 CHLOE: if dup if-satisfied? [ process-tag-children ] [ drop ] if ;
100 CHLOE-SINGLETON: label
101 CHLOE-SINGLETON: link
102 CHLOE-SINGLETON: inspector
103 CHLOE-SINGLETON: comparison
104 CHLOE-SINGLETON: html
105 CHLOE-SINGLETON: hidden
109 CHLOE-TUPLE: textarea
110 CHLOE-TUPLE: password
112 CHLOE-TUPLE: checkbox
115 : process-chloe-tag ( tag -- )
116 dup main>> dup tags get at
117 [ call ] [ "Unknown chloe tag: " prepend throw ] ?if ;
119 : process-tag ( tag -- )
121 [ main>> >lower tag-stack get push ]
123 [ process-tag-children ]
125 [ drop tag-stack get pop* ]
128 : expand-attrs ( tag -- tag )
129 dup [ tag? ] [ xml? ] bi or [
131 [ "@" ?head [ value present ] when ] assoc-map
135 : process-template ( xml -- )
138 { [ dup chloe-tag? ] [ process-chloe-tag ] }
139 { [ dup [ tag? ] [ xml? ] bi or ] [ process-tag ] }
140 { [ t ] [ write-item ] }
143 : process-chloe ( xml -- )
145 V{ } clone tag-stack set
147 nested-template? get [
151 [ prolog>> write-prolog ]
152 [ before>> write-chunk ]
154 [ after>> write-chunk ]
159 M: chloe call-template*
160 path>> ".xml" append utf8 <file-reader> read-xml process-chloe ;
162 INSTANCE: chloe template