Skip to content
Browse files

merge

Signed-off-by: Chris Granger <ibdknox@gmail.com>
  • Loading branch information...
2 parents 3926cf4 + caf3f10 commit 1bc3e53cc1c3965c85dcaa22058c004ec739ca85 @ibdknox committed May 4, 2012
View
2 README.md
@@ -6,7 +6,7 @@ Crate is a ClojureScript implementation of the awesome [Hiccup](https://github.c
```clojure
(ns myapp
- (:use-macros [defpartial])
+ (:use-macros [crate.def-macros :only [defpartial]])
(:require [crate.core :as crate]))
(crate/html [:p.woot {:id "blah"} "Hey!"])
View
96 src/crate/compiler.cljs
@@ -0,0 +1,96 @@
+(ns crate.compiler
+ (:require [goog.dom :as gdom]
+ [clojure.string :as string]))
+
+(def xmlns {:xhtml "http://www.w3.org/1999/xhtml"
+ :svg "http://www.w3.org/2000/svg"})
+
+;; ********************************************
+;; Element creation via Hiccup-like vectors
+;; ********************************************
+
+(declare elem-factory)
+(def group-id (atom 0))
+
+(defn dom-attr
+ ([elem attrs]
+ (when elem
+ (if-not (map? attrs)
+ (. elem (getAttribute (name attrs)))
+ (do
+ (doseq [[k v] attrs]
+ (dom-attr elem k v))
+ elem))))
+ ([elem k v]
+ (. elem (setAttribute (name k) v))
+ elem))
+
+(defn as-content [parent content]
+ (doseq[c content]
+ (let [child (cond
+ (nil? c) nil
+ (map? c) (throw "Maps cannot be used as content")
+ (string? c) (gdom/createTextNode c)
+ (vector? c) (elem-factory c)
+ ;;TODO: there's a bug in clojurescript that prevents seqs from
+ ;; being considered collections
+ (seq? c) (as-content parent c)
+ (.-nodeName c) c)]
+ (when child
+ (gdom/appendChild parent child)))))
+
+;; From Weavejester's Hiccup: https://github.com/weavejester/hiccup/blob/master/src/hiccup/core.clj#L57
+(def ^{:doc "Regular expression that parses a CSS-style id and class from a tag name." :private true}
+ re-tag #"([^\s\.#]+)(?:#([^\s\.#]+))?(?:\.([^\s#]+))?")
+
+(defn- normalize-element
+ "Ensure a tag vector is of the form [tag-name attrs content]."
+ [[tag & content]]
+ (when (not (or (keyword? tag) (symbol? tag) (string? tag)))
+ (throw (str tag " is not a valid tag name.")))
+ (let [[_ tag id class] (re-matches re-tag (name tag))
+ [nsp tag] (let [[nsp t] (string/split tag #":")
+ ns-xmlns (xmlns (keyword nsp))]
+ (if t
+ [(or ns-xmlns nsp) t]
+ [(:xhtml xmlns) nsp]))
+ tag-attrs (into {}
+ (filter #(not (nil? (second %)))
+ {:id (or id nil)
+ :class (if class (string/replace class #"\." " "))}))
+ map-attrs (first content)]
+ (if (map? map-attrs)
+ [nsp tag (merge tag-attrs map-attrs) (next content)]
+ [nsp tag tag-attrs content])))
+
+(defn parse-content [elem content]
+ (let [attrs (first content)]
+ (if (map? attrs)
+ (do
+ (dom-attr elem attrs)
+ (rest content))
+ content)))
+
+(def create-elem (if (.-createElementNS js/document)
+ (fn [nsp tag]
+ (.createElementNS js/document nsp tag))
+ (fn [_ tag]
+ (.createElement js/document tag))))
+
+(defn elem-factory [tag-def]
+ (let [[nsp tag attrs content] (normalize-element tag-def)
+ elem (create-elem nsp tag)]
+ (dom-attr elem attrs)
+ (as-content elem content)
+ elem))
+
+(defn add-optional-attrs
+ "Add an optional attribute argument to a function that returns a vector tag."
+ [func]
+ (fn [& args]
+ (if (map? (first args))
+ (let [[tag & body] (apply func (rest args))]
+ (if (map? (first body))
+ (apply vector tag (merge (first body) (first args)) (rest body))
+ (apply vector tag (first args) body)))
+ (apply func args))))
View
135 src/crate/core.cljs
@@ -1,136 +1,13 @@
(ns crate.core
- (:require [goog.dom :as gdom]
- [clojure.string :as string]))
-
-(def xmlns {:xhtml "http://www.w3.org/1999/xhtml"
- :svg "http://www.w3.org/2000/svg"})
-
-;; ********************************************
-;; Element creation via Hiccup-like vectors
-;; ********************************************
-
-(declare elem-factory)
-(def group-id (atom 0))
-
-(defn dom-attr
- ([elem attrs]
- (when elem
- (if-not (map? attrs)
- (. elem (getAttribute (name attrs)))
- (do
- (doseq [[k v] attrs]
- (dom-attr elem k v))
- elem))))
- ([elem k v]
- (. elem (setAttribute (name k) v))
- elem))
-
-(defn as-content [parent content]
- (doseq[c content]
- (let [child (cond
- (nil? c) nil
- (map? c) (throw "Maps cannot be used as content")
- (string? c) (gdom/createTextNode c)
- (vector? c) (elem-factory c)
- ;;TODO: there's a bug in clojurescript that prevents seqs from
- ;; being considered collections
- (seq? c) (as-content parent c)
- (.-nodeName c) c)]
- (when child
- (gdom/appendChild parent child)))))
-
-;; From Weavejester's Hiccup: https://github.com/weavejester/hiccup/blob/master/src/hiccup/core.clj#L57
-(def ^{:doc "Regular expression that parses a CSS-style id and class from a tag name." :private true}
- re-tag #"([^\s\.#]+)(?:#([^\s\.#]+))?(?:\.([^\s#]+))?")
-
-(defn- normalize-element
- "Ensure a tag vector is of the form [tag-name attrs content]."
- [[tag & content]]
- (when (not (or (keyword? tag) (symbol? tag) (string? tag)))
- (throw (str tag " is not a valid tag name.")))
- (let [[_ tag id class] (re-matches re-tag (name tag))
- [nsp tag] (let [[nsp t] (string/split tag #":")
- ns-xmlns (xmlns (keyword nsp))]
- (if t
- [(or ns-xmlns nsp) t]
- [(:xhtml xmlns) nsp]))
- tag-attrs (into {}
- (filter #(not (nil? (second %)))
- {:id (or id nil)
- :class (if class (string/replace class #"\." " "))}))
- map-attrs (first content)]
- (if (map? map-attrs)
- [nsp tag (merge tag-attrs map-attrs) (next content)]
- [nsp tag tag-attrs content])))
-
-(defn parse-content [elem content]
- (let [attrs (first content)]
- (if (map? attrs)
- (do
- (dom-attr elem attrs)
- (rest content))
- content)))
-
-(def create-elem (if (.-createElementNS js/document)
- (fn [nsp tag]
- (.createElementNS js/document nsp tag))
- (fn [_ tag]
- (.createElement js/document tag))))
-
-(defn elem-factory [tag-def]
- (let [[nsp tag attrs content] (normalize-element tag-def)
- elem (create-elem nsp tag)]
- (dom-attr elem attrs)
- (as-content elem content)
- elem))
+ (:require
+ [crate.compiler :as compiler]
+ [crate.util :as util]))
(defn html [& tags]
- (let [res (map elem-factory tags)]
+ (let [res (map compiler/elem-factory tags)]
(if (second res)
res
(first res))))
-(defn add-optional-attrs
- "Add an optional attribute argument to a function that returns a vector tag."
- [func]
- (fn [& args]
- (if (map? (first args))
- (let [[tag & body] (apply func (rest args))]
- (if (map? (first body))
- (apply vector tag (merge (first body) (first args)) (rest body))
- (apply vector tag (first args) body)))
- (apply func args))))
-
-(defn as-str
- ([] "")
- ([x]
- ; TODO: Maybe use something like (satisfies? INamed x) instead?
- (if (or (symbol? x) (keyword? x))
- (name x)
- (str x)))
- ([x & xs]
- ((fn [s more]
- (if more
- (recur (str s (as-str (first more))) (next more))
- s))
- (as-str x) xs)))
-
-(def ^:dynamic *html-mode* :xml)
-
-(defn escape-html
- "Change special characters into HTML character entities."
- [text]
- (.. (as-str text)
- (replace "&" "&amp;")
- (replace "<" "&lt;")
- (replace ">" "&gt;")
- (replace "\"" "&quot;")))
-
-(def ^:dynamic *base-url* nil)
-
-(defn resolve-uri
- "Prepends the base-url to the supplied URI."
- [uri]
- (if (re-matches #"^\w+:.*" uri)
- uri
- (str *base-url* uri)))
+(def ^ {:doc "Alias for crate.util/escape-html"}
+ h util/escape-html)
View
21 src/crate/macros.clj → src/crate/def_macros.clj
@@ -1,4 +1,4 @@
-(ns crate.macros)
+(ns crate.def-macros)
(defmacro defpartial
[name params & body]
@@ -21,18 +21,7 @@
passed to the resulting function is a map, it merges it with the attribute
map of the returned tag value."
[name & fdecl]
- `(let [func# (fn ~@fdecl)]
- (def ~name (crate.core/add-optional-attrs func#))))
-
-(defmacro with-base-url
- "Add a base-url that will be added to the output of the resolve-uri function."
- [base-url & body]
- `(binding [crate.core/*base-url* ~base-url]
- ~@body))
-
-(defmacro with-group
- "Group together a set of related form fields for use with the Ring
- nested-params middleware."
- [group & body]
- `(binding [crate.form-helpers/*group* (conj crate.form-helpers/*group* (crate.core/as-str ~group))]
- (list ~@body)))
+ `(do
+ (declare ~name)
+ (let [func# (fn ~@fdecl)]
+ (def ~name (crate.compiler/add-optional-attrs func#)))))
View
34 src/crate/element.cljs
@@ -0,0 +1,34 @@
+(ns crate.element
+ (:use [crate.util :only [to-uri]])
+ (:use-macros [crate.def-macros :only [defelem]])
+ (:require
+ ; Must require crate.compiler for defelem to work.
+ [crate.compiler :as compiler]
+ [clojure.string :as str]))
+
+(defn javascript-tag
+ "Wrap the supplied javascript up in script tags and a CDATA section."
+ [script]
+ [:script {:type "text/javascript"}
+ (str "//<![CDATA[\n" script "\n//]]>")])
+
+(defelem link-to
+ [url & content]
+ [:a {:href (to-uri url)} content])
+
+(defelem mail-to
+ [e-mail & [content]]
+ [:a {:href (str "mailto:" e-mail)}
+ (or content e-mail)])
+
+(defelem unordered-list
+ [coll]
+ [:ul (for [x coll] [:li x])])
+
+(defelem ordered-list
+ [coll]
+ [:ol (for [x coll] [:li x])])
+
+(defelem image
+ ([src] [:img {:src (to-uri src)}])
+ ([src alt] [:img {:src (to-uri src), :alt alt}]))
View
10 src/crate/form_helpers.cljs → src/crate/form.cljs
@@ -1,6 +1,8 @@
-(ns crate.form-helpers
- (:use [crate.core :only [escape-html resolve-uri as-str]])
- (:use-macros [crate.macros :only [defelem]]))
+(ns crate.form
+ (:use [crate.util :only [escape-html to-uri as-str]])
+ (:use-macros [crate.def-macros :only [defelem]])
+ ; Must require crate.compiler for defelem to work.
+ (:require [crate.compiler :as compiler]))
(def ^:dynamic *group* [])
@@ -100,7 +102,7 @@
(defelem form-to
[[method action] & body]
(let [method-str (.toUpperCase (name method))
- action-uri (resolve-uri action)]
+ action-uri (to-uri action)]
(-> (if (contains? #{:get :post} method)
[:form {:method method-str, :action action-uri}]
[:form {:method "POST", :action action-uri}
View
8 src/crate/form_macros.clj
@@ -0,0 +1,8 @@
+(ns crate.form-macros)
+
+(defmacro with-group
+ "Group together a set of related form fields for use with the Ring
+ nested-params middleware."
+ [group & body]
+ `(binding [crate.form/*group* (conj crate.form/*group* (crate.util/as-str ~group))]
+ (list ~@body)))
View
14 src/crate/page.cljs
@@ -0,0 +1,14 @@
+(ns crate.page
+ (:use [crate.util :only [to-uri]]))
+
+(defn include-js
+ "Include a list of external javascript files."
+ [& scripts]
+ (for [script scripts]
+ [:script {:type "text/javascript", :src (to-uri script)}]))
+
+(defn include-css
+ "Include a list of external stylesheet files."
+ [& styles]
+ (for [style styles]
+ [:link {:type "text/css", :href (to-uri style), :rel "stylesheet"}]))
View
69 src/crate/page_helpers.cljs
@@ -1,69 +0,0 @@
-(ns crate.page-helpers
- (:use [crate.core :only [resolve-uri as-str]])
- (:use-macros [crate.macros :only [defelem]])
- (:require [clojure.string :as str]))
-
-(defn include-js
- "Include a list of external javascript files."
- [& scripts]
- (for [script scripts]
- [:script {:type "text/javascript", :src (resolve-uri script)}]))
-
-(defn include-css
- "Include a list of external stylesheet files."
- [& styles]
- (for [style styles]
- [:link {:type "text/css", :href (resolve-uri style), :rel "stylesheet"}]))
-
-(defn javascript-tag
- "Wrap the supplied javascript up in script tags and a CDATA section."
- [script]
- [:script {:type "text/javascript"}
- (str "//<![CDATA[\n" script "\n//]]>")])
-
-(defelem link-to
- [url & content]
- [:a {:href (resolve-uri url)} content])
-
-(defelem mail-to
- [e-mail & [content]]
- [:a {:href (str "mailto:" e-mail)}
- (or content e-mail)])
-
-(defelem unordered-list
- [coll]
- [:ul (for [x coll] [:li x])])
-
-(defelem ordered-list
- [coll]
- [:ol (for [x coll] [:li x])])
-
-(defelem image
- ([src] [:img {:src (resolve-uri src)}])
- ([src alt] [:img {:src (resolve-uri src), :alt alt}]))
-
-(defn encode [s]
- "urlencode"
- (js/encodeURIComponent (as-str s)))
-
-(defn encode-params
- "Turn a map of parameters into a urlencoded string."
- [params]
- (str/join "&"
- (for [[k v] params]
- (str (encode k) "=" (encode v)))))
-
-(defn url
- "Creates a URL string 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)]
- (str
- (resolve-uri
- (str (apply str args)
- (if (map? params)
- (str "?" (encode-params params))
- params))))))
View
60 src/crate/util.cljs
@@ -0,0 +1,60 @@
+(ns crate.util
+ (:require [clojure.string :as str]))
+
+(def ^:dynamic *base-url* nil)
+
+(defn as-str
+ ([] "")
+ ([x]
+ ; TODO: Maybe use something like (satisfies? INamed x) instead?
+ (if (or (symbol? x) (keyword? x))
+ (name x)
+ (str x)))
+ ([x & xs]
+ ((fn [s more]
+ (if more
+ (recur (str s (as-str (first more))) (next more))
+ s))
+ (as-str x) xs)))
+
+(defn escape-html
+ "Change special characters into HTML character entities."
+ [text]
+ (.. (as-str text)
+ (replace "&" "&amp;")
+ (replace "<" "&lt;")
+ (replace ">" "&gt;")
+ (replace "\"" "&quot;")))
+
+(defn to-uri
+ "Prepends the base-url to the supplied URI."
+ [uri]
+ (if (re-matches #"^\w+:.*" uri)
+ uri
+ (str *base-url* uri)))
+
+(defn url-encode-component [s]
+ "urlencode"
+ (js/encodeURIComponent (as-str s)))
+
+(defn url-encode
+ "Turn a map of parameters into a urlencoded string."
+ [params]
+ (str/join "&"
+ (for [[k v] params]
+ (str (url-encode-component k) "=" (url-encode-component v)))))
+
+(defn url
+ "Creates a URL string 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)]
+ (str
+ (to-uri
+ (str (apply str args)
+ (if (map? params)
+ (str "?" (url-encode params))
+ params))))))
View
7 src/crate/util_macros.clj
@@ -0,0 +1,7 @@
+(ns crate.util-macros)
+
+(defmacro with-base-url
+ "Add a base-url that will be added to the output of the to-uri function."
+ [base-url & body]
+ `(binding [crate.util/*base-url* ~base-url]
+ ~@body))

0 comments on commit 1bc3e53

Please sign in to comment.
Something went wrong with that request. Please try again.