JSFiddle - React, Tailwind, and code Playground
HTML
<script src="//cdn.jsdelivr.net/mithril/0.1.22/mithril.min.js"></script>
CSS
html,body {margin:0;padding:0;}
table {border-collapse:collapse;}
tr:first-child td,td:first-child {background:#ddd;}
td {border:1px solid #888;padding:0;text-align:center;}
td input {border:0;display:block;height:20px;padding:1px;width:80px;}
a {border:1px solid #888;border-top:0;display:inline-block;margin:3px;padding:0 3px;text-decoration:none;}
.formula {margin:3px;width:1337px;}
JavaScript
var data = JSON.parse(localStorage["spreadsheet"] || "{}")
for (var cell in data) data[cell] = computable(data[cell])
function computable(value) {
var output = new String(value)
output.valueOf = compute.bind(this, value)
return isNaN(+value) ? output : +value
}
function compute(value) {
if (value != null && value[0] == "=") {
try { with (data) return eval(value.substring(1)) } catch (e) {}
}
else return value
}
function update(cell, value) {
data[cell] = computable(value)
localStorage["spreadsheet"] = JSON.stringify(data)
}
var cell = m.prop()
function grid(withCell) {
for (var rows = [], i = 0; i < 27; i++) {
for (var cols = [], j = 0; j < 17; j++) {
var letter = String.fromCharCode("a".charCodeAt(0) + j - 1)
cols.push(m("td", i && j ? withCell(letter + i) : i || letter))
}
rows.push(m("tr", cols))
}
return m("table", rows)
}
function view() {
return [
m("input.formula", {
onchange: m.withAttr("value", update.bind(this, cell())),
value: data[cell()] || ""
}),
grid(function(cellName) {
var value = compute(data[cellName]) || ""
return m("input", {
onkeypress: move,
onfocus: cell.bind(this, cellName),
onchange: m.withAttr("value", update.bind(this, cellName)),
value: value,
style: {textAlign: isNaN(value) || value === "" ? "left" : "right"}
})
})
]
}
function move(e) {
var td = e.target.parentNode, tr = td.parentNode, table = tr.parentNode
if (e.keyCode == 37) return highlight(tr.childNodes[Math.max(1, td.cellIndex - 1)].firstChild)
else if (e.keyCode == 38) return highlight(table.childNodes[Math.max(1, tr.rowIndex - 1)].childNodes[td.cellIndex].firstChild)
else if (e.keyCode == 39) return highlight(tr.childNodes[Math.min(tr.childNodes.length - 1, td.cellIndex + 1)].firstChild)
else if (e.keyCode == 40) return highlight(table.childNodes[Math.min(table.childNodes.length - 1, tr.rowIndex + 1)].childNodes[td.cellIndex].firstChild)
else m.redraw.strategy("none")
}
function highlight(cell)...