Skip to content

Commit

Permalink
initial version
Browse files Browse the repository at this point in the history
  • Loading branch information
mjtodd committed Apr 18, 2012
0 parents commit 962f243
Show file tree
Hide file tree
Showing 5 changed files with 139 additions and 0 deletions.
9 changes: 9 additions & 0 deletions .gitignore
@@ -0,0 +1,9 @@
pom.xml
*jar
/lib/
/classes/
.lein-deps-sum
resources/public/cljs/
.lein-plugins
.lein-cljsbuild-compiler-0
resources
35 changes: 35 additions & 0 deletions README.md
@@ -0,0 +1,35 @@
# cljs-binding

A ClojureScript binding library

cljs-binding makes it easy to bind html elements to ClojureScript functions.

## Examples

### Simple binding

In your view, add an element `[:p {:bind "text: sample.content()"}]`

The paragraphs text will be set to the return value of the `sample.content` javascript/ClojureScript function.

If the ClojureScript sample.content function dereferences any atoms, then when the values of any of those atoms change, the text of the paragraph will be automatically updated.

Multiple bindings can be specified e.g. `[:p {:bind "text: sample.content(); css: sample.contentcss()"}]`

### Binding atoms to inputs

As well as binding UI elements to functions that are dependent on atoms, atoms can also be bound to the value (or more specifically .`val()`) of an input `[:input {:bindatom "sample.MyAtom"}]`. Whenever the input fires the `change` event, the atom will be reset to the new value of the input.

## Usage

Update your project.clj to have a dependency on `fluentsoftware/cljs-binding "1.0.0.SNAPSHOT"`.

The clojure function `cljsbinding.core/init` will generate the appropriate javascript to initialise the cljs-binding client code.

In your ClojureScript code, simply `:require [cljsbinding :as binding]` to ensure that cljsbinding client code is compiled in.


## License

Copyright © 2012 Fluent Software Solutions Ltd

13 changes: 13 additions & 0 deletions project.clj
@@ -0,0 +1,13 @@
(defproject fluentsoftware/cljs-binding "1.0.0-SNAPSHOT"
:description "ClojureScript binding library"
:dependencies [[org.clojure/clojure "1.3.0"]]
:dev-dependencies [[lein-cljsbuild "0.1.8"]]
:plugins [[lein-cljsbuild "0.1.8"]]
:hooks [leiningen.cljsbuild]
:cljsbuild {
:builds [{:source-path "src-cljs"
:jar true
:compiler {:output-to "resources/public/js/cljsbinding.js"
:optimizations :whitespace
:pretty-print true}}]}
)
67 changes: 67 additions & 0 deletions src-cljs/cljsbinding.cljs
@@ -0,0 +1,67 @@
(ns cljsbinding
(:use [jayq.core :only [$ attr val change]])
)

(def BindMonitor (atom false))
(def BindDependencies (atom {}))
(def BindFn (atom nil))

(defn translate [data]
(if (map? data) (make-js-map data) data)
)

(defn bind-elem [elem data]
(let [f #(.call (aget elem (first data)) elem (translate(js/eval (second data))))]
(reset! BindMonitor true)
(reset! BindFn f)
(f)
(reset! BindMonitor false)
))

(defn make-js-map
"makes a javascript map from a clojure one"
[cljmap]
(let [out (js-obj)]
(doall (map #(aset out (name (first %)) (second %)) cljmap))
out))

(defn bind [elem]
(doseq [data (.split (attr elem "bind") ";")] (bind-elem elem (.split data ":")))
)

(defn bindatom [elem]
(bind-elem elem ["val" (str "cljs.core.deref.call(null," (attr elem "bindatom") ")") ])
(.change elem #(
(reset! (js/eval (attr elem "bindatom")) (.val elem))
:false
))
)

(defn ^:export init []
(doseq [elem ($ "*[bind]")] (bind elem))
(doseq [elem ($ "*[bindatom]")] (bindatom elem))
)

(defn seq-contains?
"Determine whether a sequence contains a given item"
[sequence item]
(if (empty? sequence)
false
(reduce #(or %1 %2) (map #(= %1 item) sequence))))

(defn ^:export register [atom]
(reset! BindMonitor false)
(swap! BindDependencies
#(assoc % atom (if (contains? % atom)
(cons @BindFn (% atom))
[@BindFn]))
)
(add-watch atom :binding-watch
(fn [key a old-val new-val]
(doseq [f (@BindDependencies a)] (f))
)
)
(reset! BindMonitor true)
)


15 changes: 15 additions & 0 deletions src/cljsbinding/core.clj
@@ -0,0 +1,15 @@
(ns cljsbinding.core)

(defn bind []
[
:script "$(function() {
// Bit of a hack to hook into deref for dependency management
var deref = cljs.core.deref
cljs.core.deref = function (a) {
if (deref(cljsbinding.BindMonitor))
cljsbinding.register(a)
return deref(a)
}
cljsbinding.init()})
"]
)

0 comments on commit 962f243

Please sign in to comment.