further decoupling of state from the view
don't pass state objects to the view. don't construct urls in the view. the controller is to prepare a view based on request parameters, session state, data model
This commit is contained in:
parent
d51647c671
commit
567de507f5
@ -25,18 +25,25 @@
|
|||||||
(defroutes app-routes
|
(defroutes app-routes
|
||||||
(GET "/" request (views/index-page request))
|
(GET "/" request (views/index-page request))
|
||||||
|
|
||||||
(GET "/login" [] (views/login-page))
|
(GET "/login" []
|
||||||
|
(views/main-template
|
||||||
|
{:title "Login"}
|
||||||
|
(-> (views/login-form ["/bookmarks"] false)
|
||||||
|
(views/login-page))))
|
||||||
|
|
||||||
(POST "/login" [username password next :as {session :session}]
|
(POST "/login" [username password next :as {session :session}]
|
||||||
(let [resp-cookies (client/login-response username password session)]
|
(let [resp-cookies (client/login-response username password session)]
|
||||||
{:status 302
|
{:status 302
|
||||||
:headers {"Location" next}
|
:headers {"Location" next}
|
||||||
:session (assoc session :cookies resp-cookies)}))
|
:session (assoc session :cookies resp-cookies :loggedin true)}))
|
||||||
|
|
||||||
(GET "/bookmarks" [page :<< as-int
|
(GET "/bookmarks" [page :<< as-int
|
||||||
:as {session :session}]
|
:as {session :session}]
|
||||||
(let [beems (get-bookmarks session page)]
|
(if (get session :loggedin)
|
||||||
(views/bookmarks-page beems)))
|
(let [beems (get-bookmarks session page)]
|
||||||
|
(views/bookmarks-page beems))
|
||||||
|
{:status 302
|
||||||
|
:headers {"Location" "/login"}}))
|
||||||
|
|
||||||
(GET "/bookmarks" []
|
(GET "/bookmarks" []
|
||||||
{:status 302 :headers {"Location" "/bookmarks?page=1"}})
|
{:status 302 :headers {"Location" "/bookmarks?page=1"}})
|
||||||
@ -44,8 +51,17 @@
|
|||||||
(GET "/thread/:id" [id :<< as-int
|
(GET "/thread/:id" [id :<< as-int
|
||||||
page :<< as-int
|
page :<< as-int
|
||||||
:as {session :session}]
|
:as {session :session}]
|
||||||
(let [thread (get-thread session id page)]
|
(let [thread (get-thread session id page)
|
||||||
(views/thread-page thread)))
|
{:keys [id page page-count title]} thread
|
||||||
|
login-part (views/login-form
|
||||||
|
["/thread/%d?page=%d" id page]
|
||||||
|
(get session :loggedin false))
|
||||||
|
header-part (views/header-fragment login-part)
|
||||||
|
thread-part (views/thread-page thread)
|
||||||
|
paginate-part (views/paginate
|
||||||
|
(str "/thread/" id) page page-count)]
|
||||||
|
(views/main-template {:title title}
|
||||||
|
header-part thread-part paginate-part)))
|
||||||
|
|
||||||
(GET "/thread/:id" [id]
|
(GET "/thread/:id" [id]
|
||||||
{:status 302 :headers {"Location" (str "/thread/" id "?page=1")}})
|
{:status 302 :headers {"Location" (str "/thread/" id "?page=1")}})
|
||||||
|
@ -5,44 +5,43 @@
|
|||||||
[ring.util.anti-forgery :refer [anti-forgery-field]]))
|
[ring.util.anti-forgery :refer [anti-forgery-field]]))
|
||||||
|
|
||||||
|
|
||||||
(def ^:dynamic *thread* {})
|
(defn login-form [next loggedin]
|
||||||
|
(if loggedin
|
||||||
|
[:a.navbar-item "Logout"]
|
||||||
|
[:div.navbar-item.has-dropdown.is-hoverable
|
||||||
|
[:a.navbar-link "Login"]
|
||||||
|
[:div.navbar-dropdown.is-right
|
||||||
|
[:div.navbar-item
|
||||||
|
[:form#login-form {:action "/login" :method "post"}
|
||||||
|
(anti-forgery-field)
|
||||||
|
[:input {:type "hidden" :name "next"
|
||||||
|
:value (apply format next)}]
|
||||||
|
[:div.field
|
||||||
|
[:label.label {:for "username"} "username"]
|
||||||
|
[:div.control
|
||||||
|
[:input#username.input {:name "username" :type "text"
|
||||||
|
:placeholder "enter your username"}]]]
|
||||||
|
[:div.field
|
||||||
|
[:label.label {:for "password"} "password"]
|
||||||
|
[:div.control
|
||||||
|
[:input#password.input {:name "password" :type "password"
|
||||||
|
:placeholder "enter your password"}]]]
|
||||||
|
[:div.field
|
||||||
|
[:div.control
|
||||||
|
[:button.button.is-primary "Submit"]]]]]]]))
|
||||||
|
|
||||||
(defn login-form []
|
(defn header-fragment [login]
|
||||||
[:form#login-form {:action "/login" :method "post"}
|
[:nav.navbar.is-transparent
|
||||||
(anti-forgery-field)
|
[:div.navbar-brand
|
||||||
[:input {:type "hidden" :name "next"
|
[:a.burger.navbar-burger {:role "button" :data-target "mainNav"}
|
||||||
:value (format "/thread/%d?page=%d" (:id *thread*) (:page *thread*))}]
|
(repeat 3 [:span {:aria-hidden "true"}])]]
|
||||||
[:div.field
|
[:div#mainNav.navbar-menu
|
||||||
[:label.label {:for "username"} "username"]
|
[:div.navbar-start
|
||||||
[:div.control
|
[:a.navbar-item {:href "/bookmarks"} "Bookmarks"]]
|
||||||
[:input#username.input {:name "username" :type "text"
|
[:div.navbar-end
|
||||||
:placeholder "enter your username"}]]]
|
login]]])
|
||||||
[:div.field
|
|
||||||
[:label.label {:for "password"} "password"]
|
|
||||||
[:div.control
|
|
||||||
[:input#password.input {:name "password" :type "password"
|
|
||||||
:placeholder "enter your password"}]]]
|
|
||||||
[:div.field
|
|
||||||
[:div.control
|
|
||||||
[:button.button.is-primary "Submit"]]]])
|
|
||||||
|
|
||||||
(defn header-fragment []
|
(defn main-template [opts header & insert-body-here]
|
||||||
(html
|
|
||||||
[:nav.navbar
|
|
||||||
[:div.navbar-brand
|
|
||||||
[:a.burger.navbar-burger {:role "button" :data-target "mainNav"}
|
|
||||||
(repeat 3 [:span {:aria-hidden "true"}])]]
|
|
||||||
[:div#mainNav.navbar-menu
|
|
||||||
[:div.navbar-start
|
|
||||||
[:a.navbar-item {:href "/bookmarks"} "Bookmarks"]]
|
|
||||||
[:div.navbar-end
|
|
||||||
[:div.navbar-item.has-dropdown.is-hoverable
|
|
||||||
[:a.navbar-link "Login"]
|
|
||||||
[:div.navbar-dropdown.is-right
|
|
||||||
[:div.navbar-item
|
|
||||||
(login-form)]]]]]]))
|
|
||||||
|
|
||||||
(defn main-template [opts & insert-body-here]
|
|
||||||
(html5
|
(html5
|
||||||
{:lang "de"}
|
{:lang "de"}
|
||||||
[:head
|
[:head
|
||||||
@ -56,7 +55,7 @@
|
|||||||
[:body
|
[:body
|
||||||
{:hx-boost "false"}
|
{:hx-boost "false"}
|
||||||
[:header
|
[:header
|
||||||
(header-fragment)]
|
header]
|
||||||
[:main
|
[:main
|
||||||
insert-body-here]
|
insert-body-here]
|
||||||
(include-js "/js/main.js")]))
|
(include-js "/js/main.js")]))
|
||||||
@ -68,59 +67,53 @@
|
|||||||
[:pre.output
|
[:pre.output
|
||||||
[:code (with-out-str (clojure.pprint/pprint req))]]]))
|
[:code (with-out-str (clojure.pprint/pprint req))]]]))
|
||||||
|
|
||||||
(defn login-page []
|
(defn login-page [login]
|
||||||
(main-template
|
[:div.container.box
|
||||||
{:title "login"}
|
login])
|
||||||
[:div.container.box
|
|
||||||
(login-form "")]))
|
|
||||||
|
|
||||||
(defn paginate [base cur last]
|
(defn paginate [base cur last]
|
||||||
(let [page-fstring "%s?page=%d"
|
(let [page-fstring "%s?page=%d"
|
||||||
href (partial format page-fstring base)]
|
href (partial format page-fstring base)]
|
||||||
[:nav.container.box.pagination {:hx-boot "false"}
|
[:section
|
||||||
[:a.pagination-previous
|
[:nav.container.box.pagination {:hx-boot "false"}
|
||||||
{:href (href (dec cur))} "<"]
|
[:a.pagination-previous
|
||||||
[:a.pagination-next
|
{:href (href (dec cur))} "<"]
|
||||||
{:href (href (inc cur))} ">"]
|
[:a.pagination-next
|
||||||
[:ul.pagination-list
|
{:href (href (inc cur))} ">"]
|
||||||
[:li
|
[:ul.pagination-list
|
||||||
[:a.pagination-link
|
[:li
|
||||||
{:href (href 1)} (str 1)]]
|
[:a.pagination-link
|
||||||
[:li
|
{:href (href 1)} (str 1)]]
|
||||||
[:span.pagination-ellipsis "…"]]
|
[:li
|
||||||
(for [i (range (- cur 2) (+ cur 3))]
|
[:span.pagination-ellipsis "…"]]
|
||||||
[:li
|
(for [i (range (- cur 2) (+ cur 3))]
|
||||||
[:a.pagination-link
|
[:li
|
||||||
{:href (href i)
|
[:a.pagination-link
|
||||||
:class (when (= i cur) "is-current")} (str i)]])
|
{:href (href i)
|
||||||
[:li
|
:class (when (= i cur) "is-current")} (str i)]])
|
||||||
[:span.pagination-ellipsis "…"]]
|
[:li
|
||||||
[:li
|
[:span.pagination-ellipsis "…"]]
|
||||||
[:a.pagination-link
|
[:li
|
||||||
{:href (href last)} (str last)]]]]))
|
[:a.pagination-link
|
||||||
|
{:href (href last)} (str last)]]]]]))
|
||||||
|
|
||||||
(defn thread-page [thread]
|
(defn thread-page [{:keys [title content]}]
|
||||||
(binding [*thread* thread]
|
(list
|
||||||
(let [{:keys [id title page page-count content]} thread]
|
[:section.title [:div.container
|
||||||
(main-template
|
[:h1.is-size-3.mb-4 title]]]
|
||||||
{:title title}
|
[:section.thread
|
||||||
[:div.container
|
(for [post content]
|
||||||
[:h1.is-size-3.mb-4 title]]
|
[:article.container.box
|
||||||
[:section.thread
|
[:div.tile.is-ancestor
|
||||||
(for [post content]
|
[:aside.userinfo.tile.is-3.is-parent
|
||||||
[:article.container.box
|
(:ui post)]
|
||||||
[:div.tile.is-ancestor
|
[:main.postbody.content.tile.is-9.is-parent.is-vertical
|
||||||
[:aside.userinfo.tile.is-3.is-parent
|
[:div.tile.is-child
|
||||||
(:ui post)]
|
(:pb post)]
|
||||||
[:main.postbody.content.tile.is-9.is-parent.is-vertical
|
[:div.level.tile.is-child.is-12
|
||||||
[:div.tile.is-child
|
[:div.level-right
|
||||||
(:pb post)]
|
[:span.postdate.level-item
|
||||||
[:div.level.tile.is-child.is-12
|
(:pd post)]]]]]])]))
|
||||||
[:div.level-right
|
|
||||||
[:span.postdate.level-item
|
|
||||||
(:pd post)]]]]]])]
|
|
||||||
[:section
|
|
||||||
(paginate (str "/thread/" id) page page-count)]))))
|
|
||||||
|
|
||||||
(defn bookmarks-page [beems]
|
(defn bookmarks-page [beems]
|
||||||
(let [{:keys [title page page-count content]} beems]
|
(let [{:keys [title page page-count content]} beems]
|
||||||
|
Loading…
Reference in New Issue
Block a user