JSFiddle - React, Tailwind, and code Playground
HTML
<link rel="stylesheet" href="http://ajax.googleapis.com/ajax/libs/jqueryui/1.8.9/themes/start/jquery-ui.css">
<table class="data" data-editable="1" data-ajax-dropdown="/echo/json/">
<thead>
<tr>
<th class="col-id">Id</th>
<th class="col-name">Name</th>
<th class="col-race">Race</th>
<th class="col-bday">Birthdate</th>
<th class="col-desc">Desc</th>
</tr>
</thead>
<tbody>
<tr data-id="1000" data-projectid="3">
<td>
1000
</td>
<td data-editor="text" data-key="name">
<span>Dave</span>
</td>
<td data-editor="dropdown" data-key="race" data-select="raceX" data-value="3" style="position:relative">
<span>AI</span>
</td>
<td data-editor="datetime" data-key="birthdate">
<span>11/15/1978</span>
</td>
<td data-editor="textarea" data-key="desc">
<span>Likes memes.</span>
</td>
</tr>
<tr data-id="1001" data-projectid="2">
<td>
1001
</td>
<td data-editor="text" data-key="name">
<span>Tom</span>
</td>
<td data-editor="dropdown" data-key="race" data-select="race" data-value="1">
<span>Human</span>
</td>
<td data-editor="datetime" data-key="birthdate">
<span>9/12/1988</span>
</td>
<td data-editor="textarea" data-key="desc">
<span>High fives a lot.</span>
</td>
</tr>
<tr data-id="1002" data-projectid="1">
<td>
1002
</td>
<td data-editor="text" data-key="name">
<span>Jordan</span>
</td>
<td data-editor="dropdown" data-key="race" data-select="race" data-value="2">
<span>Elf</span>
</td>
<td data-editor="datetime" data-key="birthdate">
<span>4/1/1984</span>
</td>
<td...
CSS
table.data {
border: 1px solid black;
border-collapse: collapse;
width: 100%;
table-layout: fixed; /* critical! Try it without this, edit something */
}
table.data th {
font-weight: bold;
}
table.data td,
table.data th {
border: 1px solid black;
padding: 2px;
vertical-align: top;
word-break: break-word; /*so long unbreakable text still wraps*/
}
th.col-id { width: 80px; }
th.col-name { min-width: 100px; }
th.col-race { width: 100px; }
th.col-bday{ width: 80px; }
th.col-desc { min-width: 100px; }
h2 {
font-size: 25px;
margin-top: 10px;
}
#changelog li {
font-weight: bold;
padding: 7px;
}
#changelog ul.edits li {
font-weight: normal;
padding: 0px;
}
/****editors****/
td.editable { cursor: pointer; }
tr.dirty {
}
td.dirty {
background-color: LightBlue;
}
/*dropdown*/
.inlineedit-dropdown {
position: absolute;
background-color: White;
max-height: 150px;
overflow-y: auto;
border: 1px solid black;
}
.inlineedit-dropdown ul {
list-style-type: none;
margin: 0px;
}
.inlineedit-dropdown li {
/* ensures a vertical scrollbar doesn't cause a horizontal scroll bar due to the
scrollbar eating up some horizontal realestate
*/
padding-right: 20px;
word-break: normal;
white-space: nowrap;
}
.inlineedit-dropdown li:hover {
background-color: lightyellow;
}
.inlineedit-dropdown li.selected {
background-color: #ddddff;
}
JavaScript
(function($) {
$.fn.inlineEdit = function(cmd) {
if (cmd === "get") {
return this.data("inlineEditor");
}
var self = this;
this.data("changes", []);
// handle clicking on a cell to enter edit mode
this.delegate("td[data-editor]", "click", function() {
var cell = $(this);
// already editing
if (cell.attr("data-editing") === "1") {
return false;
}
// save other active editors
closeEditor(self.find("td[data-editing=1]"));
if (startEditor(cell)) {
// cell is entering edit mode
cell.attr("data-editing", "1");
}
// cancel click event
return false;
});
// handle clicking outside of an editor
// this should save any open editors
$("body").click(function() {
closeEditor(self.find("td[data-editing=1]"));
});
// event when an editor implementation signals
// it is done and the editor should be closed
this.delegate("td", "save", function(ev) {
closeEditor(getCell(ev.target));
ev.stopPropagation();
self.trigger("save");
});
// event when an editor implementation signals
// it is cancelling itself
this.delegate("td", "cancel", function(ev) {
closeEditor(getCell(ev.target), true);
});
// apply editable css to those with editors
this.find("td[data-editor]").toggleClass("editable");
var api = {
getAllChanges: function(entityId) {
var changes = self.data("changes");
if (!changes) {
changes = [];
self.data("changes", changes);
}
...