Robert Brewer avatar Robert Brewer committed 81215a9

New variables UI. New pmt global function.

Comments (0)

Files changed (7)

flowrate/__init__.py

                         lo, hi = [int(z.strip()) for z in r]
                         if lo > hi:
                             continue
-                        i.extend(range(lo, hi))
+                        i.extend(range(lo, hi + 1))
                     else:
                         i.append(int(r[0].strip()))
     return list(set(i))
             cherrypy.response.status = 201
 
 
+varsmanager = cherrypy.tools.staticfile.handler(
+    filename=os.path.join(uidir, "variables.html"))
+varsmanager.GET = varsmanager
+
+
 class Variables(object):
     
     exposed = True
     description = """A catalog of available variables."""
 
+    manager = varsmanager
+
     def __init__(self):
         # This triggers tools.trailing_slash to force a redirect if missing
         self.index = self
         """Return a catalog of variables."""
         t = {
             "self": cherrypy.url(qs=cherrypy.request.query_string),
+            "manager": cherrypy.url('/variables/manager',
+                                    qs=cherrypy.request.query_string),
             "description": self.description % vars(),
             }
         t['data'] = [

flowrate/ui/accounts.html

              '&dategroup=' + query['dategroup'];
     $("txslink").href = $("txslink").href + "?" + qs;
     $("flowslink").href = $("flowslink").href + "?" + qs;
+    $("varslink").href = $("varslink").href + "?" + qs;
 
     populate_accounts();
 
         Accounts
         | <a id="txslink" href='/transactions/manager'>Transactions</a>
         | <a id="flowslink" href='/flows/manager'>Flows</a>
+        | <a id="varslink" href='/variables/manager'>Variables</a>
         | <a id="importlink" href="/import">Import</a>
     </h1>
     <div id="status"></div>

flowrate/ui/flows.html

          '&dategroup=' + query['dategroup'];
     $("accountslink").href = $("accountslink").href + "?" + qs;
     $("txslink").href = $("txslink").href + "?" + qs;
+    $("varslink").href = $("varslink").href + "?" + qs;
 
     populate_accounts();
     populate_flows();
         <a id="accountslink" href='/accounts/manager'>Accounts</a>
         | <a id="txslink" href='/transactions/manager'>Transactions</a>
         | Flows
+        | <a id="varslink" href='/variables/manager'>Variables</a>
         | <a id="importlink" href="/import">Import</a>
     </h1>
     <div id="status"></div>

flowrate/ui/import.html

         <a id="accountslink" href='/accounts/manager'>Accounts</a>
         | <a id="flowslink" href='/transactions/manager'>Transactions
         | <a id="flowslink" href='/flows/manager'>Flows</a>
+        | <a id="varslink" href='/variables/manager'>Variables</a>
         | Import
     </h1>
     <div id="status"></div>

flowrate/ui/transactions.html

          '&dategroup=' + query['dategroup'];
     $("accountslink").href = $("accountslink").href + "?" + qs;
     $("flowslink").href = $("flowslink").href + "?" + qs;
+    $("varslink").href = $("varslink").href + "?" + qs;
 
     populate_accounts();
 
         <a id="accountslink" href='/accounts/manager'>Accounts</a>
         | Transactions
         | <a id="flowslink" href='/flows/manager'>Flows</a>
+        | <a id="varslink" href='/variables/manager'>Variables</a>
         | <a id="importlink" href="/import">Import</a>
     </h1>
     <div id="status"></div>

flowrate/ui/variables.html

+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
+    "http://www.w3.org/TR/xhtml1/DTD/strict.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
+<head>
+    <title>Flowrate Variables</title>
+
+<style type='text/css'>
+
+body {
+    margin: 0;
+    padding: 0;
+    font: 10pt Verdana, sans-serif;
+}
+
+.header {
+    padding: 0.25em 1em;
+    background-color: #8495C0;
+    color: white;
+    border-bottom: 1px solid #425367;
+}
+
+h1 {
+    font: 700 14pt Verdana, sans-serif;
+}
+
+h1 a {
+    color: #DDDDEE;
+    text-decoration: none;
+}
+
+#status {
+    position: fixed;
+    top: 0;
+    padding: 0.25em;
+    right: 0;
+    width: 50%;
+    height: 5em;
+    overflow: auto;
+}
+
+#status p {
+    margin: 0;
+    padding: 0;
+    width: 100%;
+    text-align: right;
+}
+
+#fatal_error {
+    visibility: hidden;
+    position: fixed;
+    top: 20px;
+    left: 20px;
+    right: 20px;
+    bottom: 20px;
+    background-color: #FFFFFF;
+    border: 2px solid DarkRed;
+    padding: 2em;
+    overflow: auto;
+    z-index: -1;
+}
+
+#fatal_error_title {
+    font: 700 18pt Verdana, sans-serif;
+    border-bottom: 1px solid DarkRed;
+    color: DarkRed;
+}
+
+#variables {
+    padding: 0 0.25em;
+    border-collapse: collapse;
+}
+
+#variables tr {
+    padding: 0;
+}
+
+#variables th {
+    background-color: DarkGrey;
+    color: white;
+    padding: 0.25em;
+    margin: 0;
+}
+
+#variables tr.varrow {
+    padding: 0;
+    cursor: pointer;
+}
+
+#variables td {
+    vertical-align: bottom;
+    padding: 0 0.25em;
+    border: 1px solid LightGrey;
+}
+
+#variables tr#varedit input[type=text] {
+    width: 100%;
+    background-color: #FFFFF0;
+    color: black;
+}
+
+</style>
+
+<script type="text/javascript" src="https://www.google.com/jsapi"></script>
+<script type="text/javascript" src="/json2.js"></script>
+<script type="text/javascript" src="/common.js"></script>
+<script type="text/javascript">
+
+google.load('visualization', '1.0', {'packages':['corechart']});
+
+//                                  variables                                  //
+
+
+function populate_variables() {
+    var h = http("GET", "/variables", false);
+    h[200] = function(h) {
+        var j = JSON.parse(h.responseText);
+        for (var i = 0; i < j.data.length; i++) {
+            add_var_row(j.data[i]);
+        }
+    }
+    h.send();
+}
+
+variables = {};
+
+function add_var_row(v) {
+    var r = null;
+    var d = null;
+
+    variables[v.name] = v;
+
+    // Create var row
+    r = document.createElement("tr");
+    r.className = 'varrow';
+    r.id = 'varrow' + v.name;
+    r.name = v.name;
+    r.onclick = function () { edit_variable(v.name) };
+
+    // Save button cell
+    d = document.createElement("td");
+    d.className = 'varbuttons';
+    r.appendChild(d);
+
+    // Name cell
+    d = document.createElement("td");
+    d.className = 'varname';
+    set_text(d, v.name);
+    r.appendChild(d);
+
+    // source
+    d = document.createElement("td");
+    d.className = 'varsource';
+    set_text(d, v.source);
+    r.appendChild(d);
+
+    // Insert the row in order by var name ascending
+    var rowset = $("varheader").parentNode;
+    for (var i=0; i < rowset.childNodes.length; i++) {
+        var existing = rowset.childNodes[i];
+        if (existing.className == 'varrow') {
+            if (existing.varname > r.varname) {
+                rowset.insertBefore(r, existing);
+                break;
+            }
+        }
+    }
+    // If no match:
+    if (r.parentNode == null) rowset.appendChild(r);
+
+    return r;
+}
+
+var varname_being_edited = null;
+
+function edit_variable(varname) {
+    // Unhide any previously-edited row
+    if (!(varname_being_edited == null)) {
+        $('varrow' + varname_being_edited).style.display = 'table-row';
+    }
+
+    var varedit = $('varedit');
+
+    if (varname == null) {
+        // Keep existing values to make it easy to copy an existing row
+        $('edit_name').disabled = false;
+        // Remove the row from its current position
+        varedit.parentNode.removeChild(varedit);
+        // Insert before the header row
+        $('varheader').parentNode.insertBefore(varedit, $('varheader'));
+    } else {
+        var v = variables[varname];
+        $('edit_name').value = varname;
+        $('edit_name').disabled = true;
+        $('edit_source').value = v.source;
+
+        // Remove the row from its current position
+        varedit.parentNode.removeChild(varedit);
+        // Insert the edit row before the existing row, then hide the existing
+        var varrow = $('varrow' + varname);
+        varrow.parentNode.insertBefore(varedit, varrow);
+        varrow.style.display = 'none';
+    }
+
+    varname_being_edited = varname;
+}
+
+function save_variable() {
+    var v = {};
+    v.name = $('edit_name').value;
+    v.source = $('edit_source').value;
+
+    if (varname_being_edited == null) {
+        // New variable
+        var uri = '/variables/' + $('edit_name').value;
+        var h = http("PUT", uri, false,
+                     "Saving new variable");
+        h[201] = function(h) { add_var_row(v); };
+    } else {
+        // Update existing variable
+        var h = http("PUT", '/variables/' + varname_being_edited, false,
+                     "Updating variable " + varname_being_edited);
+        // TODO: update cell data
+        h[200] = function(h) {};
+        h[204] = function(h) {};
+    }
+    h.setRequestHeader("Content-Type", "application/json");
+    h.send(JSON.stringify({"body": v}));
+}
+
+//                                   OTHER                                   //
+
+query = {
+    'variables': '',
+    'years': '',
+    'months': '',
+    'days': '',
+    };
+
+function init() {
+    var pairs = document.location.search.substring('?'.length).split('&');
+    var keyval = null;
+    for (var i = 0; i < pairs.length; i++) {
+        keyval = pairs[i].split('=');
+        query[unescape(keyval[0])] = unescape(keyval[1]);
+    }
+
+    var qs = 'accounts=' + encodeURIComponent(query['accounts']) +
+             '&years=' + encodeURIComponent(query['years']) +
+             '&months=' + encodeURIComponent(query['months']) +
+             '&days=' + encodeURIComponent(query['days']) +
+             '&dategroup=' + query['dategroup'];
+    $("accountslink").href = $("accountslink").href + "?" + qs;
+    $("txslink").href = $("txslink").href + "?" + qs;
+    $("flowslink").href = $("flowslink").href + "?" + qs;
+
+    populate_variables();
+    edit_variable(null);
+}
+
+</script>
+
+</head>
+
+<body onLoad="init()">
+<div class='header'>
+    <h1 id="banner">Flowrate:
+        <a id="accountslink" href='/accounts/manager'>Accounts</a>
+        | <a id="txslink" href='/transactions/manager'>Transactions</a>
+        | <a id="flowslink" href='/flows/manager'>Flows</a>
+        | <a id="varslink" href='/variables/manager'>Variables</a>
+        | <a id="importlink" href="/import">Import</a>
+    </h1>
+    <div id="status"></div>
+</div>
+
+<div id='fatal_error'>
+    <h2 id='fatal_error_title'></h2>
+    <p style='float: right'><input type="button" value="Close" onClick="remove_fatal()" /></p>
+    <p id='fatal_error_msg'></p>
+</div>
+
+<div id="chart_div"></div>
+
+<table id='variables'>
+<tr id='varedit'>
+    <td><input id='edit_save' type='button' value='Save' onClick='save_variable()' /></td>
+    <td><input id='edit_name' type='text' value="New variable" /></td>
+    <td><input id='edit_source' type='text' value="decimal.Decimal('3.33')" /></td>
+</tr>
+<tr id='varheader'>
+    <th><span onClick="edit_variable(null)" title="New variable" style="cursor: pointer">(+)</span></th>
+    <th>Name</th>
+    <th>Source</th>
+</tr>
+</table>
+
+</body>
+</html>

flowrate/variables.py

 def eom(d):
     return d.replace(day=calendar.monthrange(d.year, d.month)[1])
 
+def pmt(interest_rate, number_of_payments, present_value):
+    """Return the payment amount for a loan using a constant schedule."""
+    i, N, pv = interest_rate, number_of_payments, present_value
+    return (i * pv) / (1 - ((1 + i) ** -N))
+
 
 missing = object()
 
         'days': days,
         'months': months,
         'eom': eom,
+        'pmt': pmt,
         }
 
     def __init__(self):
Tip: Filter by directory path e.g. /media app.js to search for public/media/app.js.
Tip: Use camelCasing e.g. ProjME to search for ProjectModifiedEvent.java.
Tip: Filter by extension type e.g. /repo .js to search for all .js files in the /repo directory.
Tip: Separate your search with spaces e.g. /ssh pom.xml to search for src/ssh/pom.xml.
Tip: Use ↑ and ↓ arrow keys to navigate and return to view the file.
Tip: You can also navigate files with Ctrl+j (next) and Ctrl+k (previous) and view the file with Ctrl+o.
Tip: You can also navigate files with Alt+j (next) and Alt+k (previous) and view the file with Alt+o.