Table Editor
https://confluence.ontrq.com/display/KB/Medium+level+-+native+JS/#Mediumlevel-nativeJS-#3:TableEditor
by fullyslick
HTML
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport"
content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<link rel="stylesheet" href="style.css">
<title>Table Editor</title>
</head>
<body>
<div class="container">
<h1>Table editor</h1>
<form action="#" class="filter-form">
<label for="name-filter">Filter By Name</label>
<input type="text" name="name-filter" id="name-filter">
</form>
<table>
<thead>
<tr id="tableHeadersShell">
<th class="sort-header" data-sort="id">Id</th>
<th class="sort-header" data-sort="name">Name</th>
<th class="sort-header" data-sort="quantity">Qty</th>
<th>Availability</th>
<th>Delete</th>
</tr>
</thead>
<tbody id="rowList">
</tbody>
</table>
<div class="operations">
<button type="button" id="addRowBtn" class="operation-button white">Add new row</button>
<button type="button" id="deleteRowBtn" class="operation-button red">Delete row</button>
<button type="button" id="demoDataBtn" class="operation-button green">Demo data</button>
<button type="button" id="clearBtn" class="operation-button blue">Clear table</button>
<button type="button" id="exportTableBtn" class="operation-button yellow">Export table</button>
</div>
<form action="#" id="addRowForm" name="addrowform" class="add-row-form">
<h2>Add new row</h2>
<div class="form-group">
<label for="rowName">Name</label>
<input type="text" name="rowName" id="rowName" required>
</div>
<div class="form-group">
<label for="rowQty">Qty</label>
<select name="rowQty" id="rowQty">
<option value="1">1</option>
<option...
CSS
body {
font-family: Arial, sans-serif;
-webkit-touch-callout: none;
-webkit-user-select: none;
-khtml-user-select: none;
-moz-user-select: none;
-ms-user-select: none;
user-select: none;
}
h1,
h2 {
text-align: center;
}
.container {
max-width: 960px;
margin: 0 auto;
}
table {
width: 100%;
padding: 5px;
border-collapse: collapse;
}
table, th, td {
border: solid 1px grey;
}
thead {
background: lightgrey;
}
td {
text-align: center;
vertical-align: middle;
}
td:hover {
cursor: grab;
}
tbody tr {
border-top: grey 1px solid;
display: none;
}
tbody tr:nth-child(even) {
background-color: #f3f3f3;
}
tbody tr:nth-child(odd) {
background-color: #fff;
}
textarea {
display: block;
margin: 10px 0;
}
.active {
display: table-row;
}
.filter-form {
margin: 10px 0;
}
.add-row-form {
border: solid 1px grey;
}
.form-group {
padding: 10px;
border-bottom: solid 1px grey;
}
.form-submit {
margin: 10px;
}
label {
display: block;
margin: 0 0 10px 0;
}
.operations {
margin: 20px;
}
.operation-button {
line-height: 2;
color: white;
border: solid grey 1px;
border-radius: 5px;
}
.white {
color: black;
background: white;
}
.red {
background: red;
}
.green {
background: green;
}
.blue {
background: blue;
}
.yellow {
background: darkorange;
}
.hidden {
display: none;
}
.pagination > ul {
list-style: none;
display: flex;
flex-flow: row wrap;
}
.pagination-btn {
display: block;
background: none;
color: dodgerblue;
border: solid 1px darkgrey;
text-decoration: none;
padding: 3px 10px;
}
.pagination-btn:hover {
cursor: pointer;
}
.sort-header:hover {
cursor: pointer;
}
.sort-header.ascending::after {
content: ' ↑';
}
.sort-header.descending::after {
content: ' ↓';
}
JavaScript
// https://confluence.ontrq.com/display/KB/Medium+level+-+native+JS/#Mediumlevel-nativeJS-#3:TableEditor
// #3: Table Editor Module 3 and Module 8 Sorting
(function() {
'use strict';
var model = {
id: 0,
rows: {},
filteredRows: {},
sortedRows: {},
addRow: function(row) {
var rowId = this.id + 1;
if (row.availability) {
row.availability = 'yes';
} else {
row.availability = 'no';
}
// Insert the newly created row to the model.rows object
this.rows[this.id] = [rowId, row.name, row.qty, row.availability];
// Increment id every time row is added to make it unique
this.id++;
},
deleteRow: function(rowId) {
rowId = Number(rowId);
// Find the requested for deletion row and delete it
for (var rowKey in this.rows) {
if (this.rows.hasOwnProperty(rowKey)) {
if (this.rows[rowKey][0] === rowId) {
delete this.rows[rowKey];
}
}
}
},
deleteAllRows: function() {
this.rows = {};
},
setDemoData: function() {
var rowAmount = this.generateRandomInt(1, 10),
row = {};
for (var i = 0; i < rowAmount; i++) {
row = this.generateRandomRow();
this.addRow(row);
}
},
generateRandomRow: function() {
return {
name: this.generateRandomName(),
qty: this.generateRandomInt(0, 1000),
availability: this.generateRandomInt(0, 1)
};
},
generateRandomInt: function(min, max) {
min = Math.ceil(min);
max = Math.floor(max);
return Math.floor(Math.random() * (max - min + 1)) + min;
},
...