Problem: Enlive snippet making funky HTML
Visual reference of problem: http://i.imgur.com/FIOzgZv.png
See bottom of code snippet for strange HTML in question
(ns notebook.handler
(:require [compojure.core :refer :all]
[compojure.handler :as handler]
[compojure.route :as route]
[net.cgrand.enlive-html :as html]))
(html/defsnippet nav "templates/nav.html" [:*]
[])
(html/deftemplate home-page "templates/base.html"
[]
[:body] (html/prepend (nav)))
(defroutes app-routes
(GET "/" [] (home-page))
(route/resources "/")
(route/not-found "Not Found"))
(def app
(handler/site app-routes))
Contents of base.html:
<html>
<head>
<link rel=stylesheet href="css/base.css">
</head>
<body>
</body>
</html>
Contents of nav.html:
<nav>
<ul>
<li>FlatNotes</li>
</ul>
</nav>
HTML when localhost:3000 is visited:
<html>
<head>
<link href="css/base.css" rel="stylesheet" />
</head>
<body><nav>
<ul>
<li>FlatNotes</li>
</ul>
</nav><ul>
<li>FlatNotes</li>
</ul><li>FlatNotes</li>
</body>
</html>
(reduce str (html/emit* (nav))) shows strange HTML meaning the problem occurs in defsnippet before deftemplate:
"<nav>\n <ul>\n\t<li>FlatNotes</li>\n </ul>\n\n</nav><ul>\n\t<li>FlatNotes</li>\n </ul><li>FlatNotes</li>"
Maybe I'm mistaken about what [:*] does, or there's a fundamental misunderstanding, or there's a gotcha I'm unaware of. I've already reduced the code down to as minimal as I can so lolidk.
:* represents the universal selector. It matches every element in nav.html - nav, ul, and li - which means the nav snippet is:
<nav>
<ul>
<li>FlatNotes</li>
</ul>
</nav>
<ul>
<li>FlatNotes</li>
</ul>
<li>FlatNotes</li>
The selector you pass to the snippet definition should point to the single, top level element of your snippet. If you change :* to match a single element (i.e. :nav), it ought to give you the snippet you're looking for.
Related
Hi All I'm trying to "parse/extract" html-data with Clojure en Enlive (any better choices ?)
I am trying to get all the ul > li tags that are *NOT part of the
<nav> tag I think I should use the (html/but) function from Enlive
but can't seem to make it work ?
;;test-envlive.clj
(defn get-tags [dom tag-list]
(let [tags
(mapv
#(vec (html/select dom %1))
tag-list)]
tags))
;;Gives NO tags
(get-tags test-dom [[[(html/but :nav) :ul :> :li]]])
;;Gives ALL the LI-tags
(get-tags test-dom [[:ul :> :li]])
<!-- test.html -->
<html>
<head><title>Test page</title> </head>
<body>
<div>
<nav>
<ul>
<li>
skip these navs-li
</li>
</ul>
</nav>
<h1>Hello World<h1>
<ul><li>get only these li's</li>
</ul>
</div>
</body></html>
If you had a valid xhtml, you could use XPath from sigel:
(require '[sigel.xpath.core :as xpath])
(let [data "<html><head><title>Test page</title></head>
<body><div><nav><ul><li>skip these navs-li</li></ul></nav>
<h1>Hello World</h1>
<ul><li>get only these li's</li></ul>
</div></body></html>"]
(xpath/select data "//li[not(ancestor::nav)]"))
I was able to select target li with Hickory, so if you don't mind changing your library:
Dependency: [hickory "0.7.1"]
Require: [hickory.core :as h] [hickory.select :as s]
(s/select (s/and
(s/descendant (s/tag :ul)
(s/tag :li))
(s/not (s/descendant (s/tag :nav)
(s/tag :li))))
(h/as-hickory (h/parse (slurp "resources/site.html"))))
=> [{:type :element, :attrs nil, :tag :li, :content ["get only these li's"]}]
You could do this with the Tupelo Forest library. Watch the video and see the examples in the unit tests.
Here is one way to solve your problem:
(ns tst.tupelo.forest-examples
(:use tupelo.core tupelo.forest tupelo.test)
(:require. ... ))
<snip>
(verify
(let [html-data "<html>
<head><title>Test page</title> </head>
<body>
<div>
<nav>
<ul>
<li>
skip these navs-li
</li>
</ul>
</nav>
<h1>Hello World<h1>
<ul><li>get only these li's</li>
</ul>
</div>
</body>
</html> "]
and the interesting part comes next.
(hid-count-reset)
(with-forest (new-forest)
(let [root-hid (add-tree-html html-data)
out-hiccup (hid->hiccup root-hid)
result-1 (find-paths root-hid [:html :body :div :ul :li])
li-hid (last (only result-1))
li-hiccup (hid->hiccup li-hid)]
(is= out-hiccup [:html
[:head [:title "Test page"]]
[:body
[:div
[:nav
[:ul
[:li
"\n skip these navs-li\n "]]]
[:h1 "Hello World"]
[:ul [:li "get only these li's"]]]]])
(is= result-1 [[1011 1010 1009 1008 1007]])
(is= li-hid 1007)
(is= li-hiccup [:li "get only these li's"])))))
The above code can be seen live in the examples.
This is a strange bug. I have an html file that extends a base template called base.html. I noticed that a script tag right before the end body tag in the base template doesn't show up in the DOM in the Elements tab of the Chrome dev tools, and the tag is cut off completely along with the rest of the html file in the Sources tab. This happens in Chrome, Mozilla, and Safari, so it must be a problem on the Django side. And obviously the observable effects on the page that the script should create aren't happening either.
Here's the end of the rendered html in the Sources tab:
<section>
what is going on
</section>
<footer></footer>
<script src="/static/home/js/ba
Completely cut off. Here's the end of that base template:
{% block main %}{% endblock %}
<footer></footer>
<script src="{% static 'home/js/base.js' %}"></script>
{% block js %}{% endblock %}
</body>
</html>
Now, here's where it gets funny. The trouble is at the end of the file, so I just added some newlines to see if there's any difference in the DOM is rendered:
{% block main %}{% endblock %}
<footer></footer>
<script src="{% static 'home/js/base.js' %}"></script>
{% block js %}{% endblock %}
</body>
</html>
And the Sources tab showed a cut off later in the tag:
<section>
what is going on
</section>
<footer></footer>
<script src="/static/home/js/base.j
I won't paste it here, but I added about 35 newlines to the end of the file before I got what I wanted in the Sources. It seems that every newline cuts off the rendered html one character later.
<section>
what is going on
</section>
<footer></footer>
<script src="/static/home/js/base.js"></script>
</body>
</html>
And the effects from the script finally worked. This feels like a temporary solution to something deeper that needs to be fixed. Anybody have any clue what the hell is going on or where to look?
Edit: Here's the template (located in the work app) that extends base.html (located in the home app), called work.html:
{% extends 'home/base.html' %}
{% block css %}
<link rel="stylesheet" href="{% static 'work/css/work.css' %}">
{% endblock %}
{% block main %}
<section>
hello
</section>
{% endblock %}
And here is the view that renders it:
from django.shortcuts import render
def work(request):
return render(request, 'work/work.html', {})
Edit 2: some more unexpected results:
When I deleted the script (so that I can paste it in head as suggested in the comments), the end of the rendered html was this:
<section> what is going on </section>
And pasting right before the </head> tag resulted in:
<section> what is going on </section>
<
Same result above when I commented it out in head.
Commenting out the script when it's before the </body> results in this:
<section> what is going on </section>
<footer></footer>
<!-- <script src="/static/home/js/base.j
And replacing single quotes with double quotes resulted in the rendered html showing double quotes instead of single quotes as the only difference. :/
Then I deleted almost everything so that my code was this:
<!DOCTYPE html>
<html lang="en-US">
<head>
</head>
And that rendered:
<!DOCTYPE html>
<html lang="en-US">
<head>
<scrip
I added back some tags:
<!DOCTYPE html>
<html lang="en-US">
<head>
</head>
<body>
</body>
</html>
And the result:
<!DOCTYPE html>
<html lang="en-US">
<head>
<script src="http://127.0.0.1:357
For some reason, the script tag generated by django-livereload-server remains. This is what the full script tag looks like:
<script src="http://127.0.0.1:35729/livereload.js"></script></head>
Mystery's over everybody. The problem is that you should not pip install django-livereload-server. I don't know what it does behind the scenes but some of my html disappear based on some weird algorithm.
So, to uninstall django-livereload-server, remove 'livereload', from your INSTALLED_APPS, remove 'livereload.middleware.LiveReloadScript', from your MIDDLEWARE, hit Control-C to get out of that livereload terminal process, Control-C in the window running the runserver process to apply the changes (because livereload latches onto runserver like a leech, so you have to restart), and enjoy expected output. And pip uninstall django-livereload-server. If anybody has any suggestions for a livereload type of app that works (where the browser reloads the page when you type something new in your html/js/css), let me know. For now I guess it's back to the old manually typed Command-R.
hii I am novice to python and django. I am referring one tutorial to develop a blog in django.
I have synchronized the database and have run the server.
My admin page is working fine but my application page is showing some problem
I have created an html file "blog.html"
(% extends "base.html" %)
(% block content %)
(% for post in object_list %)
<h3>{{ post.title}}</h3>
<div class="post_meta">
on {{post.date}}
</div>
<div class= "post_body">
{{post.body|safe|linebreaks}}
</div>
(%endfor %)
(%endblock %)
When i run my django, it is showing this code inspite of actual blog page..
Django's template language uses {% and %} for template tags, not (% and %) as in your template file.
I just start programming recently and I have this problem, so I have this html snippet. I want parse the src attribute of the img and normalize it with urly path normalization, and add some new path to the src.
<html>
<body>
<div class="content">lorem ipsum
<img style="margin-top: -5px;" src="/img/car.png" />
</div>
<img style="margin-top: -5px;" src="/img/chair.png" />
</body>
</html>
become this
<html>
<body>
<div class="content">lorem ipsum
<img style="margin-top: -5px;" src="/path1/img/car.png" />
</div>
<img style="margin-top: -5px;" src="/path1/img/chair.png" />
</body>
</html>
I think of this method but i just can't find the way to acquire the src value
(html/deftemplate template-about "../resources/public/build/about/index.html"
[]
[:img] (html/set-attr :src (str "path1" (urly/path-of ("the src value")))
)
You're looking for an update-attr function, was discussed before
As in:
(html/deftemplate template-about "../resources/public/build/about/index.html"
[]
[:img] (fn [node]
(let [href (-> node :attrs :href)]
(assoc-in node [:attrs :href] (urly/path-of href))))
Or taking the generic path
(defn update-attr [attr f & args]
(fn [node]
(apply update-in node [:attrs attr] f args))))
and then
(update-attr :href urly/path-of)
I am trying to learn Play 2.0 with scala but I dont think i quite understand how the template system for play 2.0 works. I have used play 1.2 before and i am sort of looking for an equivalent to the #{include 'views/blah.html' /}. I essentially want to create a navbar that is rendered on all the pages.
Essentially in main.scala.html i have
#(title: String)(navbar: Html)(content: Html)
<!DOCTYPE html>
<html>
<head>
<title>#title</title>
<link rel="stylesheet" media="screen" href="#routes.Assets.at("stylesheets/main.css")">
<link rel="shortcut icon" type="image/png" href="#routes.Assets.at("images/favicon.png")">
<script src="#routes.Assets.at("javascripts/jquery-1.7.1.min.js")" type="text/javascript"></script>
</head>
<header>
This is my header
</header>
<section class="navbar">#navbar</section>
<section class="content">#content</section>
<footer>
This is my footer
</footer>
and in my index.scala.html:
#navbar = {
<h1>Index</h1>
<ul>
<li>
<a href=#routes.Application.tasks>Tasks</a>
</li>
</ul>
}
#main("Home")(navbar){
content
}
in task.scala.html:
#(tasks: List[Task], taskForm: Form[String])
#import helper._
#main("Home") {
<h1>Index</h1>
<ul>
<li>
<a href=#routes.Application.tasks>Tasks</a>
</li>
</ul>
} {
task code
}
Now to include this navbar it seems i have to repeat this in every page this way i would have to hard code this navbar into every page. Is there a way to do this without without writing the whole navbar in every page?
I have also tried creating a navbar.scala.html file that contains
<h1>Index</h1>
<ul>
<li>
<a href=#routes.Application.tasks>Tasks</a>
</li>
</ul>
and saving under views/ then importing that using #import views.navbar but then i get an error stating 'navbar is not a member of views'. I am writing this in Eclipse Java EE IDE indigo if that helps.
Dont import it but just call it:
#navbar()
To include any other views template into another views template,
you simple call it using: #views.html.[location].[location].[location]()
Where [location] is just a break down of it's path.
for example:
#views.html.users.interface()
Be sure to put the "()" ie the brackets at the end of the statement if it does not take any parameters. Without the "()" you will get an error message like this:
"BaseScalaTemplate(play.api.templates...)"
If your template has parameters, be sure to include them when you call it, like this:
#views.html.users.interface( "name" )