diff --git a/.gitignore b/.gitignore index 296ef05..170826d 100644 --- a/.gitignore +++ b/.gitignore @@ -3,6 +3,7 @@ /codox /classes /checkouts +/ebin pom.xml pom.xml.asc *.jar diff --git a/src/hiccup.app.src b/src/hiccup.app.src new file mode 100644 index 0000000..6b262b0 --- /dev/null +++ b/src/hiccup.app.src @@ -0,0 +1,13 @@ +{ application +, hiccup, + [ {description, "A fast library for rendering HTML in Clojure"} + , {vsn, git} + , {registered, []} + , {applications, [kernel, stdlib]} + , {env,[]} + , {modules, []} + , {maintainers, []} + , {licenses, []} + , {links, []} + ] +}. diff --git a/src/hiccup/compiler.clj b/src/hiccup/compiler.cljc similarity index 85% rename from src/hiccup/compiler.clj rename to src/hiccup/compiler.cljc index 21dd879..e59a9a1 100644 --- a/src/hiccup/compiler.clj +++ b/src/hiccup/compiler.cljc @@ -2,8 +2,12 @@ "Internal functions for compilation." (:require [hiccup.util :as util] [clojure.string :as str]) - (:import [clojure.lang IPersistentVector ISeq Named] - [hiccup.util RawString])) + #?(:clj + (:import [clojure.lang IPersistentVector ISeq Named] + [hiccup.util RawString]) + :clje + (:import [clojerl Vector List INamed String Integer Float] + [hiccup.util RawString]))) (defn- xml-mode? [] (#{:xml :xhtml} util/*html-mode*)) @@ -99,7 +103,8 @@ (defn- normalize-element* [[tag & content] merge-attributes-fn] (when (not (or (keyword? tag) (symbol? tag) (string? tag))) - (throw (IllegalArgumentException. (str tag " is not a valid element name.")))) + (throw #?(:clj (IllegalArgumentException. (str tag " is not a valid element name.")) + :clje (str tag " is not a valid element name.")))) (let [[_ tag id class] (re-matches re-tag (util/as-str tag)) classes (if class (str/replace class "." " ")) map-attrs (first content)] @@ -130,25 +135,46 @@ "") (str "<" tag (render-attr-map attrs) (end-tag))))) -(extend-protocol HtmlRenderer - IPersistentVector - (render-html [this] - (render-element this)) - ISeq - (render-html [this] - (apply str (map render-html this))) - RawString - (render-html [this] - (str this)) - Named - (render-html [this] - (escape-html (name this))) - Object - (render-html [this] - (escape-html (str this))) - nil - (render-html [this] - "")) +#?(:clj + (extend-protocol HtmlRenderer + IPersistentVector + (render-html [this] + (render-element this)) + ISeq + (render-html [this] + (apply str (map render-html this))) + RawString + (render-html [this] + (str this)) + Named + (render-html [this] + (escape-html (name this))) + Object + (render-html [this] + (escape-html (str this))) + nil + (render-html [this] + "")) + :clje + (extend-protocol HtmlRenderer + Vector + (render-html [this] + (render-element this)) + RawString + (render-html [this] + (str this)) + default + (render-html [this] + (cond + (seq? this) + (apply str (map render-html this)) + (satisfies? clojerl.INamed this) + (escape-html (name this)) + :else + (escape-html (str this)))) + nil + (render-html [this] + ""))) (defn- unevaluated? "True if the expression has not been evaluated." @@ -214,7 +240,10 @@ [x] (or (= (form-name x) "for") (not (unevaluated? x)) - (not-hint? x java.util.Map))) + #?(:clj + (not-hint? x java.util.Map) + :clje + (not-hint? x clojerl.Map)))) (defn- element-compile-strategy "Returns the compilation strategy to use for a given element." @@ -296,7 +325,9 @@ (util/raw-string? expr) expr (literal? expr) (escape-html expr) (hint? expr String) `(escape-html ~expr) - (hint? expr Number) expr + #?@(:clj [(hint? expr Number) expr] + :clje [(or (hint? expr Float) + (hint? expr Integer)) expr]) (seq? expr) (compile-form expr) :else `(render-html ~expr))))) @@ -337,7 +368,8 @@ (= (set vals) #{true false}) `(if ~var-sym ~(compiled-forms true) ~(compiled-forms false)) :else - `(case ~var-sym ~@(apply concat distinct-forms))))) + #?(:clj `(case ~var-sym ~@(apply concat distinct-forms)) + :clje `(case ~var-sym ~@(apply concat compiled-forms)))))) (defn compile-html-with-bindings "Pre-compile data structures into HTML where possible, while taking into diff --git a/src/hiccup/core.clj b/src/hiccup/core.cljc similarity index 100% rename from src/hiccup/core.clj rename to src/hiccup/core.cljc diff --git a/src/hiccup/def.clj b/src/hiccup/def.cljc similarity index 85% rename from src/hiccup/def.clj rename to src/hiccup/def.cljc index 0df3941..5ed3112 100644 --- a/src/hiccup/def.clj +++ b/src/hiccup/def.cljc @@ -35,6 +35,9 @@ passed to the resulting function is a map, it merges it with the attribute map of the returned element value." [name & fdecl] - `(do (defn ~name ~@fdecl) - (alter-meta! (var ~name) update-in [:arglists] #'update-arglists) - (alter-var-root (var ~name) wrap-attrs))) + #?(:clj + `(do (defn ~name ~@fdecl) + (alter-meta! (var ~name) update-in [:arglists] #'update-arglists) + (alter-var-root (var ~name) wrap-attrs)) + :clje + `(defn ~name ~@fdecl))) diff --git a/src/hiccup/element.clj b/src/hiccup/element.cljc similarity index 100% rename from src/hiccup/element.clj rename to src/hiccup/element.cljc diff --git a/src/hiccup/form.clj b/src/hiccup/form.cljc similarity index 100% rename from src/hiccup/form.clj rename to src/hiccup/form.cljc diff --git a/src/hiccup/middleware.clj b/src/hiccup/middleware.cljc similarity index 100% rename from src/hiccup/middleware.clj rename to src/hiccup/middleware.cljc diff --git a/src/hiccup/page.clj b/src/hiccup/page.cljc similarity index 100% rename from src/hiccup/page.clj rename to src/hiccup/page.cljc diff --git a/src/hiccup/util.clj b/src/hiccup/util.clj deleted file mode 100644 index 833eac5..0000000 --- a/src/hiccup/util.clj +++ /dev/null @@ -1,123 +0,0 @@ -(ns hiccup.util - "Utility functions for Hiccup." - (:require [clojure.string :as str]) - (:import java.net.URI - java.net.URLEncoder)) - -(def ^:dynamic ^:no-doc *html-mode* :xhtml) - -(def ^:dynamic ^:no-doc *escape-strings?* true) - -(def ^:dynamic ^:no-doc *base-url* nil) - -(def ^:dynamic ^:no-doc *encoding* "UTF-8") - -(defmacro with-base-url - "Sets a base URL that will be prepended onto relative URIs. Note that for this - to work correctly, it needs to be placed outside the [[hiccup.core/html]] or - [[hiccup2.core/html]] macros." - [base-url & body] - `(binding [*base-url* ~base-url] - ~@body)) - -(defprotocol ToString - (^String to-str [x] "Convert a value into a string.")) - -(extend-protocol ToString - clojure.lang.Keyword - (to-str [k] (name k)) - clojure.lang.Ratio - (to-str [r] (str (float r))) - java.net.URI - (to-str [u] - (if (or (.getHost u) - (nil? (.getPath u)) - (not (-> (.getPath u) (.startsWith "/")))) - (str u) - (let [base (str *base-url*)] - (if (.endsWith base "/") - (str (subs base 0 (dec (count base))) u) - (str base u))))) - Object - (to-str [x] (str x)) - nil - (to-str [_] "")) - -(defn ^String as-str - "Converts its arguments into a string using [[to-str]]." - [& xs] - (apply str (map to-str xs))) - -(defprotocol ToURI - (^java.net.URI to-uri [x] "Convert a value into a URI.")) - -(extend-protocol ToURI - java.net.URI - (to-uri [u] u) - String - (to-uri [s] (URI. s))) - -(deftype RawString [^String s] - Object - (^String toString [this] s) - (^boolean equals [this other] - (and (instance? RawString other) - (= s (.toString other))))) - -(defn raw-string - "Converts one or more strings into an object that will not be escaped when - used with the [[hiccup2.core/html]] macro." - {:arglists '([& xs])} - ([] (RawString. "")) - ([x] (RawString. (str x))) - ([x & xs] (RawString. (apply str x xs)))) - -(defn raw-string? - "Returns true if x is a RawString created by [[raw-string]]." - [x] - (instance? RawString x)) - -(defn escape-html - "Change special characters into HTML character entities." - [text] - (.. ^String (as-str text) - (replace "&" "&") - (replace "<" "<") - (replace ">" ">") - (replace "\"" """) - (replace "'" (if (= *html-mode* :sgml) "'" "'")))) - -(defmacro with-encoding - "Sets a default encoding for URL encoding strings. Defaults to UTF-8." - [encoding & body] - `(binding [*encoding* ~encoding] - ~@body)) - -(defprotocol URLEncode - (url-encode [x] "Turn a value into a URL-encoded string.")) - -(extend-protocol URLEncode - String - (url-encode [s] (URLEncoder/encode s *encoding*)) - java.util.Map - (url-encode [m] - (str/join "&" - (for [[k v] m] - (str (url-encode k) "=" (url-encode v))))) - Object - (url-encode [x] (url-encode (to-str x)))) - -(defn url - "Creates a URI instance from a variable list of arguments and an optional - parameter map as the last argument. For example: - - (url \"/group/\" 4 \"/products\" {:page 9}) - => \"/group/4/products?page=9\"" - [& args] - (let [params (last args), args (butlast args)] - (to-uri - (str (apply str args) - (if (map? params) - (str "?" (url-encode params)) - params))))) - diff --git a/src/hiccup/util.cljc b/src/hiccup/util.cljc new file mode 100644 index 0000000..ac446b1 --- /dev/null +++ b/src/hiccup/util.cljc @@ -0,0 +1,163 @@ +(ns hiccup.util + "Utility functions for Hiccup." + (:require [clojure.string :as str]) + #?(:clj (:import java.net.URI + java.net.URLEncoder) + :clje (:import clojerl.String))) + +(def ^:dynamic ^:no-doc *html-mode* :xhtml) + +(def ^:dynamic ^:no-doc *escape-strings?* true) + +(def ^:dynamic ^:no-doc *base-url* nil) + +(def ^:dynamic ^:no-doc *encoding* "UTF-8") + +(defmacro with-base-url + "Sets a base URL that will be prepended onto relative URIs. Note that for this + to work correctly, it needs to be placed outside the [[hiccup.core/html]] or + [[hiccup2.core/html]] macros." + [base-url & body] + `(binding [*base-url* ~base-url] + ~@body)) + +(defprotocol ToString + (^String to-str [x] "Convert a value into a string.")) + +#?(:clj + (extend-protocol ToString + clojure.lang.Keyword + (to-str [k] (name k)) + clojure.lang.Ratio + (to-str [r] (str (float r))) + java.net.URI + (to-str [u] + (if (or (.getHost u) + (nil? (.getPath u)) + (not (-> (.getPath u) (.startsWith "/")))) + (str u) + (let [base (str *base-url*)] + (if (.endsWith base "/") + (str (subs base 0 (dec (count base))) u) + (str base u))))) + Object + (to-str [x] (str x)) + nil + (to-str [_] "")) + + :clje + (extend-protocol ToString + clojerl.Keyword + (to-str [k] (name k)) + default + (to-str [x] (str x)) + nil + (to-str [_] ""))) + +(defn ^String as-str + "Converts its arguments into a string using [[to-str]]." + [& xs] + (apply str (map to-str xs))) + +#?(:clj + (defprotocol ToURI + (^java.net.URI to-uri [x] "Convert a value into a URI.")) + :clje + (defprotocol ToURI + (^clojerl.String to-uri [x] "Convert a value into a URI."))) + +#?(:clj + (extend-protocol ToURI + java.net.URI + (to-uri [u] u) + String + (to-uri [s] (URI. s))) + :clje + (extend-protocol ToURI + String + (to-uri [s] s))) + +#?(:clj + (deftype RawString [^String s] + Object + (^String toString [this] s) + (^boolean equals [this other] + (and (instance? RawString other) + (= s (.toString other))))) + :clje + (deftype RawString [^String s] + clojerl.IStringable + (^String str [this] s) + clojerl.IEquiv + (^clojerl.Boolean equiv [this other] + (and (instance? RawString other) + (= s (str other)))))) + +(defn raw-string + "Converts one or more strings into an object that will not be escaped when + used with the [[hiccup2.core/html]] macro." + {:arglists '([& xs])} + ([] (RawString. "")) + ([x] (RawString. (str x))) + ([x & xs] (RawString. (apply str x xs)))) + +(defn raw-string? + "Returns true if x is a RawString created by [[raw-string]]." + [x] + (instance? RawString x)) + +(defn escape-html + "Change special characters into HTML character entities." + [text] + (.. ^String (as-str text) + (replace "&" "&") + (replace "<" "<") + (replace ">" ">") + (replace "\"" """) + (replace "'" (if (= *html-mode* :sgml) "'" "'")))) + +(defmacro with-encoding + "Sets a default encoding for URL encoding strings. Defaults to UTF-8." + [encoding & body] + `(binding [*encoding* ~encoding] + ~@body)) + +(defprotocol URLEncode + (url-encode [x] "Turn a value into a URL-encoded string.")) + +#?(:clj + (extend-protocol URLEncode + String + (url-encode [s] (URLEncoder/encode s *encoding*)) + java.util.Map + (url-encode [m] + (str/join "&" + (for [[k v] m] + (str (url-encode k) "=" (url-encode v))))) + Object + (url-encode [x] (url-encode (to-str x)))) + :clje + (extend-protocol URLEncode + String + (url-encode [s] (http_uri/encode s)) + clojerl.Map + (url-encode [m] + (str/join "&" + (for [[k v] m] + (str (url-encode k) "=" (url-encode v))))) + default + (url-encode [x] (url-encode (to-str x))))) + +(defn url + "Creates a URI instance from a variable list of arguments and an optional + parameter map as the last argument. For example: + + (url \"/group/\" 4 \"/products\" {:page 9}) + => \"/group/4/products?page=9\"" + [& args] + (let [params (last args), args (butlast args)] + (to-uri + (str (apply str args) + (if (map? params) + (str "?" (url-encode params)) + params))))) diff --git a/src/hiccup2/core.clj b/src/hiccup2/core.cljc similarity index 100% rename from src/hiccup2/core.clj rename to src/hiccup2/core.cljc