{% for x in coll %}
<h>{{ x.heading }}</h>
<p>{{ x.content }}</p>
{% endfor %]
Note that there is no containing element for the <h> and <p> elements.
How would one loop over something like this using Enlive snippets +
templates? If there was a container element it would be simple, but
without it I don't see anything obvious. Is there a way to support
this case easily?
Thanks,
David
I think you're looking for clone-for:
(at node [:option]
(clone-for [option options]
(do-> (set-attr :value (option :value))
#(if (option :selected)
((set-attr :selected "selected") %) %)
(content (option :name)))))))
Here you can see that I only ever reference the <option> element, but
obviously it could be any standalone node.
Rob
> --
> You received this message because you are subscribed to the Google Groups "Enlive" group.
> To post to this group, send email to enliv...@googlegroups.com.
> To unsubscribe from this group, send email to enlive-clj+...@googlegroups.com.
> For more options, visit this group at http://groups.google.com/group/enlive-clj?hl=en.
>
>
- Chas
On Sun, Jan 31, 2010 at 8:48 PM, David Nolen <dnolen...@gmail.com> wrote:
> When using traditional templating solutions it's common that you'll
> see something like the following:
>
> {% for x in coll %}
> <h>{{ x.heading }}</h>
> <p>{{ x.content }}</p>
> {% endfor %]
>
> Note that there is no containing element for the <h> and <p> elements.
Indeed there's no facility to transform a group of adjacent nodes
without a container.
Off the top of my head:
Clojure 1.2.0-master-SNAPSHOT
user=> (use 'net.cgrand.enlive-html)
nil
user=> (def src (-> "<h1>Big Title<h2>Smaller title<p>A paragraph<div
class="footer">a footer" java.io.StringReader. html-resource))
java.lang.Exception: Unable to resolve symbol: footer in this context
(NO_SOURCE_FILE:2)
user=> (def src (-> "<h1>Big Title<h2>Smaller title<p>A paragraph<div
class='footer'>a footer" java.io.StringReader. html-resource))
#'user/src
user=> src
({:tag :html, :attrs nil, :content [{:tag :body, :attrs nil, :content
[{:tag :h1, :attrs nil, :content ["Big Title"]} {:tag :h2, :attrs nil,
:content ["Smaller title"]} {:tag :p, :attrs nil, :content ["A
paragraph"]} {:tag :div, :attrs {:class "footer"}, :content ["a
footer"]}]}]})
user=> (apply str (emit* src))
"<html><body><h1>Big Title</h1><h2>Smaller title</h2><p>A
paragraph</p><div class=\"footer\">a footer</div></body></html>"
user=> (defsnippet h+p src [#{:h2 :p}] [{:keys [title text]}] [:h2]
(content title) [:p] (content text))
#'user/h+p
user=> (h+p {:title "hello" :text "world"})
({:tag :h2, :attrs nil, :content ("hello")} {:tag :p, :attrs nil,
:content ("world")})
user=> (apply str (emit* *1))
"<h2>hello</h2><p>world</p>"
user=> (deftemplate tmpl src [data] [#{:h2 :p}] nil [:h1] (after (map
h+p data)))
#'user/tmpl
user=> (apply str (tmpl [{:title "title#1" :text "paragraph#1"}
{:title "title#2" :text "paragraph#2"}]))
"<html><body><h1>Big
Title</h1><h2>title#1</h2><p>pragraph#1</p><h2>title#2</h2><p>pragraph#2</p><div
class=\"footer\">a footer</div></body></html>"
> How would one loop over something like this using Enlive snippets +
> templates? If there was a container element it would be simple, but
> without it I don't see anything obvious. Is there a way to support
> this case easily?
If there was a container element, one could also clone it and then
strip it from the result to leave only the repeated inner nodes.
In order to support (just musing not promising anything) such cases,
how would one define a group of adjacent nodes?
Christophe
My issue with this is that we are now offloading the problem onto the
person that is writing the markup. Ideally Enlive can just support
common cases.
I like your solution using a snippet with the #{:h2 :p} selector:
But I was thinking it would be nice to combine this with my "model"
idea from the earlier mailing list post:
(def h+p (html/selector [:div#main :> #{[:h2 (html/nth-of-type 1)]
[:p (html/nth-of-type
1)]}]))
(html/defsnippet my-snippet source h+p
[{:keys [title text]}]
[:h2] (html/content title)
[:p] (html/content text))
This actually works pretty well from what I'm describing. And though
it's certainly more verbose than this:
{% for x in coll %}
<h>{{ x.heading }}</h>
<p>{{ x.content }}</p>
{% endfor %]
The Enlive version is composable and the above is not (beyond copy and
paste).
>
> In order to support (just musing not promising anything) such cases,
> how would one define a group of adjacent nodes?
>
> Christophe
As for making it more elegant and less verbose what about something
like the following?
(html/defsnippet name src selector
[ctxt]
[:h2] :and [:p] (fn [h2 p] (...)))
I like this because preserve the idea of the selector/fn pair. If both
selectors aren't matched we just fail and move on to the next
selector/
fn pair.
David
On Tue, Feb 2, 2010 at 3:47 AM, David Nolen <dnolen...@gmail.com> wrote:
> My issue with this is that we are now offloading the problem onto the
> person that is writing the markup. Ideally Enlive can just support
> common cases.
I agree.
> But I was thinking it would be nice to combine this with my "model"
> idea from the earlier mailing list post:
>
> (def h+p (html/selector [:div#main :> #{[:h2 (html/nth-of-type 1)]
> [:p (html/nth-of-type
> 1)]}]))
>
> (html/defsnippet my-snippet source h+p
> [{:keys [title text]}]
> [:h2] (html/content title)
> [:p] (html/content text))
This is nice too but still unsatisfactory.
>> In order to support (just musing not promising anything) such cases,
>> how would one define a group of adjacent nodes?
>
> As for making it more elegant and less verbose what about something
> like the following?
>
> (html/defsnippet name src selector
> [ctxt]
> [:h2] :and [:p] (fn [h2 p] (...)))
It's close to what I have in mind but I think there's more value in
being able to specify an "extent" between two selectors:
(deftemplate name src [data]
(extent [:h2] [:p]) (clone-for [{:keys [title text]}]
[:h2] (content title)
[:p] (content text)))
An extent (if antyone has a better name please chime in) being all the
nodes between two siblings, the leftmost being selected by the first
selector, the rightmost being selected by the second selector.
What do you think?
> I like this because preserve the idea of the selector/fn pair. If both
> selectors aren't matched we just fail and move on to the next selector/
> fn pair.
What I propose is to have an new class of selectors which don't select
a single node but several *adjacent* nodes (including whitespaces and
comments) at once.
The fn would, in this case, take a seq of nodes.
Christophe
--
Professional: http://cgrand.net/ (fr)
On Clojure: http://clj-me.cgrand.net/ (en)
(extent [:h2] [:p]) (clone-for [{:keys [title text]}]
(deftemplate name src [data]
[:h2] (content title)
[:p] (content text)))
An extent (if antyone has a better name please chime in) being all the
nodes between two siblings, the leftmost being selected by the first
selector, the rightmost being selected by the second selector.
What do you think?
> It's close to what I have in mind but I think there's more value in
> being able to specify an "extent" between two selectors:
>
> (deftemplate name src [data]
> (extent [:h2] [:p]) (clone-for [{:keys [title text]}]
> [:h2] (content title)
> [:p] (content text)))
>
> An extent (if antyone has a better name please chime in) being all the
> nodes between two siblings, the leftmost being selected by the first
> selector, the rightmost being selected by the second selector.
>
> What do you think?
Regarding terminology, I'd call it a 'slice', which I think fits in
with the slice operation that many people are familiar with in python,
etc.
However...
On Tue, Feb 2, 2010 at 3:47 AM, David Nolen <dnolen...@gmail.com>
wrote:
> My issue with this is that we are now offloading the problem onto the
> person that is writing the markup. Ideally Enlive can just support
> common cases.
Just out of curiosity, is this really a common case? In my
(admittedly limited) experience, if one is looking to emit repeated
sequences of elements as described, then the CSS is going to almost
certainly need some container around each such sequence anyway. Is
this less universal than I suspect?
- Chas
Regarding terminology, I'd call it a 'slice', which I think fits in with the slice operation that many people are familiar with in python, etc.
However...
Just out of curiosity, is this really a common case? In my (admittedly limited) experience, if one is looking to emit repeated sequences of elements as described, then the CSS is going to almost certainly need some container around each such sequence anyway. Is this less universal than I suspect?
Just out of curiosity, is this really a common case? In my (admittedly limited) experience, if one is looking to emit repeated sequences of elements as described, then the CSS is going to almost certainly need some container around each such sequence anyway. Is this less universal than I suspect?You don't need a container to style repeating elements with CSS. I've seen this pattern a lot in PHP as well as in Django templates. I've been handed markup that looks this from designers as well. Many JavaScript accordions expect this pattern.
In this html snippet: <div><h1>title</h1><p>p1</p><p>p2</p></div> do
you think that {[:h1] [:p]} should select:
* <h1>title</h1><p>p1</p>
* <h1>title</h1><p>p1</p><p>p2</p>
* both
Right now my vote is on the first choice as it seems the least surprising.
> --
> You received this message because you are subscribed to the Google Groups
> "Enlive" group.
> To post to this group, send email to enliv...@googlegroups.com.
> To unsubscribe from this group, send email to
> enlive-clj+...@googlegroups.com.
> For more options, visit this group at
> http://groups.google.com/group/enlive-clj?hl=en.
>
--
What about {[:h1] [:p]} to denote the extent/slice selector?
In this html snippet: <div><h1>title</h1><p>p1</p><p>p2</p></div> do
you think that {[:h1] [:p]} should select:
* <h1>title</h1><p>p1</p>
* <h1>title</h1><p>p1</p><p>p2</p>
* both
Right now my vote is on the first choice as it seems the least surprising.
It's a possibility but I'd like to pick a single option for the moment
and see if the need for the other arises.
Note that {[:h1] [:p] :greedy true} can be written {[:h1] [[last-of-type :p]]}
So, do you have a strong opinion on which option to choose?
Christophe
It's a possibility but I'd like to pick a single option for the moment
and see if the need for the other arises.
Note that {[:h1] [:p] :greedy true} can be written {[:h1] [[last-of-type :p]]}
So, do you have a strong opinion on which option to choose?
I created a kind of todo list: http://wiki.github.com/cgrand/enlive/whats-next