Submitting a feature request for the :toc to support both ordered and unordered lists by expanding the vocabulary of the existing :toc directive to include :ul and :ol

This commit is contained in:
Jeff Rabinowitz 2015-10-25 19:14:43 -04:00
parent b96a872654
commit 482700a311
2 changed files with 30 additions and 15 deletions

View file

@ -86,7 +86,8 @@
(update-in page-meta [:layout] #(str (name %) ".html")) (update-in page-meta [:layout] #(str (name %) ".html"))
{:file-name file-name {:file-name file-name
:content content :content content
:toc (if (:toc page-meta) (generate-toc content))})) :toc (if-let [toc (:toc page-meta)]
(generate-toc content :list-type toc))}))
(defn parse-page (defn parse-page
"Parses a page/post and returns a map of the content, uri, date etc." "Parses a page/post and returns a map of the content, uri, date etc."

View file

@ -18,6 +18,7 @@
headings))) headings)))
[] content)) [] content))
(defn make-links (defn make-links
"Create a table of contents from the given headings. This function will look "Create a table of contents from the given headings. This function will look
for either: for either:
@ -27,7 +28,8 @@
(2) headings with an id attribute, e.g. <h1 id=\"reference\">Reference Title</h1> (2) headings with an id attribute, e.g. <h1 id=\"reference\">Reference Title</h1>
In both cases above, the anchor reference becomes \"#reference\" and the In both cases above, the anchor reference becomes \"#reference\" and the
anchor text is \"Reference Title\"." anchor text is \"Reference Title\"."
[headings] [headings li-tags]
(let [[li-open li-close] li-tags]
(loop [items headings acc nil _last nil] (loop [items headings acc nil _last nil]
(if-let [{tag :tag {id :id} :attrs [{{name :name} :attrs} title :as htext] :content} (first items)] (if-let [{tag :tag {id :id} :attrs [{{name :name} :attrs} title :as htext] :content} (first items)]
(let [anchor (or id name)] (let [anchor (or id name)]
@ -35,18 +37,30 @@
(recur (rest items) acc nil) (recur (rest items) acc nil)
(let [entry [:li [:a {:href (str "#" anchor)} (or title (first htext))]] (let [entry [:li [:a {:href (str "#" anchor)} (or title (first htext))]]
jump (compare_index _last tag)] jump (compare_index _last tag)]
(cond (> jump 0) (recur (rest items) (str acc "<ol>" (hiccup/html entry)) tag) (cond (> jump 0) (recur (rest items) (str acc li-open (hiccup/html entry)) tag)
(= jump 0) (recur (rest items) (str acc (hiccup/html entry)) tag) (= jump 0) (recur (rest items) (str acc (hiccup/html entry)) tag)
(< jump 0) (recur (rest items) (str acc (apply str (repeat (* -1 jump) "</ol>")) (< jump 0) (recur (rest items) (str acc (apply str (repeat (* -1 jump) li-close))
(hiccup/html entry)) tag))))) (hiccup/html entry)) tag)))))
(str acc "</ol>")))) (str acc li-close)))))
(defn generate-toc [^String html]
(def _list-types {true ["<ol>" "</ol>"] :ol ["<ol>" "</ol>"] :ul ["<ul>" "</ul>"]})
(defn generate-toc [^String html & {list-type :list-type :or {list-type true}}]
"Reads an HTML string and parses it for headers, then returns a list of links
to them.
Optionally, a map of :list-type can be provided with value :ul, :ol, or true.
:ol and true will result in an ordered list being generated for the table of
contents, while :ul will result in an unordered list. The default is an
ordered list."
(let [li-tags (list-type _list-types)
top-tag (li-tags -> first (subs 1 3))]
(-> html (-> html
(.getBytes "UTF-8") (.getBytes "UTF-8")
(java.io.ByteArrayInputStream.) (java.io.ByteArrayInputStream.)
(html/parse) (html/parse)
:content :content
(get-headings) (get-headings)
(make-links) (make-links li-tags)
(clojure.string/replace-first #"ol" "ol class=\"contents\""))) (clojure.string/replace-first
(re-pattern top-tag) (str top-tag "class=\"contents\"")))))