Enlive templating - Adding CSS includes to <head>

348 views Asked by At

I'm not sure how I should be approaching this. I have a list of CSS files that I want to feed into something and get HTML back. For example,

(list "base.css" "index.css" "more_css.css") ;vector might be more appropriate?

should be transformed into:

<link href="css/base.css" rel="stylesheet" />
<link href="css/index.css" rel="stylesheet" />
<link href="css/more_css.css" rel="stylesheet" />

From there it should be appended into <head>.

defsnippet almost looks appropriate but takes a template file and a selector for a section of that file. The generated HTML here is not dependent on a template and something that only generates the HTML seems appropriate. clone-for might do the looping part of what I want but I'm having trouble figuring out how to use it.

2

There are 2 answers

0
deadghost On BEST ANSWER

Alternatively:

(require '[net.cgrand.enlive-html :as enlive])

(defn include-css [href]
      (first (enlive/html [:link {:href href :rel "stylesheet"}])))

(map include-css ["css/base.css" "css/index.css" "css/more_css.css"])
;; newlines added by hand for clarity
=> ({:tag :link, :attrs {:href "css/base.css", :rel "stylesheet"}, :content ()} 
    {:tag :link, :attrs {:href "css/index.css", :rel "stylesheet"}, :content ()} 
    {:tag :link, :attrs {:href "css/more_css.css", :rel "stylesheet"}, :content ()})

Double-check it produces the correct HTML:

(print (apply str (html/emit* (map include-css ["css/base.css" "css/index.css" "css/more_css.css"]))))
;; newlines added by hand for clarity
=> <link href="css/base.css" rel="stylesheet" />
   <link href="css/index.css" rel="stylesheet" />
   <link href="css/more_css.css" rel="stylesheet" />
   nil
0
Michał Marczyk On

defsnippet actually takes any source that Enlive can understand, it doesn't need to be a file. In particular, it can be an inline Enlive-style representation of the link tag template. Since version 1.1.0, Enlive also provides a helper (net.grand.enlive-html/html) that parses Hiccup style notation; I find Hiccup style to be more convenient to write by hand, so that's what I'll use below. (You can also use inline HTML strings by wrapping them in a StringReader: (java.io.StringReader. "<div></div>").)

Here's the code:

(require '[net.cgrand.enlive-html :as enlive])

(enlive/defsnippet link-css
  ;; representation of the link tag template:
  (enlive/html [:link {:href "" :rel "stylesheet"}])
  ;; selector is required, :link works fine here:
  [:link]
  ;; this is the parameter vector of the fn defsnippet will generate:
  [hrefs]
  ;; clone-for will generate one link tag for each provided href:
  (enlive/clone-for [href hrefs]
    [:link]
    (enlive/set-attr :href href)))

You'd use it like so:

(->> (link-css ["css/base.css" "css/index.css" "css/more_css.css"])
  (enlive/emit*)
  (apply str))
;= "<link href=\"css/base.css\" rel=\"stylesheet\" /><link href=\"css/index.css\" rel=\"stylesheet\" /><link href=\"css/more_css.css\" rel=\"stylesheet\" />"

Adding println to the end of the ->> pipeline is a convenient way to test this; here's the output (with the two newlines inserted by hand for clarity):

<link href="css/base.css" rel="stylesheet" />
<link href="css/index.css" rel="stylesheet" />
<link href="css/more_css.css" rel="stylesheet" />