diff --git a/collects/tests/web-server/template/examples/blog-posted.html b/collects/tests/web-server/template/examples/blog-posted.html
new file mode 100644
index 0000000000..b3284cdd9e
--- /dev/null
+++ b/collects/tests/web-server/template/examples/blog-posted.html
@@ -0,0 +1,4 @@
+
@|title|
+@|body|
+
+
\ No newline at end of file
diff --git a/collects/tests/web-server/template/examples/blog-posts.html b/collects/tests/web-server/template/examples/blog-posts.html
new file mode 100644
index 0000000000..669399ac7c
--- /dev/null
+++ b/collects/tests/web-server/template/examples/blog-posts.html
@@ -0,0 +1,16 @@
+@in[p posts]{
+ @(post-title p)
+ @(post-body p)
+
+ @in[c (post-comments p)]{
+ - @|c|
+ }
+
+}
+
+New Post
+
diff --git a/collects/tests/web-server/template/examples/blog-xexpr.ss b/collects/tests/web-server/template/examples/blog-xexpr.ss
new file mode 100644
index 0000000000..807b7c4a62
--- /dev/null
+++ b/collects/tests/web-server/template/examples/blog-xexpr.ss
@@ -0,0 +1,93 @@
+#lang scheme
+(require web-server/servlet
+ xml
+ web-server/servlet-env)
+
+(define-struct post (title body comments))
+
+(define posts
+ (list
+ (make-post
+ "(Y Y) Works: The Why of Y"
+ "..."
+ (list
+ "First post! - A.T."
+ "Didn't I write this? - Matthias"))
+ (make-post
+ "Church and the States"
+ "As you may know, I grew up in DC, not technically a state..."
+ (list
+ "Finally, A Diet That Really Works! As Seen On TV"))))
+
+(define (template section body)
+ `(html
+ (head (title "Alonzo's Church: " ,section)
+ (style ([type "text/css"])
+ ,(make-cdata #f #f "
+ body {
+ margin: 0px;
+ padding: 10px;
+ }
+
+ #main {
+ background: #dddddd;
+ }")))
+ (body
+ (script ([type "text/javascript"])
+ ,(make-cdata #f #f "
+ var gaJsHost = ((\"https:\" == document.location.protocol) ?
+ \"https://ssl.\" : \"http://www.\");
+ document.write(unescape(\"%3Cscript src='\" + gaJsHost +
+ \"google-analytics.com/ga.js' type='text/javascript'%3E%3C/script%3E\"));
+"))
+ (script ([type "text/javascript"])
+ ,(make-cdata #f #f "
+ var pageTracker = _gat._getTracker(\"UA-YYYYYYY-Y\");
+ pageTracker._trackPageview();
+"))
+
+ (h1 "Alonzo's Church: " ,section)
+ (div ([id "main"])
+ ,@body))))
+
+(define (blog-posted title body k-url)
+ `((h2 ,title)
+ (p ,body)
+ (h1 (a ([href ,k-url]) "Continue"))))
+
+(define (extract-post req)
+ (define title (extract-binding/single 'title (request-bindings req)))
+ (define body (extract-binding/single 'body (request-bindings req)))
+ (set! posts
+ (list* (make-post title body empty)
+ posts))
+ (send/suspend
+ (lambda (k-url)
+ (template "Posted" (blog-posted title body k-url))))
+ (display-posts))
+
+(define (blog-posts k-url)
+ (append
+ (apply append
+ (for/list ([p posts])
+ `((h2 ,(post-title p))
+ (p ,(post-body p))
+ (ul
+ ,@(for/list ([c (post-comments p)])
+ `(li ,c))))))
+ `((h1 "New Post")
+ (form ([action ,k-url])
+ (input ([name "title"]))
+ (input ([name "body"]))
+ (input ([type "submit"]))))))
+
+(define (display-posts)
+ (extract-post
+ (send/suspend
+ (lambda (k-url)
+ (template "Posts" (blog-posts k-url))))))
+
+(define (start req)
+ (display-posts))
+
+(serve/servlet start)
diff --git a/collects/tests/web-server/template/examples/blog.html b/collects/tests/web-server/template/examples/blog.html
new file mode 100644
index 0000000000..c5dc3f41bd
--- /dev/null
+++ b/collects/tests/web-server/template/examples/blog.html
@@ -0,0 +1,32 @@
+
+
+ Alonzo's Church: @|section|
+
+
+
+
+
+
+ Alonzo's Church: @|section|
+
+ @body
+
+
+
diff --git a/collects/tests/web-server/template/examples/blog.ss b/collects/tests/web-server/template/examples/blog.ss
new file mode 100644
index 0000000000..34e0c12a82
--- /dev/null
+++ b/collects/tests/web-server/template/examples/blog.ss
@@ -0,0 +1,46 @@
+#lang scheme
+(require web-server/templates
+ web-server/servlet
+ web-server/servlet-env)
+
+(define-struct post (title body comments))
+
+(define posts
+ (list
+ (make-post
+ "(Y Y) Works: The Why of Y"
+ "..."
+ (list
+ "First post! - A.T."
+ "Didn't I write this? - Matthias"))
+ (make-post
+ "Church and the States"
+ "As you may know, I grew up in DC, not technically a state..."
+ (list
+ "Finally, A Diet That Really Works! As Seen On TV"))))
+
+(define (template section body)
+ (list TEXT/HTML-MIME-TYPE
+ (include-template "blog.html")))
+
+(define (extract-post req)
+ (define title (extract-binding/single 'title (request-bindings req)))
+ (define body (extract-binding/single 'body (request-bindings req)))
+ (set! posts
+ (list* (make-post title body empty)
+ posts))
+ (send/suspend
+ (lambda (k-url)
+ (template "Posted" (include-template "blog-posted.html"))))
+ (display-posts))
+
+(define (display-posts)
+ (extract-post
+ (send/suspend
+ (lambda (k-url)
+ (template "Posts" (include-template "blog-posts.html"))))))
+
+(define (start req)
+ (display-posts))
+
+(serve/servlet start)
diff --git a/collects/web-server/scribblings/templates.scrbl b/collects/web-server/scribblings/templates.scrbl
index a42b233b04..f202eee7ad 100644
--- a/collects/web-server/scribblings/templates.scrbl
+++ b/collects/web-server/scribblings/templates.scrbl
@@ -2,11 +2,13 @@
@(require "web-server.ss")
@(require (for-label web-server/servlet
web-server/templates
+ scheme/promise
scheme/list
xml))
@(define xexpr @tech[#:doc '(lib "xml/xml.scrbl")]{X-expression})
@(define at-reader-ref @secref[#:doc '(lib "scribblings/scribble/scribble.scrbl")]{reader})
+@(define text-ref @secref[#:doc '(lib "scribblings/scribble/scribble.scrbl")]{preprocessor})
@title[#:tag "templates"]{Templates}
@@ -15,6 +17,9 @@
The @web-server provides a powerful Web template system for separating the presentation logic of a Web application
and enabling non-programmers to contribute to PLT-based Web applications.
+@margin-note{Although all the examples here generate HTML, the template language and the @text-ref it is based on can
+ be used to generate any text-based format: C, SQL, form emails, reports, etc.}
+
@local-table-of-contents[]
@section{Static}
@@ -62,8 +67,8 @@ Then
]
evaluates to the same content as the static example.
-There is no constraints on the values, the way they are used, or the way they are defined, that are made accessible to the template.
-For example,
+There are no constraints on how the lexical context of the template is populated. For instance, you can built template abstractions
+by wrapping the inclusion of a template in a function:
@schemeblock[
(define (fast-template thing)
(include-template "simple.html"))
@@ -94,18 +99,71 @@ and