#lang web-server/insta (require web-server/formlets "model-3.rkt") ;; start: request -> doesn't return ;; Consumes a request and produces a page that displays ;; all of the web content. (define (start request) (render-blog-page (initialize-blog! (build-path (current-directory) "the-blog-data.sqlite")) request)) ;; new-post-formlet : formlet (values string? string?) ;; A formlet for requesting a title and body of a post (define new-post-formlet (formlet (#%# ,{input-string . => . title} ,{input-string . => . body}) (values title body))) ;; render-blog-page: blog request -> doesn't return ;; Produces an HTML page of the content of the ;; blog. (define (render-blog-page a-blog request) (local [(define (response-generator embed/url) (response/xexpr `(html (head (title "My Blog")) (body (h1 "My Blog") ,(render-posts a-blog embed/url) (form ([action ,(embed/url insert-post-handler)]) ,@(formlet-display new-post-formlet) (input ([type "submit"]))))))) (define (insert-post-handler request) (define-values (title body) (formlet-process new-post-formlet request)) (blog-insert-post! a-blog title body) (render-blog-page a-blog (redirect/get)))] (send/suspend/dispatch response-generator))) ;; new-comment-formlet : formlet string ;; A formlet for requesting a comment (define new-comment-formlet input-string) ;; render-post-detail-page: post request -> doesn't return ;; Consumes a post and produces a detail page of the post. ;; The user will be able to either insert new comments ;; or go back to render-blog-page. (define (render-post-detail-page a-blog a-post request) (local [(define (response-generator embed/url) (response/xexpr `(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 ,(embed/url insert-comment-handler)]) ,@(formlet-display new-comment-formlet) (input ([type "submit"]))) (a ([href ,(embed/url back-handler)]) "Back to the blog"))))) (define (insert-comment-handler request) (render-confirm-add-comment-page a-blog (formlet-process new-comment-formlet request) a-post request)) (define (back-handler request) (render-blog-page a-blog request))] (send/suspend/dispatch response-generator))) ;; render-confirm-add-comment-page : ;; blog comment post request -> doesn't return ;; Consumes a comment that we intend to add to a post, as well ;; as the request. If the user follows through, adds a comment ;; and goes back to the display page. Otherwise, goes back to ;; the detail page of the post. (define (render-confirm-add-comment-page a-blog a-comment a-post request) (local [(define (response-generator embed/url) (response/xexpr `(html (head (title "Add a Comment")) (body (h1 "Add a Comment") "The comment: " (div (p ,a-comment)) "will be added to " (div ,(post-title a-post)) (p (a ([href ,(embed/url yes-handler)]) "Yes, add the comment.")) (p (a ([href ,(embed/url cancel-handler)]) "No, I changed my mind!")))))) (define (yes-handler request) (post-insert-comment! a-blog a-post a-comment) (render-post-detail-page a-blog a-post (redirect/get))) (define (cancel-handler request) (render-post-detail-page a-blog a-post request))] (send/suspend/dispatch response-generator))) ;; render-post: post (handler -> string) -> xexpr ;; Consumes a post, produces an xexpr fragment of the post. ;; The fragment contains a link to show a detailed view of the post. (define (render-post a-blog a-post embed/url) (local [(define (view-post-handler request) (render-post-detail-page a-blog a-post request))] `(div ([class "post"]) (a ([href ,(embed/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: blog (handler -> string) -> xexpr ;; Consumes a embed/url, produces an xexpr fragment ;; of all its posts. (define (render-posts a-blog embed/url) (local [(define (render-post/embed/url a-post) (render-post a-blog a-post embed/url))] `(div ([class "posts"]) ,@(map render-post/embed/url (blog-posts a-blog))))) ;; render-as-itemized-list: (listof xexpr) -> xexpr ;; 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: xexpr -> xexpr ;; Consumes an xexpr, and produces a rendering ;; as a list item. (define (render-as-item a-fragment) `(li ,a-fragment))