From 482700a311872d6e05a61cf92da80b1bb78dbf5a Mon Sep 17 00:00:00 2001 From: Jeff Rabinowitz Date: Sun, 25 Oct 2015 19:14:43 -0400 Subject: [PATCH] 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 --- src/cryogen_core/compiler.clj | 3 ++- src/cryogen_core/toc.clj | 42 +++++++++++++++++++++++------------ 2 files changed, 30 insertions(+), 15 deletions(-) diff --git a/src/cryogen_core/compiler.clj b/src/cryogen_core/compiler.clj index bb54d7f..2d8a15e 100644 --- a/src/cryogen_core/compiler.clj +++ b/src/cryogen_core/compiler.clj @@ -86,7 +86,8 @@ (update-in page-meta [:layout] #(str (name %) ".html")) {:file-name file-name :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 "Parses a page/post and returns a map of the content, uri, date etc." diff --git a/src/cryogen_core/toc.clj b/src/cryogen_core/toc.clj index f576ccc..0230d75 100644 --- a/src/cryogen_core/toc.clj +++ b/src/cryogen_core/toc.clj @@ -18,6 +18,7 @@ headings))) [] content)) + (defn make-links "Create a table of contents from the given headings. This function will look for either: @@ -27,26 +28,39 @@ (2) headings with an id attribute, e.g.

Reference Title

In both cases above, the anchor reference becomes \"#reference\" and the anchor text is \"Reference Title\"." - [headings] - (loop [items headings acc nil _last nil] + [headings li-tags] + (let [[li-open li-close] li-tags] + (loop [items headings acc nil _last nil] (if-let [{tag :tag {id :id} :attrs [{{name :name} :attrs} title :as htext] :content} (first items)] (let [anchor (or id name)] (if (nil? anchor) (recur (rest items) acc nil) (let [entry [:li [:a {:href (str "#" anchor)} (or title (first htext))]] jump (compare_index _last tag)] - (cond (> jump 0) (recur (rest items) (str acc "
    " (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 (apply str (repeat (* -1 jump) "
")) + (< jump 0) (recur (rest items) (str acc (apply str (repeat (* -1 jump) li-close)) (hiccup/html entry)) tag))))) - (str acc "")))) + (str acc li-close))))) -(defn generate-toc [^String html] - (-> html - (.getBytes "UTF-8") - (java.io.ByteArrayInputStream.) - (html/parse) - :content - (get-headings) - (make-links) - (clojure.string/replace-first #"ol" "ol class=\"contents\""))) + +(def _list-types {true ["
    " "
"] :ol ["
    " "
"] :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 + (.getBytes "UTF-8") + (java.io.ByteArrayInputStream.) + (html/parse) + :content + (get-headings) + (make-links li-tags) + (clojure.string/replace-first + (re-pattern top-tag) (str top-tag "class=\"contents\"")))))