134 lines
4.9 KiB
Scheme
134 lines
4.9 KiB
Scheme
#lang web-server/insta
|
|
|
|
;; A blog is a (make-blog posts)
|
|
;; where posts is a (listof post)
|
|
(define-struct blog (posts) #:mutable)
|
|
|
|
;; and post is a (make-post title body comments)
|
|
;; where title is a string, body is a string,
|
|
;; and comments is a (listof string)
|
|
(define-struct post (title body comments) #:mutable)
|
|
|
|
;; BLOG: blog
|
|
;; The initial BLOG.
|
|
(define BLOG
|
|
(make-blog
|
|
(list (make-post "First Post"
|
|
"This is my first post"
|
|
(list "First comment!"))
|
|
(make-post "Second Post"
|
|
"This is another post"
|
|
(list)))))
|
|
|
|
;; blog-insert-post!: blog post -> void
|
|
;; Consumes a blog and a post, adds the post at the top of the blog.
|
|
(define (blog-insert-post! a-blog a-post)
|
|
(set-blog-posts! a-blog
|
|
(cons a-post (blog-posts a-blog))))
|
|
|
|
|
|
;; post-insert-comment!: post string -> void
|
|
;; Consumes a post and a comment string. As a side-efect,
|
|
;; adds the comment to the bottom of the post's list of comments.
|
|
(define (post-insert-comment! a-post a-comment)
|
|
(set-post-comments!
|
|
a-post
|
|
(append (post-comments a-post) (list a-comment))))
|
|
|
|
;; start: request -> html-response
|
|
;; Consumes a request, and produces a page that displays
|
|
;; all of the web content.
|
|
(define (start request)
|
|
(render-blog-page request))
|
|
|
|
;; render-blog-page: request -> html-response
|
|
;; Produces an html-response page of the content of the
|
|
;; BLOG.
|
|
(define (render-blog-page request)
|
|
(local [(define (response-generator make-url)
|
|
`(html (head (title "My Blog"))
|
|
(body
|
|
(h1 "My Blog")
|
|
,(render-posts make-url)
|
|
(form ((action
|
|
,(make-url insert-post-handler)))
|
|
(input ((name "title")))
|
|
(input ((name "body")))
|
|
(input ((type "submit")))))))
|
|
|
|
;; parse-post: bindings -> post
|
|
;; Extracts a post out of the bindings.
|
|
(define (parse-post bindings)
|
|
(make-post (extract-binding/single 'title bindings)
|
|
(extract-binding/single 'body bindings)
|
|
(list)))
|
|
|
|
(define (insert-post-handler request)
|
|
(blog-insert-post!
|
|
BLOG (parse-post (request-bindings request)))
|
|
(render-blog-page request))]
|
|
|
|
(send/suspend/dispatch response-generator)))
|
|
|
|
;; render-post-detail-page: post request -> html-response
|
|
;; Consumes a post and request, and produces a detail page
|
|
;; of the post. The user will be able to insert new comments.
|
|
(define (render-post-detail-page a-post request)
|
|
(local [(define (response-generator make-url)
|
|
`(html (head (title "Post Details"))
|
|
(body
|
|
(h1 "Post Details")
|
|
(h2 ,(post-title a-post))
|
|
(p ,(post-body a-post))
|
|
,(render-as-itemized-list
|
|
(post-comments a-post))
|
|
(form ((action
|
|
,(make-url insert-comment-handler)))
|
|
(input ((name "comment")))
|
|
(input ((type "submit")))))))
|
|
|
|
(define (parse-comment bindings)
|
|
(extract-binding/single 'comment bindings))
|
|
|
|
(define (insert-comment-handler a-request)
|
|
(post-insert-comment!
|
|
a-post (parse-comment (request-bindings a-request)))
|
|
(render-post-detail-page a-post a-request))]
|
|
|
|
|
|
(send/suspend/dispatch response-generator)))
|
|
|
|
|
|
;; render-post: post (handler -> string) -> html-response
|
|
;; Consumes a post, produces an html-response fragment of the post.
|
|
;; The fragment contains a link to show a detailed view of the post.
|
|
(define (render-post a-post make-url)
|
|
(local [(define (view-post-handler request)
|
|
(render-post-detail-page a-post request))]
|
|
`(div ((class "post"))
|
|
(a ((href ,(make-url view-post-handler)))
|
|
,(post-title a-post))
|
|
(p ,(post-body a-post))
|
|
(div ,(number->string (length (post-comments a-post)))
|
|
" comment(s)"))))
|
|
|
|
;; render-posts: (handler -> string) -> html-response
|
|
;; Consumes a make-url, and produces an html-response fragment
|
|
;; of all its posts.
|
|
(define (render-posts make-url)
|
|
(local [(define (render-post/make-url a-post)
|
|
(render-post a-post make-url))]
|
|
`(div ((class "posts"))
|
|
,@(map render-post/make-url (blog-posts BLOG)))))
|
|
|
|
;; render-as-itemized-list: (listof html-response) -> html-response
|
|
;; Consumes a list of items, and produces a rendering as
|
|
;; an unorderered list.
|
|
(define (render-as-itemized-list fragments)
|
|
`(ul ,@(map render-as-item fragments)))
|
|
|
|
;; render-as-item: html-response -> html-response
|
|
;; Consumes an html-response, and produces a rendering
|
|
;; as a list item.
|
|
(define (render-as-item a-fragment)
|
|
`(li ,a-fragment)) |