-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
4cc07e8
commit b93144b
Showing
20 changed files
with
3,228 additions
and
3 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
## License (extracted from [README](https://github.com/jkk/formative/blob/b881a68b5ffb176a21c5939eb14abdd61c915123/README.md#license)) | ||
|
||
Copyright © 2012-2013 Justin Kramer | ||
|
||
Distributed under the Eclipse Public License, the same as Clojure. |
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,33 @@ | ||
(defproject formidable "0.1.0" | ||
:description "Web forms - rendering, parsing, and validating" | ||
:url "https://github.com/teamwall/formidable" | ||
:license {:name "Eclipse Public License" | ||
:url "http://www.eclipse.org/legal/epl-v10.html"} | ||
:dependencies [[org.clojure/clojure "1.5.1"] | ||
[jkkramer/verily "0.6.0"] | ||
[clj-time "0.8.0"] | ||
[crate "0.2.5"] | ||
[prismatic/dommy "1.0.0"] | ||
[ring-anti-forgery "0.3.0"]] | ||
:test-paths ["target/test-classes"] | ||
:cljx {:builds [{:source-paths ["src"] | ||
:output-path "target/classes" | ||
:rules :clj} | ||
{:source-paths ["src"] | ||
:output-path "target/classes" | ||
:rules :cljs} | ||
{:source-paths ["test"] | ||
:output-path "target/test-classes" | ||
:rules :clj} | ||
{:source-paths ["test"] | ||
:output-path "target/test-classes" | ||
:rules :cljs}]} | ||
:prep-tasks [["cljx" "once"]] | ||
:profiles {:dev {:dependencies [[com.cemerick/clojurescript.test "0.3.3"] | ||
[org.clojure/clojurescript "0.0-2498"] | ||
[com.cemerick/piggieback "0.1.3"] | ||
[com.keminglabs/cljx "0.5.0"]] | ||
:plugins [[com.keminglabs/cljx "0.5.0"]] | ||
:repl-options {:nrepl-middleware [cemerick.piggieback/wrap-cljs-repl | ||
cljx.repl-middleware/wrap-cljx]} | ||
:prep-tasks [["cljx" "once"]]}}) |
Large diffs are not rendered by default.
Oops, something went wrong.
Large diffs are not rendered by default.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,117 @@ | ||
(ns formidable.dom | ||
(:require [formidable.util :as fu] | ||
[formidable.parse :as fp] | ||
[formidable.render :as fr] | ||
[dommy.core :as d :refer-macros [sel sel1]] | ||
[dommy.utils :as du] | ||
[clojure.string :as string] | ||
[crate.core :as crate]) | ||
(:require-macros [formidable.macros :refer [with-fallback]])) | ||
|
||
(defn serialize | ||
"Returns a form data string for the given form element, suitable for Ajax | ||
GET/POST, or passing to formidable.parse/parse-params." | ||
[form-el] | ||
(->> (for [el (du/->Array (.-elements form-el)) | ||
:let [name (.-name el)] | ||
:when (not (string/blank? name))] | ||
(let [node-name (.-nodeName el) | ||
type (.-type el) | ||
value (.-value el)] | ||
(cond | ||
(and (= "INPUT" node-name) | ||
(#{"checkbox" "radio"} type)) | ||
(when (.-checked el) | ||
(fu/encode-uri-kv name value)) | ||
|
||
(and (= "SELECT" node-name) | ||
(= "select-multiple" type)) | ||
(->> (for [opt (du/->Array (.-options el)) | ||
:when (.-selected opt)] | ||
(fu/encode-uri-kv name (.-value opt))) | ||
(string/join "&")) | ||
|
||
(and (= "INPUT" node-name) | ||
(= "file" type)) | ||
nil | ||
|
||
:else | ||
(fu/encode-uri-kv name value)))) | ||
(remove nil?) | ||
(string/join "&"))) | ||
|
||
(defn get-form-el | ||
"Given a form container element or a form element, returns the form element" | ||
[container-or-form-el] | ||
(if (= "FORM" (.-nodeName container-or-form-el)) | ||
container-or-form-el | ||
(sel1 container-or-form-el "form"))) | ||
|
||
(defn clear-problems | ||
"Clears form problems from the DOM" | ||
[container-or-form-el] | ||
(let [form-el (get-form-el container-or-form-el)] | ||
(when-let [parent-el (.-parentNode form-el)] | ||
(when-let [problems-el (sel1 parent-el ".form-problems")] | ||
(d/remove! problems-el))) | ||
(doseq [el (sel form-el ".problem.error")] | ||
(d/remove-class! el "problem" "error")))) | ||
|
||
(defn get-scroll-top | ||
"Returns the top window scroll position" | ||
[] | ||
(if (exists? (.-pageYOffset js/window)) | ||
(.-pageYOffset js/window) | ||
(.-scrollTop (or (-> js/document .-documentElement) | ||
(-> js/document .-body .-parentNode) | ||
(-> js/document .-body))))) | ||
|
||
(defn get-offset-top | ||
"Returns an element's top offset relative to the window" | ||
[el] | ||
(let [rect (.getBoundingClientRect el)] | ||
(+ (.-top rect) (get-scroll-top)))) | ||
|
||
(defn scroll-to-el | ||
"Scrolls the window to an element's offset top" | ||
[el] | ||
(.scrollTo js/window 0 (- (get-offset-top el) 10))) | ||
|
||
(defn show-problems | ||
"Shows form problems in the DOM" | ||
[form-spec container-or-form-el problems] | ||
(let [form-el (get-form-el container-or-form-el)] | ||
(clear-problems form-el) | ||
(let [problems-el (crate/html (fr/render-problems problems | ||
(:fields form-spec)))] | ||
(d/insert-before! problems-el form-el) | ||
(scroll-to-el problems-el)) | ||
(doseq [problem problems | ||
:let [fnames (map name (if (map? problem) | ||
(:keys problem) | ||
[problem]))] | ||
fname fnames] | ||
(let [field-container-id (fu/get-field-container-id | ||
{:id (fu/get-field-id {:name fname}) | ||
:name fname})] | ||
(when-let [el (sel1 (str "#" field-container-id))] | ||
(d/add-class! el "problem error")))))) | ||
|
||
(defn handle-submit | ||
"Attaches an event handler to a form's \"submit\" browser event, validates | ||
submitted data, then: | ||
* If validation fails, shows the problems (or, if provided, calls a custom | ||
failure function with the problems data as the argument) | ||
* If validation succeeds, calls a success function with parsed params as | ||
the argument" | ||
[form-spec container-or-form-el success & [failure]] | ||
(let [form-el (get-form-el container-or-form-el) | ||
failure (or failure | ||
#(show-problems form-spec form-el %))] | ||
(d/listen! form-el :submit | ||
(fn [event] | ||
(.preventDefault event) | ||
(with-fallback failure | ||
(clear-problems form-el) | ||
(success | ||
(fp/parse-params form-spec (serialize form-el)))))))) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,14 @@ | ||
(ns formidable.macros) | ||
|
||
;; ClojureScript macros | ||
|
||
(defmacro with-fallback | ||
"Attempts to run body; if an ExceptionInfo with a :problems key is caught, | ||
calls fallback-fn with the problems as the argument." | ||
[fallback-fn & body] | ||
`(try | ||
~@body | ||
(catch js/Error e# | ||
(if-let [problems# (:problems (ex-data e#))] | ||
(~fallback-fn problems#) | ||
(throw e#))))) |
Oops, something went wrong.