Skip to content

Instantly share code, notes, and snippets.

@danlentz
Created September 12, 2013 18:51
Show Gist options
  • Save danlentz/6542190 to your computer and use it in GitHub Desktop.
Save danlentz/6542190 to your computer and use it in GitHub Desktop.
clojure enlive content layout

You can use snippet markers within your HTML template code in order to generate *-prefixed selectors that you can later use within Enlive template.

For example, if you say:

<div snippet="content-main"></div>

You can later reference it with *content-main selector, which will be automatically generated for you.

One of the hidden benefist is that if your application code relies on some element in HTML, here it will be validated, and if there's anything referenced that's not present in HTML, you'll get an exception during compilation, which is good, I think.

(ns clojurewerkz.gizmo.enlive
(:require [net.cgrand.enlive-html :as html]))
(defn has-attr
[attr]
(html/pred #(not (nil? (-> % :attrs attr)))))
(defn snip
[snippet-name]
(html/pred #(= snippet-name (-> % :attrs :snippet))))
(defn format-selector
[name]
(format "*%s" name))
(defmacro defsnippet
"Define a named snippet with enclosed selectors"
[name source selector args & forms]
(let [snippets (html/select (html/html-resource source) [(has-attr :snippet)])
names (apply concat (map #(vector
(-> % :attrs :snippet format-selector symbol)
(list 'snip (-> % :attrs :snippet))) snippets))]
`(let* [~@names]
(def ~name (html/snippet ~source ~selector ~args ~@forms)))))
<!DOCTYPE html>
<html lang="en">
<head>
<title>App Layout</title>
</head>
<body>
<div snippet="content-main">
<ul snippet="simple-list">
<li snippet="simple-list-item">${value}</li>
</ul>
</div>
</body>
</html>
(ns clojurewerkz.gizmo.enlive-test
(:require [net.cgrand.enlive-html :as html])
(:use clojure.test
clojurewerkz.gizmo.widget
clojurewerkz.gizmo.enlive))
(deftest defsnippet-test
(defsnippet defsnippet-test-snippet-1 "templates/snippets/sniptest.html"
[*content-main]
[values]
[*simple-list [*simple-list-item]] (html/clone-for [value values]
[html/any-node] (html/replace-vars {:value value})))
(is (= (render* (defsnippet-test-snippet-1 ["a" "b" "c"]))
"<div snippet=\"content-main\">
<ul snippet=\"simple-list\">
<li snippet=\"simple-list-item\">a</li><li snippet=\"simple-list-item\">b</li><li snippet=\"simple-list-item\">c</li>
</ul>
</div>")))
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment