Getting started with Moustache and Enlive
A while ago i wrote a tutorial for compojure. Since i have switched to using enlive and moustache almost al the time. I think it is time for them to get a tutorial aswell. The goal for this tutorial will be to write a simple page for bookmarking.Getting started
I will be using Leinigen, you can ofcource use Cake without changing much (if anything at al). Start withlein new FeedTutorialI have added all the dependencies that will be used, so we dont have to go back later: My project.clj
(defproject FeedTutorial "1.0.0-SNAPSHOT"
:description "FIXME: write"
:dependencies [[org.clojure/clojure "1.2.0"]
[org.clojure/clojure-contrib "1.2.0"]
[enlive "1.0.0-SNAPSHOT"]
[net.cgrand/moustache "1.0.0-SNAPSHOT"]
[ring/ring-core "0.2.5"]
[ring/ring-devel "0.2.5"]
[ring/ring-jetty-adapter "0.2.5"]])(ns FeedTutorial.core
( :use net.cgrand.moustache
net.cgrand.enlive-html
ring.util.response
[ring.adapter.jetty :only [run-jetty]]))
(def my-app-handler
(app
[""] (-> "My own page!" response constantly)))
(run-jetty #'my-app-handler {:port 8080
:join? false})FeedTutorial.core> (response "Sometext")
{:status 200, :headers {}, :body "Sometext"}FeedTutorial.core> ((constantly 1) 2)
1
FeedTutorial.core> ((constantly 1) 2 3 4 5 6 7)
1Adding a template
As i said earlier, i will use enlive, wich is a templating engine. Lets see some code, we create our first template:(deftemplate index "FeedTutorial/index.html"
[])<html>
<head>
<title>My page!</title>
</head>
<body>
I am using a template!
</body>
</html>(def my-app-handler
(app
[""] (-> (index) response constantly)
["hello"] (-> "My own page!" response constantly)))Making changes to the template
Displaying a static .html file is not realy magic. To make changes, we first add something in the .html file that we want to change. I added: <div id="bookmarks">
</div>(deftemplate index "FeedTutorial/index.html"
[]
[:div#bookmarks] (content "I changed the html"))$("div#bookmarks").html("jquery changed me");(def bookmarks ["Something happend!" "More news." "Very cool stuff"]) <ul id="items">
<li>This will be replaced</li>
</ul>(deftemplate index "FeedTutorial/index.html"
[items]
[:div#bookmarks] (content "I changed the html")
[:ul#items :li] (clone-for [item items]
(content item))) [""] (-> (index bookmarks) response constantly)(def bookmarks [ {:title "Something happend!" :url "www.someurl.com"}
{:title "More news." :url "www.newssite.com"}
{:title "Very cool stuff" :url "www.verycoolsite.com"}]) <table id="items">
<tr class="bookmark">
<td class="title"></td>
<td class="url"></td>
</tr>
</table>(deftemplate index "FeedTutorial/index.html"
[items]
[:div#bookmarks] (content "I changed the html")
[:table#items :tr.bookmark] (clone-for [item items]
[:td.title] (content (:title item))
[:td.url] (content (:url item)))) <table id="items">
<tr class="bookmark">
<td class="title">Something happend!</td>
<td class="url">www.someurl.com</td>
</tr><tr class="bookmark">
<td class="title">More news.</td>
<td class="url">www.newssite.com</td>
</tr><tr class="bookmark">
<td class="title">Very cool stuff</td>
<td class="url">www.verycoolsite.com</td>
</tr>
</table> <table id="items">
<tr class="header">
<th>Title</th>
<th>URL</th>
</tr>
<tr class="bookmark">
<td class="title"></td>
<td class="url"></td>
</tr>
</table> [:div#bookmarks :*] (content "My own bookmarkingpage!") <div id="bookmarks">
<h1></h1>
</div>Adding new content
We have a very static page, since the only way to change the content now is to change the clojure code itself. We can change this by adding a /addBookmark route First we need a function to handle the request:(defn add-bookmark [request]
(response (str request))) ["addBookmark"] add-bookmark{:remote-addr "0:0:0:0:0:0:0:1", :scheme :http, :request-method
:get, :query-string nil, :content-type nil, :uri "/addBookmark",
:server-name "localhost",
:headers {"accept-charset" "ISO-8859-1,utf-8;q=0.7,*;q=0.3",
"accept-language" "en-US,en;q=0.8", "accept-encoding" "gzip,deflate,sdch",
"user-agent" "Mozilla/5.0 (X11; U; Linux x86_64; en-US) AppleWebKit/534.15 (KHTML, like Gecko) Chrome/10.0.612.1 Safari/534.15",
"accept" "application/xml,application/xhtml+xml,text/html;q=0.9,text/plain;q=0.8,image/png,*/*;q=0.5",
"connection" "keep-alive", "host" "localhost:8080"},
:content-length nil, :server-port 8080, :character-encoding nil,
:body #<Input org.mortbay.jetty.HttpParser$Input@1faf67f0>}curl -d "title=a title&url=www.myurl.com" localhost:8080/addBookmarkThe response i get now is:
{:remote-addr "0:0:0:0:0:0:0:1", :scheme :http,
:request-method :post, :query-string nil,
:content-type "application/x-www-form-urlencoded",
:uri "/addBookmark",
:server-name "localhost",
:headers {"content-type" "application/x-www-form-urlencoded",
"content-length" "27", "accept" "*/*", "host" "localhost:8080",
"user-agent" "curl/7.21.0 (x86_64-pc-linux-gnu) libcurl/7.21.0 OpenSSL/0.9.8o zlib/1.2.3.4 libidn/1.18"},
:content-length 27, :server-port 8080, :character-encoding nil,
:body #<Input org.mortbay.jetty.HttpParser$Input@769652dd>}(def my-app-handler
(app
wrap-params
["addBookmark"] add-bookmark
[""] (-> (index bookmarks) response constantly)
["raw"] (-> (raw) response constantly)))(ns FeedTutorial.core
( :use net.cgrand.moustache
net.cgrand.enlive-html
ring.util.response
ring.middleware.params
[ring.adapter.jetty :only [run-jetty]]))curl -d "title=a title&url=myurl.com" localhost:8080/addBookmarks
{:remote-addr "0:0:0:0:0:0:0:1",
:scheme :http, :query-params {},
:form-params {"url" "myurl.com", "title" "a title"},
:request-method :post, :query-string nil,
:content-type "application/x-www-form-urlencoded",
:uri "/addBookmarks",
:server-name "localhost",
:params {"url" "myurl.com", "title" "a title"},
:headers {"content-type" "application/x-www-form-urlencoded",
"content-length" "27", "accept" "*/*", "host" "localhost:8080",
"user-agent" "curl/7.21.0 (x86_64-pc-linux-gnu) libcurl/7.21.0 OpenSSL/0.9.8o zlib/1.2.3.4 libidn/1.18"},
:content-length 27, :server-port 8080, :character-encoding nil,
:body #<Input org.mortbay.jetty.HttpParser$Input@44fc63be>}(defn add-bookmark [{params :params}]
(response (str params)))
curl -d "title=a title&url=myurl.com" localhost:8080/addNews
{"url" "myurl.com", "title" "a title"}
To be able to add bookmarks in a nice way. We can wrap it as an agent:
(def bookmarks (agent [{:title "Something happend!" :url "www.someurl.com"}
{:title "More news." :url "www.newssite.com"}
{:title "Very cool stuff" :url "www.verycoolsite.com"}])) [""] (-> (index @bookmarks) response constantly)(conj @bookmarks {:title "test" :url "www.test.com"})
[{:title "Something happend!", :url "www.someurl.com"}
{:title "More news.", :url "www.newssite.com"}
{:title "Very cool stuff", :url "www.verycoolsite.com"}
{:title "test", :url "www.test.com"}]@bookmarks
[{:title "Something happend!", :url "www.someurl.com"}
{:title "More news.", :url "www.newssite.com"}
{:title "Very cool stuff", :url "www.verycoolsite.com"}](defn add-bookmark [{params :params}]
(send bookmarks conj {:title (params "title") :url (params "url")})
(response (str params)))javascript:function%20iprl5(){
var d=document,z=d.createElement('scr'+'ipt'),
b=d.body,l=d.location;try{if(!b)throw(0);
z.setAttribute('src',l.protocol+'//localhost:8080/addBookmark?title='+encodeURIComponent(d.title)+'&url='+encodeURIComponent(l.href));b.appendChild(z);}
catch(e){alert('Please wait until the page has loaded.');}}iprl5();void(0)
blog comments powered by Disqus