Monday, September 22, 2014

Simple spreadsheet

Ever wanted to use a spreadsheet just for a quick calculation either on your computer or especially on a touch pad.  If nothing else it can be used as a learning to in building your own spreadsheets. Years ago I found this source code for a minimal spreadsheet from a CPM (forerunner of DOS operating systems) magazine. Typed it in and have been using it since. Of course many improvements have been made since the original code was typed in.  As I port the code to new platforms, there are always enhancements to be made.



Everything now is web based so why not a basic spreadsheet. It is made up of three files that need to reside in the same directory. Major improvements can and should be made. Hope you enjoy this page as much as I did from the code I used years ago.  To be honest there are many good javascript spreadsheets (aka http://www.simple-groupware.de/cms/Spreadsheet/Home), this article is just for example in case you wanted to dabble one of your own.


---------------------------------------------------------------------------------------------------------------

Main file: ss.html

<!DOCTYPE html>
<html>
<head>
  <meta http-equiv="content-type" content="text/html; charset=UTF-8">
  <title>Tiny Excel-like app in vanilla JS.</title>
 
  <script type='text/javascript' src='ss.js'></script>
 
  <link rel="stylesheet" type="text/css" href="ss.css">

 script type='text/javascript'>//<![CDATA[
window.onload=function(){
for (var i=0; i<10; i++) {
    var row = document.querySelector("table").insertRow(-1);
    for (var j=0; j<10; j++) {
        var letter = String.fromCharCode("A".charCodeAt(0)+j-1);
        row.insertCell(-1).innerHTML = i&&j ? "<input id='"+ letter+i +"'/>" : i||letter;
    }
}

var DATA={}, INPUTS=[].slice.call(document.querySelectorAll("input"));
INPUTS.forEach(function(elm) {
    elm.onfocus = function(e) {
        e.target.value = localStorage[e.target.id] || "";
    };
    elm.onblur = function(e) {
        localStorage[e.target.id] = e.target.value;
        computeAll();
    };
    var getter = function() {
        var value = localStorage[elm.id] || "";
        if (value.charAt(0) == "=") {
            with (DATA) return eval(value.substring(1));
        } else { return isNaN(parseFloat(value)) ? value : parseFloat(value); }
    };
    Object.defineProperty(DATA, elm.id, {get:getter});
    Object.defineProperty(DATA, elm.id.toLowerCase(), {get:getter});
});
(window.computeAll = function() {
    INPUTS.forEach(function(elm) { try { elm.value = DATA[elm.id]; } catch(e) {} });
})();
}//]]> 

</script>
</head>
<body>
<p><b> Simple sheet</b></p>
<p>Features:</p>

<ul>
    <li><b>Use at your own risk</b></li>
    <li>Enter key does not work, click on a cell to accept input</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>
</ul>
<br />
<table></table>
<br />
<footer> <p class="copy-left">&copy;</p> 2014 <a href="http://computoman.blogspot.com/">Computoman<a></p></footer>
</body>
</html>


---------

CSS file: ss.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%;
}

.copy-left {
     display: inline-block;
     text-align: right;
     margin: 0px;
    -moz-transform: scaleX(-1);
    -o-transform: scaleX(-1);
    -webkit-transform: scaleX(-1);
    transform: scaleX(-1);
    filter: FlipH;
    -ms-filter: "FlipH";
}

----------------
Javascript: ss.js

 for (var i=0; i<6; i++) {
    var row = document.querySelector("table").insertRow(-1);
    for (var j=0; j<6; j++) {
        var letter = String.fromCharCode("A".charCodeAt(0)+j-1);
        row.insertCell(-1).innerHTML = i&&j ? "<input id='"+ letter+i +"'/>" : i||letter;
    }
}

var DATA={}, INPUTS=[].slice.call(document.querySelectorAll("input"));
INPUTS.forEach(function(elm) {
    elm.onfocus = function(e) {
        e.target.value = localStorage[e.target.id] || "";
    };
    elm.onblur = function(e) {
        localStorage[e.target.id] = e.target.value;
        computeAll();
    };
    var getter = function() {
        var value = localStorage[elm.id] || "";
        if (value.charAt(0) == "=") {
            with (DATA) return eval(value.substring(1));
        } else { return isNaN(parseFloat(value)) ? value : parseFloat(value); }
    };
    Object.defineProperty(DATA, elm.id, {get:getter});
    Object.defineProperty(DATA, elm.id.toLowerCase(), {get:getter});
});
(window.computeAll = function() {
    INPUTS.forEach(function(elm) { try { elm.value = DATA[elm.id]; } catch(e) {} });
})();



No comments:

Post a Comment