/collects/web-server/scribblings/tutorial/examples/iteration-6.rkt

http://github.com/gmarceau/PLT · Racket · 171 lines · 104 code · 25 blank · 42 comment · 2 complexity · b48dbbe9fbc89baac64075d3769e5d30 MD5 · raw file

  1. #lang web-server/insta
  2. ;; A blog is a (make-blog posts)
  3. ;; where posts is a (listof post)
  4. (struct blog (posts) #:mutable)
  5. ;; and post is a (make-post title body comments)
  6. ;; where title is a string, body is a string,
  7. ;; and comments is a (listof string)
  8. (struct post (title body comments) #:mutable)
  9. ;; BLOG: blog
  10. ;; The initial BLOG.
  11. (define BLOG
  12. (blog
  13. (list (post "First Post"
  14. "This is my first post"
  15. (list "First comment!"))
  16. (post "Second Post"
  17. "This is another post"
  18. (list)))))
  19. ;; blog-insert-post!: blog post -> void
  20. ;; Consumes a blog and a post, adds the post at the top of the blog.
  21. (define (blog-insert-post! a-blog a-post)
  22. (set-blog-posts! a-blog
  23. (cons a-post (blog-posts a-blog))))
  24. ;; post-insert-comment!: post string -> void
  25. ;; Consumes a post and a comment string. As a side-efect,
  26. ;; adds the comment to the bottom of the post's list of comments.
  27. (define (post-insert-comment! a-post a-comment)
  28. (set-post-comments!
  29. a-post
  30. (append (post-comments a-post) (list a-comment))))
  31. ;; start: request -> doesn't return
  32. ;; Consumes a request and produces a page that displays
  33. ;; all of the web content.
  34. (define (start request)
  35. (render-blog-page request))
  36. ;; render-blog-page: request -> doesn't return
  37. ;; Produces an HTML page of the content of the
  38. ;; BLOG.
  39. (define (render-blog-page request)
  40. (local [(define (response-generator make-url)
  41. (response/xexpr
  42. `(html (head (title "My Blog"))
  43. (body
  44. (h1 "My Blog")
  45. ,(render-posts make-url)
  46. (form ((action
  47. ,(make-url insert-post-handler)))
  48. (input ((name "title")))
  49. (input ((name "body")))
  50. (input ((type "submit"))))))))
  51. ;; parse-post: bindings -> post
  52. ;; Extracts a post out of the bindings.
  53. (define (parse-post bindings)
  54. (post (extract-binding/single 'title bindings)
  55. (extract-binding/single 'body bindings)
  56. (list)))
  57. (define (insert-post-handler request)
  58. (blog-insert-post!
  59. BLOG (parse-post (request-bindings request)))
  60. (render-blog-page request))]
  61. (send/suspend/dispatch response-generator)))
  62. ;; render-post-detail-page: post request -> doesn't return
  63. ;; Consumes a post and produces a detail page of the post.
  64. ;; The user will be able to either insert new comments
  65. ;; or go back to render-blog-page.
  66. (define (render-post-detail-page a-post request)
  67. (local [(define (response-generator make-url)
  68. (response/xexpr
  69. `(html (head (title "Post Details"))
  70. (body
  71. (h1 "Post Details")
  72. (h2 ,(post-title a-post))
  73. (p ,(post-body a-post))
  74. ,(render-as-itemized-list
  75. (post-comments a-post))
  76. (form ((action
  77. ,(make-url insert-comment-handler)))
  78. (input ((name "comment")))
  79. (input ((type "submit"))))
  80. (a ((href ,(make-url back-handler)))
  81. "Back to the blog")))))
  82. (define (parse-comment bindings)
  83. (extract-binding/single 'comment bindings))
  84. (define (insert-comment-handler request)
  85. (render-confirm-add-comment-page
  86. (parse-comment (request-bindings request))
  87. a-post
  88. request))
  89. (define (back-handler request)
  90. (render-blog-page request))]
  91. (send/suspend/dispatch response-generator)))
  92. ;; render-confirm-add-comment-page :
  93. ;; comment post request -> doesn't return
  94. ;; Consumes a comment that we intend to add to a post, as well
  95. ;; as the request. If the user follows through, adds a comment
  96. ;; and goes back to the display page. Otherwise, goes back to
  97. ;; the detail page of the post.
  98. (define (render-confirm-add-comment-page a-comment a-post request)
  99. (local [(define (response-generator make-url)
  100. (response/xexpr
  101. `(html (head (title "Add a Comment"))
  102. (body
  103. (h1 "Add a Comment")
  104. "The comment: " (div (p ,a-comment))
  105. "will be added to "
  106. (div ,(post-title a-post))
  107. (p (a ((href ,(make-url yes-handler)))
  108. "Yes, add the comment."))
  109. (p (a ((href ,(make-url cancel-handler)))
  110. "No, I changed my mind!"))))))
  111. (define (yes-handler request)
  112. (post-insert-comment! a-post a-comment)
  113. (render-post-detail-page a-post request))
  114. (define (cancel-handler request)
  115. (render-post-detail-page a-post request))]
  116. (send/suspend/dispatch response-generator)))
  117. ;; render-post: post (handler -> string) -> xexpr
  118. ;; Consumes a post, produces an xexpr fragment of the post.
  119. ;; The fragment contains a link to show a detailed view of the post.
  120. (define (render-post a-post make-url)
  121. (local [(define (view-post-handler request)
  122. (render-post-detail-page a-post request))]
  123. `(div ((class "post"))
  124. (a ((href ,(make-url view-post-handler)))
  125. ,(post-title a-post))
  126. (p ,(post-body a-post))
  127. (div ,(number->string (length (post-comments a-post)))
  128. " comment(s)"))))
  129. ;; render-posts: (handler -> string) -> xexpr
  130. ;; Consumes a make-url, produces an xexpr fragment
  131. ;; of all its posts.
  132. (define (render-posts make-url)
  133. (local [(define (render-post/make-url a-post)
  134. (render-post a-post make-url))]
  135. `(div ((class "posts"))
  136. ,@(map render-post/make-url (blog-posts BLOG)))))
  137. ;; render-as-itemized-list: (listof xexpr) -> xexpr
  138. ;; Consumes a list of items, and produces a rendering as
  139. ;; an unorderered list.
  140. (define (render-as-itemized-list fragments)
  141. `(ul ,@(map render-as-item fragments)))
  142. ;; render-as-item: xexpr -> xexpr
  143. ;; Consumes an xexpr, and produces a rendering
  144. ;; as a list item.
  145. (define (render-as-item a-fragment)
  146. `(li ,a-fragment))