add css stylesheet string generation functionality

This commit is contained in:
Gered 2017-04-01 18:24:34 -04:00
parent a74fdd5ae6
commit eadbe13ee1
3 changed files with 166 additions and 1 deletions

View file

@ -11,4 +11,9 @@
[hiccup "1.0.5"]] [hiccup "1.0.5"]]
:profiles {:provided :profiles {:provided
{:dependencies [[org.clojure/clojure "1.8.0"]]}}) {:dependencies [[org.clojure/clojure "1.8.0"]]}
:dev
{:dependencies [[pjstadig/humane-test-output "0.8.1"]]
:injections [(require 'pjstadig.humane-test-output)
(pjstadig.humane-test-output/activate!)]}})

53
src/clj_htmltopdf/css.clj Normal file
View file

@ -0,0 +1,53 @@
(ns clj-htmltopdf.css
(:require
[clojure.string :as string])
(:import
[java.lang StringBuilder]))
; everything in this namespace solely exists because garden cannot be used
; to define suitable @page css that we will require.
; and it defines a bunch of its internal extension functionality as private.
; *sigh*
(defn css-rule-name-str
[names]
(let [names (map #(if (keyword? %) (name %) %) names)]
(string/join ", " names)))
(defn css-attr-str
[attr-name attr-value]
(let [attr-name (if (keyword? attr-name) (name attr-name) attr-name)
attr-value (str attr-value)]
(if (and (not (string/blank? attr-name)) (not (string/blank? attr-value)))
(str attr-name ": " attr-value ";"))))
(defn css-rule->str
[^StringBuilder sb rule & [level]]
(if (seq rule)
(let [level (or level 0)
indent (string/join (repeat level " "))
attr-indent (str indent " ")
names (take-while #(or (keyword? %) (string? %)) rule)
rule (drop (count names) rule)
attrs (first rule)
sub-rules (rest rule)]
(.append sb indent)
(.append sb (css-rule-name-str names))
(.append sb " {\n")
(doseq [[attr-name attr-value] attrs]
(when-let [attr-str (css-attr-str attr-name attr-value)]
(.append sb attr-indent)
(.append sb attr-str)
(.append sb \newline)))
(doseq [sub-rule sub-rules]
(css-rule->str sb sub-rule (inc level)))
(.append sb indent)
(.append sb "}\n")))
sb)
(defn css->str
[rules]
(let [sb (StringBuilder.)]
(doseq [rule rules]
(css-rule->str sb rule))
(.toString sb)))

View file

@ -0,0 +1,107 @@
(ns clj-htmltopdf.test.css
(:use
clojure.test
clj-htmltopdf.css)
(:import
[java.lang StringBuilder]))
(deftest rule-name-parsing
(is (= ""
(css-rule-name-str nil)))
(is (= ""
(css-rule-name-str [])))
(is (= "p"
(css-rule-name-str ["p"])))
(is (= "p"
(css-rule-name-str [:p])))
(is (= "p, li"
(css-rule-name-str ["p" :li])))
(is (= "h1, h2, h3, h4, h5, h6"
(css-rule-name-str [:h1 :h2 :h3 :h4 :h5 :h6])))
(is (= "ul>li, ol>li"
(css-rule-name-str [:ul>li :ol>li])))
(is (= "ul>li, ol>li"
(css-rule-name-str ["ul>li" "ol>li"]))))
(deftest rule-attribute-parsing
(is (= "color: black;"
(css-attr-str :color "black")))
(is (= "color: #ff0000;"
(css-attr-str "color" "#ff0000")))
(is (= nil
(css-attr-str nil "foo")))
(is (= nil
(css-attr-str :color nil)))
(is (= nil
(css-attr-str "" "bar")))
(is (= nil
(css-attr-str :color "")))
(is (= nil
(css-attr-str nil nil))))
(deftest rule-parsing
(is (= ""
(str (css-rule->str (StringBuilder.) nil))))
(is (= ""
(str (css-rule->str (StringBuilder.) []))))
(is (= "p {\n}\n"
(str (css-rule->str (StringBuilder.) [:p]))))
(is (= "p {\n}\n"
(str (css-rule->str (StringBuilder.) [:p {}]))))
(is (= "p {\n font-weight: bold;\n}\n"
(str (css-rule->str (StringBuilder.) [:p {:font-weight "bold"}]))))
(is (= "p {\n font-weight: bold;\n color: #000;\n}\n"
(str (css-rule->str (StringBuilder.) [:p {:font-weight "bold" :color "#000"}]))))
(is (= "@page {\n size: 8.5in 11in;\n margin: 10%;\n @top-right {\n content: \"Page \" counter(page);\n }\n @top-left {\n content: \"Foobar\";\n border: solid red;\n }\n}\n"
(str (css-rule->str
(StringBuilder.)
["@page"
{:size "8.5in 11in" :margin "10%"}
["@top-right"
{:content "\"Page \" counter(page)"}]
["@top-left"
{:content "\"Foobar\""
:border "solid red"}]])))))
(deftest sheet-parsing
(is (= ""
(css->str nil)))
(is (= ""
(css->str [])))
(is (thrown?
java.lang.IllegalArgumentException
(css->str [:body {:color "red"}])))
(is (= "body {\n}\n"
(css->str [[:body]])))
(is (= "body {\n}\n"
(css->str [[:body {}]])))
(is (= "body {\n}\np {\n font-size: 12pt;\n}\n"
(css->str
[[:body {}]
[:p {:font-size "12pt"}]])))
(is (thrown?
java.lang.IllegalArgumentException
(css->str
[[:body {}]
:p])))
(is (= "body {\n background-color: white;\n color: black;\n}\np {\n font-size: 12pt;\n}\n"
(css->str
[[:body
{:background-color "white"
:color "black"}]
[:p
{:font-size "12pt"}]])))
(is (= "body {\n background-color: white;\n color: black;\n}\n@page {\n size: 8.5in 11in;\n margin: 10%;\n @top-right {\n content: \"Page \" counter(page);\n }\n @top-left {\n content: \"Foobar\";\n border: solid red;\n }\n}\n"
(css->str
[[:body
{:background-color "white"
:color "black"}]
["@page"
{:size "8.5in 11in" :margin "10%"}
["@top-right"
{:content "\"Page \" counter(page)"}]
["@top-left"
{:content "\"Foobar\""
:border "solid red"}]]]))))
#_(run-tests)