react template

HTML

<script src="//netdna.bootstrapcdn.com/bootstrap/3.1.1/js/bootstrap.min.js"></script>
<script src="//cdnjs.cloudflare.com/ajax/libs/accounting.js/0.3.2/accounting.min.js"></script>
<script src="//cdnjs.cloudflare.com/ajax/libs/underscore.js/1.6.0/underscore-min.js"></script>
<script src="http://fb.me/JSXTransformer-0.10.0.js"></script>
<script src="http://fb.me/react-0.10.0.min.js"></script>
<link rel="stylesheet" href="//netdna.bootstrapcdn.com/bootstrap/3.1.1/css/bootstrap.min.css">
<script src="https://rawgit.com/appendto/jquery-mockjax/master/jquery.mockjax.js"></script>
<script src="https://rawgit.com/postaljs/postal.js/master/lib/postal.js"></script>
<script src="https://rawgit.com/postaljs/postal.request-response/master/lib/postal.request-response.js"></script>
<script src="http://fb.me/react-js-fiddle-integration.js"></script>

CSS

.worksheet-title {
	padding: 0 0 0 1em;
}

.budget-item {
	margin: 0 0 1% 0;
}

.budget-item .desc {
	/*margin-right: .5em;*/
}

.budget-item input[type="text"] {
	width: 5em;
	padding-right:5%;
	text-align: right;
	border-radius: 2px;
	border: 1pt solid rgba(49, 44, 113, .3);
}

.budget-item .budget input[type="text"] {
	background-color: rgba(183, 219, 162, .7);
}

.budget-item .actual input[type="text"] {
	background-color: rgba(250, 207, 185, .7);
}

.budget-item div:not(:first-child) {
	text-align: right;
}

.budget-item .header {
	font-weight: bold;
	text-align: left;
	color: rgba(49, 44, 113, .7);
}

.budget-item-add {
	padding: .5em 0 .25em 0;
	margin: 0 0 .5em 0;
	border: 1pt solid rgba(49, 44, 113, .15);
	border-radius: 5px;
}

.budget-item-add .ctrls {
	text-align: right;
}

.budget-item-add .desc input[type="text"]  {
	width: 100%;
	text-align: left;
}

.budget-item-add input[type="text"] {
	background-color: rgba(138, 135, 174, .4);
}

.budget-item-add select {
	background-color: rgba(138, 135, 174, .4);
	border: 1pt solid rgba(49, 44, 113, .15);
	width: 100%;
}

.budget-item button {
	width: 5em;
	text-align: center;
}

.amount {
	text-align: right;
}

.summary {
	border: 1pt solid rgba(49, 44, 113, .3);
	padding: 0 1.5em 1em 1.5em;
}

.summary-header {
	text-align: center;
}

.summary.budget {
	background-color: rgba(183, 219, 162, .7);
}

.summary.actual {
	background-color: rgba(250, 207, 185, .7);
}

.remainder {
	border-top: 1pt solid black;
	font-weight: bold;
}

JavaScript 1.7

/** @jsx React.DOM */
(function(React, postal, $) {
    // We need to tell postal how to get a deferred instance
    postal.configuration.promise.createDeferred = function() {
        return new $.Deferred();
    };
    // We need to tell postal how to get a "public-facing"/safe promise instance
    postal.configuration.promise.getPromise = function(dfd) {
        return dfd.promise();
    };

    $.mockjax({
        url: '/worksheet/2014-05',
        contentType: "text/json",
        responseTime: 100,
        responseText: {
            period : "May 2014",
            items  : [
                { 
                    description : "Rent",
                    type        : "expense",
                    budget      : 1600,
                    actual      : 1600
                },
                {
                    description : "Salary",
                    type        : "income",
                    budget      : 5300,
                    actual      : 4875
                },
                { 
                    description : "Groceries",
                    type        : "expense",
                    budget      : 800,
                    actual      : 650
                }
            ]
        }
    });
    
    var budgetDataSrc = (function(){
        var dataSrc = {
            read: function(data, env) {
                var url = "/worksheet/" + data.periodId;
                $.ajax({
                    url: url,
                    dataType: 'json'
                }).then(function(data) {
                    env.reply(data);
                });
            }
        };
        
        postal.subscribe({
            channel: "worksheet",
            topic: "#",
            callback: function(data, env) {
                if(dataSrc.hasOwnProperty(env.topic)) {
                    dataSrc[env.topic](data, env);
                } else {
                    throw new Error("No such operation exists on the budget datasource:" + env.topic);
           ...