2edbd420 by Michael Richards

Merge pull request #25 from wearefractal/master

Support for events + build script
2 parents 3a172296 b1a1aea0
// Generated by CoffeeScript 1.3.3
(function() {
var Rivets, attributeBinding, bidirectionals, getInputValue, rivets,
var Rivets, attributeBinding, bidirectionals, bindEvent, eventBinding, getInputValue, rivets, unbindEvent,
__bind = function(fn, me){ return function(){ return fn.apply(me, arguments); }; },
__indexOf = [].indexOf || function(item) { for (var i = 0, l = this.length; i < l; i++) { if (i in this && this[i] === item) return i; } return -1; };
......@@ -14,9 +14,10 @@
Rivets.Binding = (function() {
function Binding(el, type, model, keypath, formatters) {
function Binding(el, type, bindType, model, keypath, formatters) {
this.el = el;
this.type = type;
this.bindType = bindType;
this.model = model;
this.keypath = keypath;
this.formatters = formatters != null ? formatters : [];
......@@ -26,8 +27,12 @@
this.set = __bind(this.set, this);
if (this.bindType === "event") {
this.routine = eventBinding(this.type);
} else {
this.routine = Rivets.routines[this.type] || attributeBinding(this.type);
}
}
Binding.prototype.set = function(value) {
var formatter, _i, _len, _ref;
......@@ -36,21 +41,21 @@
formatter = _ref[_i];
value = Rivets.config.formatters[formatter](value);
}
if (this.bindType === "event") {
this.routine(this.el, value, this.currentListener);
return this.currentListener = value;
} else {
return this.routine(this.el, value);
}
};
Binding.prototype.bind = function() {
var _ref;
Rivets.config.adapter.subscribe(this.model, this.keypath, this.set);
if (Rivets.config.preloadData) {
this.set(Rivets.config.adapter.read(this.model, this.keypath));
}
if (_ref = this.type, __indexOf.call(bidirectionals, _ref) >= 0) {
if (window.addEventListener) {
return this.el.addEventListener('change', this.publish);
} else {
return this.el.attachEvent('change', this.publish);
}
if (this.bindType === "bidirectional") {
return bindEvent(this.el, 'change', this.publish);
}
};
......@@ -92,9 +97,10 @@
};
View.prototype.build = function() {
var attribute, bindingRegExp, keypath, model, node, path, pipe, pipes, type, _i, _len, _ref, _results;
var attribute, bindType, bindingRegExp, eventRegExp, keypath, model, node, path, pipe, pipes, type, _i, _len, _ref, _results;
this.bindings = [];
bindingRegExp = this.bindingRegExp();
eventRegExp = /^event-/;
_ref = this.el.getElementsByTagName('*');
_results = [];
for (_i = 0, _len = _ref.length; _i < _len; _i++) {
......@@ -106,6 +112,7 @@
for (_j = 0, _len1 = _ref1.length; _j < _len1; _j++) {
attribute = _ref1[_j];
if (bindingRegExp.test(attribute.name)) {
bindType = "attribute";
type = attribute.name.replace(bindingRegExp, '');
pipes = (function() {
var _k, _len2, _ref2, _results2;
......@@ -120,7 +127,13 @@
path = pipes.shift().split('.');
model = this.models[path.shift()];
keypath = path.join('.');
_results1.push(this.bindings.push(new Rivets.Binding(node, type, model, keypath, pipes)));
if (eventRegExp.test(type)) {
type = type.replace(eventRegExp, '');
bindType = "event";
} else if (__indexOf.call(bidirectionals, type) >= 0) {
bindType = "bidirectional";
}
_results1.push(this.bindings.push(new Rivets.Binding(node, type, bindType, model, keypath, pipes)));
} else {
_results1.push(void 0);
}
......@@ -146,6 +159,22 @@
})();
bindEvent = function(el, event, fn) {
if (window.addEventListener) {
return el.addEventListener(event, fn);
} else {
return el.attachEvent(event, fn);
}
};
unbindEvent = function(el, event, fn) {
if (window.removeEventListener) {
return el.removeEventListener(event, fn);
} else {
return el.detachEvent(event, fn);
}
};
getInputValue = function(el) {
switch (el.type) {
case 'text':
......@@ -159,6 +188,17 @@
}
};
eventBinding = function(event) {
return function(el, bind, unbind) {
if (bind) {
bindEvent(el, event, bind);
}
if (unbind) {
return unbindEvent(el, event, unbind);
}
};
};
attributeBinding = function(attr) {
return function(el, value) {
if (value) {
......
......@@ -11,5 +11,8 @@
"repository" : {
"type" : "git",
"url" : "https://github.com/mikeric/rivets.git"
},
"scripts" : {
"build" : "coffee -o lib -c src"
}
}
......
......@@ -14,7 +14,10 @@ class Rivets.Binding
# All information about the binding is passed into the constructor; the DOM
# element, the routine identifier, the model object and the keypath at which
# to listen for changes.
constructor: (@el, @type, @model, @keypath, @formatters = []) ->
constructor: (@el, @type, @bindType, @model, @keypath, @formatters = []) ->
if @bindType is "event"
@routine = eventBinding @type
else
@routine = Rivets.routines[@type] || attributeBinding @type
# Sets the value for the binding. This Basically just runs the binding routine
......@@ -23,6 +26,10 @@ class Rivets.Binding
for formatter in @formatters
value = Rivets.config.formatters[formatter] value
if @bindType is "event"
@routine @el, value, @currentListener
@currentListener = value
else
@routine @el, value
# Subscribes to the model for changes at the specified keypath. Bi-directional
......@@ -34,13 +41,8 @@ class Rivets.Binding
if Rivets.config.preloadData
@set Rivets.config.adapter.read @model, @keypath
if @type in bidirectionals
# Check to see if addEventListener is available.
if window.addEventListener
@el.addEventListener 'change', @publish
else
# Assume we are in IE and use attachEvent.
@el.attachEvent 'change', @publish
if @bindType is "bidirectional"
bindEvent @el, 'change', @publish
# Publishes the value currently set on the input element back to the model.
publish: (e) =>
......@@ -64,28 +66,57 @@ class Rivets.View
build: =>
@bindings = []
bindingRegExp = @bindingRegExp()
eventRegExp = /^event-/
for node in @el.getElementsByTagName '*'
for attribute in node.attributes
if bindingRegExp.test attribute.name
bindType = "attribute"
type = attribute.name.replace bindingRegExp, ''
pipes = (pipe.trim() for pipe in attribute.value.split '|')
path = pipes.shift().split '.'
model = @models[path.shift()]
keypath = path.join '.'
@bindings.push new Rivets.Binding node, type, model, keypath, pipes
if eventRegExp.test type
type = type.replace eventRegExp, ''
bindType = "event"
else if type in bidirectionals
bindType = "bidirectional"
@bindings.push new Rivets.Binding node, type, bindType, model, keypath, pipes
# Binds all of the current bindings for this view.
bind: =>
binding.bind() for binding in @bindings
# Cross-browser event binding
bindEvent = (el, event, fn) ->
# Check to see if addEventListener is available.
if window.addEventListener
el.addEventListener event, fn
else
# Assume we are in IE and use attachEvent.
el.attachEvent event, fn
unbindEvent = (el, event, fn) ->
# Check to see if addEventListener is available.
if window.removeEventListener
el.removeEventListener event, fn
else
# Assume we are in IE and use attachEvent.
el.detachEvent event, fn
# Returns the current input value for the specified element.
getInputValue = (el) ->
switch el.type
when 'text', 'textarea', 'password', 'select-one' then el.value
when 'checkbox', 'radio' then el.checked
# Returns an element binding routine for the specified attribute.
eventBinding = (event) -> (el, bind, unbind) ->
bindEvent el, event, bind if bind
unbindEvent el, event, unbind if unbind
# Returns an attribute binding routine for the specified attribute. This is what
# `registerBinding` falls back to when there is no routine for the binding type.
attributeBinding = (attr) -> (el, value) ->
......