Bindings with ProAct.js+Zepto/jQuery

Simple binding system with implemented using ProAct.js. Example with the reactive sum.

HTML

<script src="http://cdn.jsdelivr.net/proact.js/1.2.1/proact.min.js"></script>
<div class="sum">
    <p>The result of <span pro-bind="x"></span> + <span pro-bind="y"></span> is <span pro-bind="z"></span>
    </p>
        <p>The result of <span pro-bind="y"></span> + <span pro-bind="x"></span> is <span pro-bind="z"></span>
    </p>
</div>
<div class="sum-one-prop">
    <p pro-bind="txt"></p>
</div>
<div class="inputs sum">
    <div>
        <label for="x">X:</label>
        <input name="x" type="text" onkeyup="App.x.trigger(event)" pro-bind="x" />
    </div>
    <div>
        <label for="y">Y:</label>
        <input name="y" type="text" onkeyup="App.y.trigger(event)" pro-bind="y" />
    </div>
</div>

CSS

.inputs {
    position: absolute;
    right: 100px;
    top: 10px;
}
.inputs div {
    margin: 10px;
}
.inputs div input {
    width: 30px;
}

JavaScript

(function (window, ProAct, $) {
    'use strict';

    function onProp($binding, obj, property, safe) {
        if (!obj.p(property)) {
            return;
        }
        
        var tag = $binding.prop('tagName').toLowerCase();

        obj.p(property).on(function () {
            if (tag === 'input') {
                $binding.prop('value', obj[property]);
                return;
            }
            if (safe) {
                $binding.html(obj[property]);
            } else {
                $binding.text(obj[property]);
            }
        });

        // sync
        obj.p(property).update();
    }

    function setupBinding($binding, obj) {
        var property = $binding.attr('pro-bind'),
            safe = false;

        if (property.substring(0, 4) === 'safe') {
            property = property.substring(5);
            safe = true;
        }

        if (!obj.p(property)) {
            return;
        }

        onProp($binding, obj, property, safe);
    }

    function create($el, obj) {
        var $bindings = $el.find('[pro-bind]')
            .add($el.filter('[pro-bind]'));

        $bindings.each(function () {
            setupBinding($(this), obj);
        });
    }

    ProAct.Bindings = {
        create: create
    };
})(window, ProAct, $);

var sum = ProAct.prob({
    x: 4,
    y: 5,
    z: function () {
        return this.x + this.y;
    },
    txt: function () {
        return 'The result of ' + this.x + ' + ' + this.y + ' is ' + this.z;
    }
});

ProAct.Bindings.create($('.sum'), sum);
ProAct.Bindings.create($('.sum-one-prop'), sum);

function intVal(e) {
    var val = parseInt(e.target.value, 10);

    return isNaN(val) ? 0 : val;
}

var xStream = new ProAct.ThrottlingStream(250);
var yStream = new ProAct.ThrottlingStream(250);

sum.p('x').into(xStream.map(intVal));
sum.p('y').into(yStream.map(intVal));

window.App = {
    x: xStream,
    y: yStream
};