Tiny Excel-like app in vanilla JS
HTML
<p>Inspired by <a href="http://thomasstreet.net/blog/spreadsheet.html">http://thomasstreet.net/blog/spreadsheet.html</a>. Features:</p>
<ul>
<li>30 lines of CoffeeScript</li>
<li>Libraries used: <strong>none</strong></li>
<li>Excel-like syntax (formulas start with "=")</li>
<li>Support for arbitrary expressions (=A1+B2*C3)</li>
<li>Circular reference prevention</li>
<li>Automatic localStorage persistence</li>
</ul>
<table></table>
<footer><p>© 2013 <a href="http://ondras.zarovi.cz/">Ondřej Žára</a></p></footer>
CSS
li {
list-style: none;
}
li:before {
content: "✓ ";
}
input {
border: none;
width: 80px;
font-size: 14px;
padding: 2px;
}
input:hover {
background-color: #eee;
}
input:focus {
background-color: #ccf;
}
input:not(:focus) {
text-align: right;
}
table {
border-collapse: collapse;
}
td {
border: 1px solid #999;
padding: 0;
}
tr:first-child td, td:first-child {
background-color: #ccc;
padding: 1px 3px;
font-weight: bold;
text-align: center;
}
footer {
font-size: 80%;
}
CoffeeScript
for i in [0..5]
row = document.querySelector('table').insertRow(-1)
for j in [0..5]
letter = String.fromCharCode( 'A'.charCodeAt(0) + j-1 )
html = if i && j then "<input id='#{letter+i}'/>" else i || letter
row.insertCell(-1).innerHTML = html
DATA = {}
INPUTS = [].slice.call document.querySelectorAll('input')
INPUTS.forEach (elm) ->
elm.onfocus = (e) ->
e.target.value = localStorage[e.target.id] || ''
elm.onblur = (e) ->
localStorage[e.target.id] = e.target.value
computeAll()
Object.defineProperty DATA, elm.id, { get: ->
value = localStorage[elm.id] || ''
if value.charAt(0) == '='
eval value.substring(1).replace(/([A-E][1-5])/g, 'DATA.$1')
else
if isNaN parseFloat(value) then value else parseFloat(value)
}
computeAll = (elm) ->
try elm.value = DATA[elm.id] for elm in INPUTS
computeAll()