Skip to content

Commit

Permalink
reorganize files + v1.2.0
Browse files Browse the repository at this point in the history
  • Loading branch information
rafd committed Dec 19, 2014
1 parent 3357370 commit 47b96a8
Show file tree
Hide file tree
Showing 11 changed files with 221 additions and 208 deletions.
2 changes: 1 addition & 1 deletion project.clj
@@ -1,4 +1,4 @@
(defproject org.clojars.leanpixel/om-fields "1.1.5"
(defproject org.clojars.leanpixel/om-fields "1.2.0"
:description "FIXME: write description"
:url "http://example.com/FIXME"
:license {:name "Eclipse Public License"
Expand Down
195 changes: 9 additions & 186 deletions src/om_fields/core.cljs
@@ -1,190 +1,13 @@
(ns om-fields.core
(:require [om.core :as om :include-macros]
[om.dom :as dom :include-macros]
[om-fields.text :refer [human-friendly-editable]]
[om-fields.thing :refer [thing]]
[om-fields.multiselect :refer [multiselect]]
[clojure.string :refer [blank?]]

[cljs-time.format :refer [formatter formatters unparse]]
[cljs-time.core :refer [date-time]]))

(defmulti ^:export input (fn [data owner opts] (opts :type)))
(:require [om-fields.interface :refer [field]]
[om-fields.fields.text]
[om-fields.fields.thing]
[om-fields.fields.file]
[om-fields.fields.date]
[om-fields.fields.multiselect]
[om-fields.fields.checkbox]))

(def ^:export input-available
(keys (methods input)))

(defn str-or-nil [s]
(if (blank? s) nil s))

(defmethod input :read-only [_]
(fn [data owner opts]
(reify
om/IRender
(render [_]
(dom/div #js {:className "readonly"}
(get-in data (opts :edit-key)))))))

(defmethod input :text [data owner opts]
(human-friendly-editable data owner (assoc opts
:value-to-string identity
:string-to-value str-or-nil)))

(defmethod input :password [data owner opts]
(human-friendly-editable data owner (assoc opts
:type "password"
:value-to-string identity
:string-to-value str-or-nil)))

(defmethod input :url [data owner opts]
(human-friendly-editable data owner (assoc opts
:string-to-value str-or-nil
:value-validate (fn [value]
(if value
(re-matches #"(?i)^(https?|ftp)://[^\s/$.?#].[^\s]*$" value)
true)))))

(defmethod input :long-text [data owner opts]
(human-friendly-editable data owner (assoc opts
:value-to-string identity
:string-to-value str-or-nil
:multi-line true)))

(defmethod input :integer [data owner opts]
(human-friendly-editable data owner (assoc opts
:value-to-string str
:value-validate integer?
:string-to-value (fn [v]
(js/parseInt (str-or-nil v) 10)))))

(defmethod input :keyword [data owner opts]
(human-friendly-editable data owner (assoc opts
:value-to-string (fn [value]
(when value
(name value)))
:value-validate (complement nil?)
:string-to-value (fn [string]
(-> string
str-or-nil
keyword)))))

(defmethod input :date [data owner opts]
(let [date-format (if (opts :date-format)
(formatter (opts :date-format))
(formatters :mysql))]
(human-friendly-editable data owner (assoc opts
:value-to-string (fn [value]
(when value
(unparse date-format (date-time value))))
:value-validate (fn [value]
(not (js/isNaN (.getTime value))))
:string-to-value (fn [string]
(when-let [s (str-or-nil string)]
(js/Date.create s)))))))

(defmethod input :email [data owner opts]
(human-friendly-editable data owner (assoc opts
:value-validate (fn [value]
(if value
(re-matches #"(?i)[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,4}" value)
true)))))



(defmethod input :file [cursor owner {:keys [update-fn edit-key upload] :as opts}]
(let [update-fn (or update-fn #(om/update! cursor edit-key %))]
(reify
om/IRender
(render [_]
(let [handle-files (fn [file-list]
(when (< 0 (.-length file-list))
(upload (aget file-list 0) (fn [url] (update-fn url)))))
url (get-in cursor edit-key)]
(dom/div #js {:className "file"}
; direct url input
(dom/div #js {:className "input-wrapper"}
(om/build input cursor {:opts (assoc opts :type :url)}))
; hidden file input
(dom/input #js {:type "file"
:ref "file-input"
:style #js {:display "none"}
:onChange (fn [e]
(handle-files (.. e -target -files)))})
; styled input button
(dom/div #js {:className "action"
:onClick (fn [e]
(.click (om/get-node owner "file-input")))} " Upload a File")))))))

(defmethod input :image [cursor owner {:keys [update-fn edit-key upload] :as opts}]
(let [update-fn (or update-fn #(om/update! cursor edit-key %))]
(reify
om/IInitState
(init-state [_]
{:data-url nil})

om/IRenderState
(render-state [_ state]
(let [handle-files (fn [file-list]
(when (< 0 (.-length file-list))
(let [reader (js/FileReader. )]
(aset reader "onload" (fn [e]
(om/set-state! owner :data-url (.. e -target -result))))
(upload (aget file-list 0)
(fn [url]
(update-fn url)))
(.. reader (readAsDataURL (aget file-list 0))))))
url (get-in cursor edit-key)]
(dom/div #js {:className "image"}
; direct url input
(dom/div #js {:className "input-wrapper"}
(om/build input cursor {:opts (assoc opts :type :url)}))
; hidden file input
(dom/input #js {:type "file"
:ref "file-input"
:style #js {:display "none"}
:onChange (fn [e]
(handle-files (.. e -target -files)))})
; styled input button
(dom/div #js {:className "action"
:style #js {:cursor "pointer"}
:onClick (fn [e]
(.click (om/get-node owner "file-input")))} " Upload an Image")

; drop area + image + button
(dom/div #js {:className "embed"
:title "Upload an Image"
:style #js {:cursor "pointer"}
:onClick (fn [e]
(.click (om/get-node owner "file-input")))
:onDragEnter (fn [e] false)
:onDragOver (fn [e] false)
:onDrop (fn [e]
(.preventDefault e)
(when-let [web-content (.. e -dataTransfer (getData "text/html"))]
(when-let [img-url (get (re-find #"src=\"([^\"]*)\" " web-content) 1)]
(om/set-state! owner :data-url img-url)))
(handle-files (.. e -dataTransfer -files))
)}
(if-let [src (or (state :data-url) url)]
(dom/img #js {:src src})
(dom/span #js {:className "button"} "+")))))))))

(defmethod input :thing [data owner opts]
(thing data owner opts))

(defmethod input :multiselect [data owner opts]
(multiselect data owner opts))

(defmethod input :checkbox [cursor owner {:keys [update-fn edit-key label] :as opts}]
(let [update-fn (or update-fn #(om/update! cursor edit-key %))]
(reify
om/IRender
(render [_]
(dom/label #js {:style #js {:cursor "pointer"}}
(dom/input #js {:type "checkbox"
:style #js {:cursor "pointer"}
:onClick (fn [e]
(update-fn (.. e -target -checked)))
:checked (get-in cursor edit-key) })
label)))))
(keys (methods field)))

(def ^:export input field)
17 changes: 8 additions & 9 deletions src/om_fields/text.cljs → src/om_fields/editable.cljs
@@ -1,16 +1,16 @@
(ns om-fields.text
(:require-macros [cljs.core.async.macros :refer [go]])
(:require [om.core :as om :include-macros]
[om.dom :as dom :include-macros]
[cljs.core.async :refer [put! chan <! alts!]]
[clojure.string :as string]
[om-fields.util :refer [debounce]]))
(ns om-fields.editable
(:require-macros [cljs.core.async.macros :refer [go]])
(:require [om.core :as om :include-macros]
[om.dom :as dom :include-macros]
[om-fields.util :refer [debounce]]
[cljs.core.async :refer [chan put! <!]]
[clojure.string :as string]))

(defn- auto-resize [el]
(set! (.. el -style -height) "auto")
(set! (.. el -style -height) (str (.-scrollHeight el) "px")))

(defn- human-friendly-editable
(defn editable
"editable text field that shows and allows editing of a value that is actually different in reality
useful when state value is not a string
ex. dates: 'Monday' vs Date('2014-10-24 9:00:00')"
Expand Down Expand Up @@ -68,4 +68,3 @@
(om/set-state! owner :state "editing")
(put! (state :change-chan) (.-value el))
(om/set-state! owner :display-value (.-value el))))})))))

18 changes: 18 additions & 0 deletions src/om_fields/fields/checkbox.cljs
@@ -0,0 +1,18 @@
(ns om-fields.fields.checkbox
(:require [om.core :as om :include-macros]
[om.dom :as dom :include-macros]
[om-fields.interface :refer [field]]))

(defmethod field :checkbox [cursor owner {:keys [update-fn edit-key label] :as opts}]
(let [update-fn (or update-fn #(om/update! cursor edit-key %))]
(reify
om/IRender
(render [_]
(dom/label #js {:style #js {:cursor "pointer"}}
(dom/input #js {:type "checkbox"
:style #js {:cursor "pointer"}
:onClick (fn [e]
(update-fn (.. e -target -checked)))
:checked (get-in cursor edit-key) })
label)))))

23 changes: 23 additions & 0 deletions src/om_fields/fields/date.cljs
@@ -0,0 +1,23 @@
(ns om-fields.fields.date
(:require [om-fields.interface :refer [field]]
[om-fields.editable :refer [editable]]
[om-fields.util :refer [str-or-nil]]
[cljs-time.format :refer [formatter formatters unparse]]
[cljs-time.core :refer [date-time]]))

(defmethod field :date [data owner opts]
(let [date-format (if (opts :date-format)
(formatter (opts :date-format))
(formatters :mysql))]
(editable data owner (assoc opts
:value-to-string (fn [value]
(when value
(unparse date-format (date-time value))))
:value-validate (fn [value]
(not (js/isNaN (.getTime value))))
:string-to-value (fn [string]
(when-let [s (str-or-nil string)]
(js/Date.create s)))))))



82 changes: 82 additions & 0 deletions src/om_fields/fields/file.cljs
@@ -0,0 +1,82 @@
(ns om-fields.fields.file
(:require [om.core :as om :include-macros]
[om.dom :as dom :include-macros]
[om-fields.interface :refer [field]]))

(defmethod field :file [cursor owner {:keys [update-fn edit-key upload] :as opts}]
(let [update-fn (or update-fn #(om/update! cursor edit-key %))]
(reify
om/IRender
(render [_]
(let [handle-files (fn [file-list]
(when (< 0 (.-length file-list))
(upload (aget file-list 0) (fn [url] (update-fn url)))))
url (get-in cursor edit-key)]
(dom/div #js {:className "file"}
; direct url input
(dom/div #js {:className "input-wrapper"}
(om/build field cursor {:opts (assoc opts :type :url)}))
; hidden file input
(dom/input #js {:type "file"
:ref "file-input"
:style #js {:display "none"}
:onChange (fn [e]
(handle-files (.. e -target -files)))})
; styled input button
(dom/div #js {:className "action"
:onClick (fn [e]
(.click (om/get-node owner "file-input")))} " Upload a File")))))))

(defmethod field :image [cursor owner {:keys [update-fn edit-key upload] :as opts}]
(let [update-fn (or update-fn #(om/update! cursor edit-key %))]
(reify
om/IInitState
(init-state [_]
{:data-url nil})

om/IRenderState
(render-state [_ state]
(let [handle-files (fn [file-list]
(when (< 0 (.-length file-list))
(let [reader (js/FileReader. )]
(aset reader "onload" (fn [e]
(om/set-state! owner :data-url (.. e -target -result))))
(upload (aget file-list 0)
(fn [url]
(update-fn url)))
(.. reader (readAsDataURL (aget file-list 0))))))
url (get-in cursor edit-key)]
(dom/div #js {:className "image"}
; direct url input
(dom/div #js {:className "input-wrapper"}
(om/build field cursor {:opts (assoc opts :type :url)}))
; hidden file input
(dom/input #js {:type "file"
:ref "file-input"
:style #js {:display "none"}
:onChange (fn [e]
(handle-files (.. e -target -files)))})
; styled input button
(dom/div #js {:className "action"
:style #js {:cursor "pointer"}
:onClick (fn [e]
(.click (om/get-node owner "file-input")))} " Upload an Image")

; drop area + image + button
(dom/div #js {:className "embed"
:title "Upload an Image"
:style #js {:cursor "pointer"}
:onClick (fn [e]
(.click (om/get-node owner "file-input")))
:onDragEnter (fn [e] false)
:onDragOver (fn [e] false)
:onDrop (fn [e]
(.preventDefault e)
(when-let [web-content (.. e -dataTransfer (getData "text/html"))]
(when-let [img-url (get (re-find #"src=\"([^\"]*)\" " web-content) 1)]
(om/set-state! owner :data-url img-url)))
(handle-files (.. e -dataTransfer -files))
)}
(if-let [src (or (state :data-url) url)]
(dom/img #js {:src src})
(dom/span #js {:className "button"} "+")))))))))
@@ -1,9 +1,10 @@
(ns om-fields.multiselect
(ns om-fields.fields.multiselect
(:require-macros [cljs.core.async.macros :refer [go]])
(:require [om.core :as om :include-macros true]
[om.dom :as dom :include-macros true]
[om-fields.editable :refer [editable]]
[om-fields.interface :refer [field]]
[clojure.set :refer [union]]
[om-fields.text :refer [human-friendly-editable]]
[cljs.core.async :refer [put! chan <! sub pub]]
[om-fields.util :refer [debounce]]
[clojure.string :as string]))
Expand All @@ -12,7 +13,7 @@
(set! (.. el -style -width) "auto")
(set! (.. el -style -width) (str (.-scrollWidth el) "px")))

(defn multiselect [cursor owner {:keys [placeholder update-fn edit-key options] :as opts}]
(defmethod field :multiselect [cursor owner {:keys [placeholder update-fn edit-key options] :as opts}]
(let [options (or options #{})
edit-key (or edit-key [])
update-fn (or update-fn #(om/update! cursor edit-key %))]
Expand Down

0 comments on commit 47b96a8

Please sign in to comment.