Quick Start

Starting a new Project

The quickest way to get up and running is to use the enfocus-template. This is a Leiningen template that creates a sample app for using enfocus and ring.

Creating your application:

lein new enfocus-template my-app

Launching your applications:

cd my-app
lein cljsbuild once
lein ring server

This should launch the app into a browser.

Adding Enfocus to an Existing Project

From any leiningen project file:
[enfocus "2.0.0-SNAPSHOT"]

For the best development experience, use lein-cljsbuild.

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 [] 
  (ef/at "body" (ef/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:

Single Transform

(at a-node (transform arg1 ...))

;or implied js/document as main node

(at "selector" (transfrom arg1 ...))

Multiple Transforms

(at a-node
    "selector1" (transform1 arg1 ...)
    "selector2" (transform2 arg1 ...))

;or implied js/document as main node

(at "selector1" (transform1 arg1 ...)
    "selector2" (transform2 arg1 ...))

In the first case, at is passed a node/node set or a selector, and a transform and calls the transform on each element in the node set. If a selector is passed the root node is defaulted to js/document.

A transform is nothing more than a function that takes a set of arguments and returns a function that takes a node. In case of the "Hello World!" example above, we see the use of (ef/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 optionally passed a node or node set followed by selector/transform pairs. The selectors are scoped by the node or node set, if provided or js/document otherwise, 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

Lets look at handling events. When we click the button it will change to say "I have been clicked."

HTML:

<html>
  <body>
    <button id="button1">click me</button>
  </body>
</html>
CLJS:
(em/defaction change [msg] 
  "#button1" (ef/content msg))

(em/defaction setup []
  "#button1" (ef/listen :click #(change "I have been clicked")))
	
(set! (.-onload js/window) setup)         

The defaction construct is use here instead of 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.

HTML:

<html>
  <body>
    <div id="rz-demo" style="width: 5px; height: 10px; background-color: #33ff33;"> </div>
    <button id="button2">click me</button>
  </body>
</html>

CLJS:

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

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

A bit more complicated example with clone-for

Example:

fruitquantity
replaceme

The following action is triggered when we click the button.

(defn clone-for-demo []
  (let [fruit-data {"apple" 5, "pear" 6}]
    (ef/at "#clone-for-demo tbody > tr:first-child" 
      (ef/clone-for [fr (vec fruit-data)]
        "*:first-child" (ef/content (first fr))
        "*:last-child" (ef/content (str (second fr)))))))

Getting Data from the DOM

Below is an example of using the from form with the read-form extractor.



one
two
three

Example:

The following action is triggered when we click the button.

(defn get-prop-demo []
  (let [values (ef/from "#read-form-test" (ef/read-form))]
    (ef/at "#read-form-demo" (ef/content (pr-str values)))))