Skip to content

thickey/enfocus

 
 

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

79 Commits
 
 
 
 
 
 
 
 

Repository files navigation

Enfocus

Enfocus is a DOM manipulation and templating library for ClojureScript. Inspired by Christophe Grand’s Enlive, Enfocus’ primary purpose is providing a base for building rich interfaces in ClojureScript.

You can find examples and documention for enfocus here

If you are unfamiliar with enlive I also recommend taking a look at these links.

David Nolen wrote a nice tutorial
Another tutorial by Brian Marick.

Where do I get support?

On the group

Quick Start

Setup

From any leiningen project file:

[enfocus “0.8.0-SNAPSHOT”]

Then make sure you have your lib folder on your classpath.

For the best development experience, try out cljs-watch. If you do, you’ll need to replace the goog.jar in your CLOJURESCRIPT_HOME/lib with the goog-jar.jar that comes down as a dependency with enfocus.

The Basics

Every great journey starts with “Hello world!”

(ns my.namespace
(:require [enfocus.core :as ef])
(:require-macros [enfocus.macros :as em]))

(defn start []
(em/at js/document
[“body”] (em/content “Hello world!”))

(set! (.onload js/window) start)

The at form

At the core to understanding Enfocus is the at form used in the
“Hello world!” example above. It comes in two basic flavors listed below:

(at a-node (transform arg1 …))

and

(at a-node
[selector1] (transform1 arg1 …)
[selector2] (transform2 arg1 …))

In the first case at is passed a node or node set and a transform. This form of at
calls the transform on each element in the node set.

A transform is nothing more than a function that takes a set of arguments and returns a function
that takes a set of nodes. In case of the “Hello World!” example above, we see the use of
(em/content “Hello world!”) this call returns a function that takes node or node set
and replaces the content with “Hello world!”

In the second case, we see at is passed a node or node set and a set of
selector/transform pairs. The selectors are scoped by the node or node set passed in and
the results of each selector is passed on to its partner transformation.

A selector is a string representing a CSS3 compliant selector

Handling Events

Enfocus has event handling. Below is a simple example to add an onclick event handler to a button.

(em/defaction change [msg] 
[“#button1”] (em/content msg))

(em/defaction setup []
[“#button1”] (em/listen :click #(change “I have been clicked”)))

(set! (.onload js/window) setup)

The defaction construct is use here instead defn. defaction
creates a function that calls the at form like discussed above
and passes in js/document as the node to be transformed.

Effects

Enfocus has the concept of effects. Effects are nothing more than transformations
over a period of time. Below is a simple example of a resize effect. Notice how the
effects can be chained.

(em/defaction resize-div [width] 
  ["#rz-demo"] (em/chain 
                 (em/resize width :curheight 500 20)
                 (em/resize 5 :curheight 500 20)))

(em/defaction setup []
  ["#button2"] (em/listen #(resize-div 200)))
	
(set! (.onload js/window) setup)         

Actions, templates and snippets

A snippet is a function that returns a seq of nodes, it can be used as a
building block for more complex templates or actions.

You define a snippet by providing a remote resource, a selector and series of transformations.
The snippet definition below selects a table body from the remote resource
templates/template1.html and grabs the first row. It then fills the content of the row.

  (em/defsnippet snippet2 "templates/template1.html" ["tbody > *:first-child"] 
               [fruit quantity] 
               ["tr > *:first-child"] (em/content fruit)
               ["tr > *:last-child"] (em/content (str quantity)))

A template is very similar to a snippet except it does not require a selector to
grap a sub section, instead the entire remote resource is used as the dom.
If the remote resource is a full html document only what is inside the body tag is
brought into the template.

  (em/deftemplate template2 "/templates/template1.html" [fruit-data] 
                ["#heading1"] (em/content "fruit")  
                ["thead tr > *:last-child"] (em/content "quantity")
                ["tbody"] (em/content
                           (map #(snippit2 % (fruit-data %)) (keys fruit-data))))

An action is a set of transforms that take place on the live dom. below is a
definition of a an action.

(em/defaction action2 [] 
             [".cool[foo=false]"] (em/content (template2 {"banana" 5 "pineapple" 10}))
             ["#heading1"] (em/set-attr :id "new-heading1"))

Transformations

A transformation is a function that returns either a node or collection of node.

Enfocus defines several helper functions:

Supported Enlive Transformations


content (content “xyz” a-node “abc”)
html-content (html-content “please no”)
set-attr (set-attr :attr1 “val1” :attr2 “val2”)
remove-attr (remove-attr :attr1 :attr2)
add-class (add-class “foo” “bar”)
remove-class (remove-class “foo” “bar”)
do→ (do→ transformation1 transformation2)
append (append “xyz” a-node “abc”)
prepend (prepend “xyz” a-node “abc”)
after (after “xyz” a-node “abc”)
before (before “xyz” a-node “abc”)
substitute (substitute “xyz” a-node “abc”)
clone-for (clone-for [item items] transformation)
or (clone-for [item items]
selector1 transformation1
selector2 transformation2)
wrap (wrap :div) or (wrap :div {:class "foo"})
unwrap (unwrap)

New Transformations


set-style (set-style :font-size “10px” :background “#fff”)
remove-style (remove-style :font-size :background)
listen (listen :mouseover (fn [event] …))
remove-listener (remove-listener :mouseover :mouseout)
fade-in (fade-in time step-size)
or (fade-in time step-size callback)
fade-out (fade-out time step-size)
or (fade-out time step-size callback)
resize (resize width height ttime step-size)
or (resize width height ttime step-size callback)
move (move x y ttime step-size)
or (move x y ttime step size callback)
chain (chain (fade-in ttime step-size) ;serialize async effects
(move x y ttime step-size)
(fade-out ttime step-size)
…)

Currently there is one transformation that is supported by Enlive but not Enfocus. (Patches very welcome!!)


move (move [:.footnote] [:#footnotes] content)
;this will be called relocate in enfocus

Contributing

  • Download lieningen
  • Download & Install cljs-watch
  • Make sure that you have your CLOJURESCRIPT_HOME path setup correctly
  • Also ensure that your ClojureScript lib has the goog-jar.jar that comes down as an enfocus dependency

Compile ClojureScript

git clone git://github.com/ckirkendall/enfocus.git
cd enfocus/project
cljs-watch cljs-src '{:output-dir "../sample/resources/public/cljs" :output-to "../sample/resources/public/cljs/enfocus.js"}'

Viewing the Test Page

cd enfocus/sample
lein deps
lein repl
=>(use 'ring.adapter.jetty)
=>(use 'enfocus.ring)
=>(run-jetty app {:port 3000})

Open your browser to:
http://localhost:3000/test.html

Special Thanks!

Christophe Grand for creating enlive and building a simple api for dom manipulation.

About

DOM manipulation and templating library for ClojureScript inspired by Enlive.

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published