Skip to content

Commit

Permalink
first commit
Browse files Browse the repository at this point in the history
  • Loading branch information
drcode committed Nov 14, 2012
0 parents commit aba4347
Show file tree
Hide file tree
Showing 57 changed files with 21,835 additions and 0 deletions.
11 changes: 11 additions & 0 deletions README
@@ -0,0 +1,11 @@
# webfui

Client Side Web Development Framework For ClojureScript

## Usage

Documentation is still pending (expect it by November 2012). At this time, your best guide is to run the code in the "webfui-examples" directory- Just run "lein deps;lein run" and fire up your Safari, Chrome, or iOS browser to "localhost:8080"

## License

Distributed under the Eclipse Public License 1.0 (http://opensource.org/licenses/eclipse-1.0.php), the same as Clojure.
66 changes: 66 additions & 0 deletions info.txt
@@ -0,0 +1,66 @@
*presentation notes

What is the DOM?

Problems with the DOM
- It changes
- Changing it is slow

What is EDN?

What is AJAX?

How to build a web framework:
- Should do things the Clojure Way
- Code should be in the functional style
- The browser DOM should be EDN data stored in an atom

DOM is not a complete representation of browser state
- Can't set button as pushed
- Can't set scrollbar position
- Can't set text selection

Problem: AJAX requires side effects. Reframed problem: Our state atom no longer contains the whole world

Original sin: Our state is _always_ corrupt in a program that uses AJAX.

We have to contain the corruption (Can be done with FP)
We have to repair the corruption (Requires imperative programming)

"State Corruption" Design Pattern

AJAX=Corruption of state

Corruption is implicit- Make it explicit

GET: State item has value of nil
or selection variable has id that points to nonexistent item

POST: Create new item in state with id=nil

PUT: Have "holding area" in state, set source of truth=nil. Move from holding area back to final area

DELETE: Just delete item

*todos
item insert/deletion in delta system
text selection
full IK artwork
"preview" in calculator

*Hello World
(ns my-app.core
(:use [webfui.framework :only [launch-app]]))

(defn render-all []
"hello world!")

(launch-app (atom nil) render-all)



*timing
~250 for mouseup
~150 for webfui code
~90 for parsing html
~90 for delta detection
Binary file added lib/clojure-1.3.0.jar
Binary file not shown.
40 changes: 40 additions & 0 deletions pom.xml
@@ -0,0 +1,40 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd" xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<modelVersion>4.0.0</modelVersion>
<groupId>webfui</groupId>
<artifactId>webfui</artifactId>
<version>0.2</version>
<name>webfui</name>
<description>Alpha release of Webfui- All Webfui source included in this repository release under Eclipse Public License 1.0 (http://opensource.org/licenses/eclipse-1.0.php)</description>
<url>http://lisperati.com</url>
<build>
<sourceDirectory>src</sourceDirectory>
<testSourceDirectory>test</testSourceDirectory>
<resources>
<resource>
<directory>resources</directory>
</resource>
</resources>
<testResources>
<testResource>
<directory>test-resources</directory>
</testResource>
</testResources>
</build>
<repositories>
<repository>
<id>central</id>
<url>http://repo1.maven.org/maven2</url>
</repository>
<repository>
<id>clojars</id>
<url>http://clojars.org/repo/</url>
</repository>
</repositories>
</project>

<!-- This file was autogenerated by Leiningen.
Please do not edit it directly; instead edit project.clj and regenerate it.
It should not be considered canonical data. For more information see
https://github.com/technomancy/leiningen -->
3 changes: 3 additions & 0 deletions project.clj
@@ -0,0 +1,3 @@
(defproject webfui "0.2"
:description "Alpha release of Webfui- All Webfui source included in this repository release under Eclipse Public License 1.0 (http://opensource.org/licenses/eclipse-1.0.php)"
:url "http://lisperati.com")
63 changes: 63 additions & 0 deletions src/webfui/core.cljs
@@ -0,0 +1,63 @@
(ns webfui.core
(:use [webfui.html :only [html parse-html parsed-html render-attribute-value html-delta]]
[webfui.plugin.core :only [active-plugins Plugin declare-events fix-dom]]
[cljs.reader :only [read-string]]))

;; This file contains the core engine for webfui. You usually don't want to load this file directly, instead load webfui.dom or webfui.framework.

(defn body []
(.-body js/document))

(defn select-path-dom [node path]
(if-let [[cur & more] (seq path)]
(recur (.item (.-childNodes node) cur) more)
node))

(defn dom-ready? []
(= (.-readyState js/document) "complete"))

(defn dom-ready [fun]
(set! (.-onload js/window) fun))

(defn parsed-html-watcher [key a old new]
(let [delta (html-delta (.-children old) (.-children new) [])]
(doseq [[typ path a b] delta]
(let [node (select-path-dom (body) path)]
(case typ
:att (if (= a :value)
(set! (.-value node) (str b))
(.setAttribute node (name a) (render-attribute-value a b)))
:rem-att (.removeAttribute node (name a))
:html (set! (.-innerHTML node) (apply str (map html a))))))
(doseq [plugin @active-plugins]
(fix-dom plugin))))

(def parsed-html-atom (atom (parsed-html. :body {} nil)))

(defn update-parsed-html-atom [new old]
(parsed-html. :body
{}
(if (or (seq? new) (list? new))
(parse-html new)
(parse-html (list new)))))

(defn html-watcher [key a old new]
(swap! parsed-html-atom (partial update-parsed-html-atom new)))

(def dom-watchers (atom {}))

(defn core-add-dom-watch [id fun]
(swap! dom-watchers assoc id fun))

(defn init-dom [html]
(let [b (body)]
(doseq [plugin @active-plugins]
(declare-events plugin (body) dom-watchers parsed-html-atom))
(add-watch html :dom-watcher html-watcher)
(add-watch parsed-html-atom :parsed-html-watcher parsed-html-watcher)
(swap! html identity)))

(defn core-defdom [clj-dom]
(if (dom-ready?)
(init-dom clj-dom)
(dom-ready (partial init-dom clj-dom))))
11 changes: 11 additions & 0 deletions src/webfui/dom.cljs
@@ -0,0 +1,11 @@
(ns webfui.dom
(:use [webfui.core :only [core-add-dom-watch core-defdom]]
[webfui.plugin.core :only [register-plugin]]
[webfui.plugin.form-values :only [form-values]]))

(def add-dom-watch core-add-dom-watch)

(def defdom core-defdom)

(register-plugin (form-values.))

23 changes: 23 additions & 0 deletions src/webfui/dom_manipulation.cljs
@@ -0,0 +1,23 @@
(ns webfui.dom-manipulation
(:use [webfui.html :only [unparse-html]]))

;; This file is for DOM manipulation functions used by both the core of webfui as well as plugins.

(defn path-dom [node]
(drop 3
(reverse ((fn f [node]
(lazy-seq (when node
(cons (dec (count (take-while identity (iterate #(.-previousSibling %) node)))) (f (.-parentNode node))))))
node))))

(defn select-path-html [html path]
(if-let [[cur & more] (seq path)]
(recur (nth (.-children html) cur) more)
html))

(defn resolve-target [parsed-html target]
(let [path (path-dom target)
parsed-element (select-path-html parsed-html path)]
(unparse-html parsed-element)))


51 changes: 51 additions & 0 deletions src/webfui/framework.cljs
@@ -0,0 +1,51 @@
(ns webfui.framework
(:use [webfui.dom :only [defdom add-dom-watch]]
[webfui.plugin.core :only [register-plugin]]
[webfui.plugin.mouse :only [mouse add-mouse-watch]]
[webfui.state-patches :only [patch]]
[webfui.utilities :only [get-attribute]]))

(register-plugin (mouse.))

(defn state-watcher [dom renderer key state old new]
(swap! dom (constantly (renderer new))))

(declare cur-state)

(defn launch-app [state renderer]
(let [dom (atom (renderer @state))]
(defdom dom)
(add-watch state :state-watcher (partial state-watcher dom renderer)))
(def cur-state state))

(defn add-dom-watch-helper [id fun]
(add-dom-watch id
(fn [_ element-new]
(swap! cur-state
(fn [state]
(let [diff (fun state element-new)]
(patch state diff)))))))

(def mouse-down-state (atom nil))

(defn add-mouse-watch-helper [id fun optimization]
(add-mouse-watch id
(fn [element-old element-new points]
(swap! mouse-down-state
(fn [old]
(or old @cur-state)))
(reset! cur-state
(if (= optimization :incremental)
(let [mds @mouse-down-state
diff (fun mds element-old element-new (subvec points (max 0 (- (count points) 2))))
new-state (patch mds diff)]
(reset! mouse-down-state
(when (get-attribute element-old :active)
new-state))
new-state)
(let [mds @mouse-down-state
diff (fun mds element-old element-new points)]
(when-not (get-attribute element-old :active)
(reset! mouse-down-state nil))
(patch mds diff)))))))

11 changes: 11 additions & 0 deletions src/webfui/framework/macros.clj
@@ -0,0 +1,11 @@
;*CLJSBUILD-MACRO-FILE*;

(ns webfui.framework.macros)

(defmacro add-dom-watch [id vars & more]
`(webfui.framework/add-dom-watch-helper ~id (fn ~vars ~@more)))

(defmacro add-mouse-watch [id vars & more]
(if (vector? id)
`(webfui.framework/add-mouse-watch-helper ~(first id) (fn ~vars ~@more) ~(second id))
`(webfui.framework/add-mouse-watch-helper ~id (fn ~vars ~@more) :full)))

0 comments on commit aba4347

Please sign in to comment.