add css stylesheet string generation functionality
This commit is contained in:
parent
a74fdd5ae6
commit
eadbe13ee1
|
@ -11,4 +11,9 @@
|
|||
[hiccup "1.0.5"]]
|
||||
|
||||
: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
53
src/clj_htmltopdf/css.clj
Normal 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)))
|
107
test/clj_htmltopdf/test/css.clj
Normal file
107
test/clj_htmltopdf/test/css.clj
Normal 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)
|
Loading…
Reference in a new issue