Scriptjure, Static, and Disqus

The blogging engine I use is written in clojure. I am now using scriptjure, a clojure library for generating javascript, for the javascript in my page templates.

I included scriptjure in my fork of static (clojure static site generator that runs this blog). I have modified my default.clj and now use hiccup and scriptjure for the disqus integration as follows. To adapt this code for your own use, you need only to change the string after forums – in this case: apocalispnow – to the name of your site.

I rewrote the following section to use hiccup:

Without Hiccup:

[:div {:id "disqus"} 
 (if (= (:type metadata) :post) 
 "<div id=\"disqus_thread\"></div><script type=\"text/javascript\" src=\"http://disqus.com/forums/nakkaya/embed.js\"></script><noscript><a href=\"http://disqus.com/forums/nakkaya/?url=ref\">View the discussion thread.</a></noscript><a href=\"http://disqus.com\" class=\"dsq-brlink\">blog comments powered by <span class=\"logo-disqus\">Disqus</span></a>")]]

With Hiccup:

[:div {:id "disqus"}
 (if (= (:type metadata) :post)
   (html
    [:div#disqus_thread]
    [:script {:type "text/javascript" :src "http://disqus.com/forums/apocalispnow/embed.js"}]
    [:noscript
     [:a {:href "http://disqus.com/forums/apocalispnow/?url=ref"} "View the discussion thread."]]
    [:a {:href "http://disqus.com" :class "dsq-brlink"} "blog comments powered by" [:span {:class "logo-disqus"} "Disqus"]]))]

I think this is easier to read, more idiomatic, and makes embedding disqus in clojure web applications easier. Likewise for embedding javascript, though scriptjure may be overkill.

Without scriptjure & hiccup:

  (if (= (:type metadata) :post) 
    "<script type=\"text/javascript\">
//<![CDATA[
(function() {
             var links = document.getElementsByTagName('a');
             var query = '?';
             for(var i = 0; i < links.length; i++) {
                     if(links[i].href.indexOf('#disqus_thread') >= 0) {
                                                                       query += 'url' + i + '=' + encodeURIComponent(links[i].href) + '&';
                                                                       }
                     }
             document.write('<script charset=\"utf-8\" type=\"text/javascript\" src=\"http://disqus.com/forums/nakkaya/get_num_replies.js' + query + '\"></' + 'script>');
             })();
//]]>
</script>")
[:script {:type "text/javascript"}
 "$(document).ready(function() {
      $(\"pre\").wrapInner(\"<code></code>\");
      hljs.initHighlightingOnLoad();
  });"]

With scriptjure & hiccup:

(if (= (:type metadata) :post)
  (html
   [:script {:type "text/javascript" :charset "utf-8" :src
             (str "http://disqus.com/forums/apocalispnow/get_num_replies.js"
                  (js (do
                        (var links (.getElementsByTagName document "a"))
                        (var query "?")
                        (var i 0)
                        (while (< i (.length links))
                          (if (>= (.href.indexOf (aget links i) "#disqus_thread") 0)
                            (set! query
                                  (+ query "url" i "="
                                     (encodeURIComponent (.href (aget links i))) "&")))
                          (inc i))
                        (return query))))}])

Above I use the (html) function to wrap everything so if doesn't complain.

[:script {:type "text/javascript"}
 (js (. ($ document) ready 
        (fn []
          (. ($ "pre") wrapInner (clj (html [:code])))
          (.initHighlightingOnLoad hljs))))]

I do have some comments on scriptjure. First let me say that I think it's an awesome project and opens up possibilities for a dynamic web frontend to clojure apps. Hiccup and Scriptjure are a great example of how to create web pages from within clojure. However, scriptjure is still in early development. If you've taken a look at my code above you may notice some strange choices in terms of representing the javascript in scriptjure. I had to tweak my solution to work around what is currently supported in scriptjure, which was not much of a hassle but may be a deterrent for some.

For instance, I was unable to figure out how to represent a js for loop in scriptjure. After some research I realized it was because for isn't currently in the scriptjure special forms, which you can browse to here. Another issue was working around set! with scriptjure. set! performs basic javascript assignment, as seen below:

> (js (set! x 5))
"x = 5;\n" 

Attempts at manual assignment seem to fail:

> (js (= x 5))
"(x === 5)"
> (js (== x 5))
"(x == 5)"
> (js (+= x 5))
"(x += 5)"

I would like to be able to use (= 1 1) for tests and (== x y), (+= x y) for javascript assignment in scriptjure. Oh well…

All in all, I'm excited to see how scripture progresses. I think one of the cool things about the project is interoperability between clojure and javascript. Coupled with enlive, I see some cool projects in the near future.