JSFiddle - React, Tailwind, and code Playground
HTML
<link rel="stylesheet" href="http://netdna.bootstrapcdn.com/bootstrap/3.1.1/css/bootstrap.min.css">
<script src="//ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<script src="//netdna.bootstrapcdn.com/bootstrap/3.1.1/js/bootstrap.min.js"></script>
<p>All equations must start with a = character (like in Excel).</p>
<p>Use the # character to lookup variables and cell references in the equation editor.</p>
<hr>
<div id="dynamic-table-main">
<div data-ng-controller="GridCtrl">
<table class="table sheet table-bordered table-hover table-striped" id="grid">
<thead></thead>
<tbody>
<tr ng-repeat="row in data.body">
<td ng-repeat="col in row" class="input-tooltip-wrapper">
<formula-editor value="col.value"></formula-editor> <span class="c-tooltip">{{compute(col)}}</span>
<div class="cell-view" ng-bind="compute(col) | cellFormatter" tabindex="{{ $parent.$index + $index }}" style="text-align: {{isNum(compute(col)) ? 'right' : 'left'}}"></div>
</td>
</tr>
</tbody>
</table>
<h3>Variables</h3>
<div class="row">
<div class="col-md-6">
<table class="table variables table-bordered table-hover table-striped">
<tbody>
<tr ng-repeat="variable in variables">
<td class="variable-name">{{variable.name}}</td>
<td>
<input class="form-control" type="text" ng-model="variable.value" />
</td>
<td> <a href="#" ng-click="removeVariable(variable)" class="btn btn-danger">Remove</a>
</td>
</tr>
<tr>
<form data-ng-submit="addVariable(newVar)">
...
CSS
body {
padding:50px 20px 20px 20px;
}
table.sheet {
table-layout:fixed;
}
table.sheet .taggable-text-wrapper > div {
outline: 0;
}
.input-tooltip-wrapper {
position:relative;
}
/* .input-tooltip-wrapper:hover .c-tooltip{
display:block
} */
.taggable-text-wrapper:hover + .c-tooltip {
display:block
}
.c-tooltip {
display:none;
position:absolute;
min-width:100px;
margin-left:0;
line-height:30px;
color:#fff;
padding:0 5px;
border-radius:4px;
font-size:12px;
background:rgba(0, 0, 0, 0.8);
top:auto;
bottom:150%;
left:0;
z-index:10;
text-align:center;
margin-top:0;
transition:all 0.5s ease;
}
.c-tooltip:after {
position: absolute;
width: 0;
height: 0;
border-color: transparent;
border-style: solid;
display:block;
content:" ";
bottom: -6px;
left:12px;
margin-left: -6px;
border-width: 6px 6px 0;
border-top-color: rgba(0, 0, 0, 0.8);
}
table.sheet td {
position: relative;
}
table.sheet th.index {
width:10%;
}
table.sheet td .taggable-text-wrapper {
display: none;
position: absolute;
left: -10px;
right: 0;
top: -10px;
bottom: 0;
width: 100%;
height:100%;
z-index:10;
}
table.sheet td .taggable-text-wrapper div {
min-width:100%;
min-height:34px;
padding:15px;
-webkit-box-shadow: 0 0 4px 1px rgba(0, 0, 0, 0.3);
box-shadow: 0 0 4px 1px rgba(0, 0, 0, 0.3);
background:#fff;
border-radius:4px;
}
table.variables {
}
td.variable-name {
font-size:18px;
font-weight:bold;
line-height:30px !important;
vertical-align:middle;
}
table.variables .btn {
min-width:100px;
}
.btn-tag-control {
padding:0px 6px;
margin:3px;
}
JavaScript
// =================================================
// LIBS
/*
IntegraXor Web SCADA - JavaScript Number Formatter
http://www.integraxor.com/
author: KPL, KHL
(c)2011 ecava
Dual licensed under the MIT or GPL Version 2 licenses.
*/
window.format = function(b, a) {
if(!b || isNaN(+a))return a;
var a = b.charAt(0) == "-" ? -a : +a, j = a < 0 ? a = -a : 0, e = b.match(/[^\d\-\+#]/g), h = e && e[e.length - 1] || ".", e = e && e[1] && e[0] || ",", b = b.split(h), a = a.toFixed(b[1] && b[1].length), a = +a + "", d = b[1] && b[1].lastIndexOf("0"), c = a.split(".");
if(!c[1] || c[1] && c[1].length <= d)a = (+a).toFixed(d + 1);
d = b[0].split(e);
b[0] = d.join("");
var f = b[0] && b[0].indexOf("0");
if(f > -1)for(; c[0].length < b[0].length - f;)c[0] = "0" + c[0]; else+c[0] == 0 && (c[0] = "");
a = a.split(".");
a[0] = c[0];
if(c = d[1] && d[d.length -
1].length) {
for(var d = a[0], f = "", k = d.length % c, g = 0, i = d.length; g < i; g++)f += d.charAt(g), !((g - k + 1) % c) && g < i - c && (f += e);
a[0] = f
}
a[1] = b[1] && a[1] ? h + a[1] : "";
return(j ? "-" : "") + a[0] + a[1]
};
/*!
* jquery.taggable-text.js
*
* Adapted from https://github.com/yuku-t/jquery-textcomplete
*/
(function() {
var UtilityFunctions = {
getSelection : function(containerEl) {
// http://stackoverflow.com/a/13950376/564580
var range = window.getSelection().getRangeAt(0);
// /\ this is sometimes painful
var preSelectionRange = range.cloneRange();
preSelectionRange.selectNodeContents(containerEl);
preSelectionRange.setEnd(range.startContainer, range.startOffset);
var start = preSelectionRange.toString().length;
if(typeof start === "undefined") {
start = 0;
}
return {
start : start,
end : start +...