d06e350d by Michael Richards

Namespace everything under Rivets and rewrite the registerBinding function as a new class.

1 parent 77351bb8
// Generated by CoffeeScript 1.3.1
(function() {
var attributeBinding, bidirectionals, bindings, getInputValue, registerBinding, rivets, stateBinding,
var Rivets,
__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; };
registerBinding = function(el, adapter, type, context, keypath) {
var bind;
bind = bindings[type] || attributeBinding(type);
bind(el, adapter.read(context, keypath));
adapter.subscribe(context, keypath, function(value) {
return bind(el, value);
});
if (__indexOf.call(bidirectionals, type) >= 0) {
return el.addEventListener('change', function() {
return adapter.publish(context, keypath, getInputValue(this));
});
}
Rivets = {
Helpers: {}
};
getInputValue = function(el) {
Rivets.Binding = (function() {
Binding.name = 'Binding';
function Binding(el, adapter, type, context, keypath) {
this.el = el;
this.adapter = adapter;
this.type = type;
this.context = context;
this.keypath = keypath;
this.bind = __bind(this.bind, this);
this.set = __bind(this.set, this);
this.routine = Rivets.bindings[this.type] || Rivets.Helpers.attributeBinding(this.type);
}
Binding.prototype.set = function(value) {
if (value == null) {
value = null;
}
return this.routine(this.el, value || this.adapter.read(this.context, this.keypath));
};
Binding.prototype.bind = function() {
var _ref,
_this = this;
this.adapter.subscribe(this.context, this.keypath, function(value) {
return _this.set(value);
});
if (_ref = this.type, __indexOf.call(Rivets.bidirectionals, _ref) >= 0) {
return this.el.addEventListener('change', function(el) {
return _this.adapter.publish(_this.context, _this.keypath, Rivets.Helpers.getInputValue(el));
});
}
};
return Binding;
})();
Rivets.Helpers.getInputValue = function(el) {
switch (el.type) {
case 'text':
case 'textarea':
......@@ -30,7 +62,7 @@
}
};
attributeBinding = function(attr) {
Rivets.Helpers.attributeBinding = function(attr) {
return function(el, value) {
if (value) {
return el.setAttribute(attr, value);
......@@ -40,22 +72,24 @@
};
};
stateBinding = function(attr, inverse) {
Rivets.Helpers.stateBinding = function(attr, inverse) {
if (inverse == null) {
inverse = false;
}
return function(el, value) {
return attributeBinding(attr)(el, inverse === !value ? attr : false);
var binding;
binding = Rivets.Helpers.attributeBinding(attr);
return binding(el, inverse === !value ? attr : false);
};
};
bindings = {
checked: stateBinding('checked'),
selected: stateBinding('selected'),
disabled: stateBinding('disabled'),
unchecked: stateBinding('checked', true),
unselected: stateBinding('selected', true),
enabled: stateBinding('disabled', true),
Rivets.bindings = {
checked: Rivets.Helpers.stateBinding('checked'),
selected: Rivets.Helpers.stateBinding('selected'),
disabled: Rivets.Helpers.stateBinding('disabled'),
unchecked: Rivets.Helpers.stateBinding('checked', true),
unselected: Rivets.Helpers.stateBinding('selected', true),
enabled: Rivets.Helpers.stateBinding('disabled', true),
text: function(el, value) {
return el.innerText = value || '';
},
......@@ -73,14 +107,14 @@
}
};
bidirectionals = ['value', 'checked', 'unchecked', 'selected', 'unselected'];
Rivets.bidirectionals = ['value', 'checked', 'unchecked', 'selected', 'unselected'];
rivets = {
Rivets["interface"] = {
register: function(routine, routineFunction) {
return bindings[routine] = routineFunction;
return Rivets.bindings[routine] = routineFunction;
},
bind: function(el, adapter, contexts) {
var attribute, context, keypath, node, path, type, _i, _len, _ref, _results;
var attribute, binding, context, keypath, node, path, type, _i, _len, _ref, _results;
if (contexts == null) {
contexts = {};
}
......@@ -99,7 +133,8 @@
path = attribute.value.split('.');
context = path.shift();
keypath = path.join('.');
_results1.push(registerBinding(node, adapter, type, contexts[context], keypath));
binding = new Rivets.Binding(node, adapter, type, contexts[context], keypath);
_results1.push(binding.bind());
} else {
_results1.push(void 0);
}
......@@ -112,9 +147,9 @@
};
if (typeof module !== "undefined" && module !== null) {
module.exports = rivets;
module.exports = Rivets["interface"];
} else {
this.rivets = rivets;
this.rivets = Rivets["interface"];
}
}).call(this);
......
......@@ -3,53 +3,60 @@
# author : Michael Richards
# license : MIT
# Registers a specific binding routine between a model object and a DOM element.
# All information for that routine is passed in when calling this function; the
# specific element to bind to, an adapter interface for the model object, the
# type of binding, the context object and the keypath at which to subscribe to
# on the model object.
registerBinding = (el, adapter, type, context, keypath) ->
bind = bindings[type] || attributeBinding type
bind el, adapter.read context, keypath
Rivets =
Helpers: {}
adapter.subscribe context, keypath, (value) ->
bind el, value
class Rivets.Binding
constructor: (@el, @adapter, @type, @context, @keypath) ->
@routine = Rivets.bindings[@type] || Rivets.Helpers.attributeBinding @type
if type in bidirectionals
el.addEventListener 'change', ->
adapter.publish context, keypath, getInputValue this
# Sets a value for this binding. Basically just runs the routine on the
# element with a suplied value.
set: (value = null) =>
@routine @el, value || @adapter.read @context, @keypath
# Subscribes to the context object for changes on the specific keypath.
# Conditionally also does the inverse and listens to the element for changes
# to propogate back to the context object.
bind: =>
@adapter.subscribe @context, @keypath, (value) => @set value
if @type in Rivets.bidirectionals
@el.addEventListener 'change', (el) =>
@adapter.publish @context, @keypath, Rivets.Helpers.getInputValue el
# Returns the current input value for the specified element.
getInputValue = (el) ->
Rivets.Helpers.getInputValue = (el) ->
switch el.type
when 'text', 'textarea', 'password', 'select-one' then el.value
when 'checkbox', 'radio' then el.checked
# 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) ->
Rivets.Helpers.attributeBinding = (attr) -> (el, value) ->
if value then el.setAttribute attr, value else el.removeAttribute attr
# Returns a state binding routine for the specified attribute. Can optionally be
# negatively evaluated. This is used to build a lot of the core state binding
# routines.
stateBinding = (attr, inverse = false) -> (el, value) ->
attributeBinding(attr) el, if inverse is !value then attr else false
Rivets.Helpers.stateBinding = (attr, inverse = false) -> (el, value) ->
binding = Rivets.Helpers.attributeBinding(attr)
binding el, if inverse is !value then attr else false
# Core binding routines.
bindings =
Rivets.bindings =
checked:
stateBinding 'checked'
Rivets.Helpers.stateBinding 'checked'
selected:
stateBinding 'selected'
Rivets.Helpers.stateBinding 'selected'
disabled:
stateBinding 'disabled'
Rivets.Helpers.stateBinding 'disabled'
unchecked:
stateBinding 'checked', true
Rivets.Helpers.stateBinding 'checked', true
unselected:
stateBinding 'selected', true
Rivets.Helpers.stateBinding 'selected', true
enabled:
stateBinding 'disabled', true
Rivets.Helpers.stateBinding 'disabled', true
text: (el, value) ->
el.innerText = value or ''
html: (el, value) ->
......@@ -63,13 +70,13 @@ bindings =
# Bindings that should also be observed for changes on the DOM element in order
# to propogate those changes back to the model object.
bidirectionals = ['value', 'checked', 'unchecked', 'selected', 'unselected']
Rivets.bidirectionals = ['value', 'checked', 'unchecked', 'selected', 'unselected']
# The rivets module exposes `register` and `bind` functions to register new
# binding routines and bind contexts to DOM elements.
rivets =
Rivets.interface =
register: (routine, routineFunction) ->
bindings[routine] = routineFunction
Rivets.bindings[routine] = routineFunction
bind: (el, adapter, contexts = {}) ->
for node in el.getElementsByTagName '*'
......@@ -79,10 +86,12 @@ rivets =
path = attribute.value.split '.'
context = path.shift()
keypath = path.join '.'
registerBinding node, adapter, type, contexts[context], keypath
binding = new Rivets.Binding node, adapter, type, contexts[context], keypath
binding.bind()
# Exports rivets for both CommonJS and the browser.
if module?
module.exports = rivets
module.exports = Rivets.interface
else
@rivets = rivets
\ No newline at end of file
@rivets = Rivets.interface
\ No newline at end of file
......