Skip to content

Commit 70e9743

Browse files
committed
Add HTML table: filter and sort (metafacture-core#369)
The flux-commands-table.html is a HTML view of flux-commands.md with filter and sort functionality of the signature of the commands. Proof of concept - WIP
1 parent ceacddb commit 70e9743

File tree

3 files changed

+391
-0
lines changed

3 files changed

+391
-0
lines changed

Diff for: assets/css/sortTable.css

+101
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,101 @@
1+
.sr-only {
2+
position: absolute;
3+
top: -30em;
4+
}
5+
6+
table.sortable td,
7+
table.sortable th {
8+
padding: 0.125em 0.25em;
9+
width: 22em;
10+
}
11+
12+
table.sortable th {
13+
font-weight: bold;
14+
border-bottom: thin solid #888;
15+
position: relative;
16+
}
17+
18+
table.sortable th.no-sort {
19+
padding-top: 0.35em;
20+
}
21+
22+
table.sortable th:nth-child(5) {
23+
width: 10em;
24+
}
25+
26+
table.sortable th button {
27+
padding: 4px;
28+
margin: 1px;
29+
font-size: 100%;
30+
font-weight: bold;
31+
background: transparent;
32+
border: none;
33+
display: inline;
34+
right: 0;
35+
left: 0;
36+
top: 0;
37+
bottom: 0;
38+
width: 100%;
39+
text-align: left;
40+
outline: none;
41+
cursor: pointer;
42+
}
43+
44+
table.sortable th button span {
45+
position: absolute;
46+
right: 4px;
47+
}
48+
49+
table.sortable th[aria-sort="descending"] span::after {
50+
content: "▼";
51+
color: currentcolor;
52+
font-size: 100%;
53+
top: 0;
54+
}
55+
56+
table.sortable th[aria-sort="ascending"] span::after {
57+
content: "▲";
58+
color: currentcolor;
59+
font-size: 100%;
60+
top: 0;
61+
}
62+
63+
table.show-unsorted-icon th:not([aria-sort]) button span::after {
64+
content: "♢";
65+
color: currentcolor;
66+
font-size: 100%;
67+
position: relative;
68+
top: -3px;
69+
left: -4px;
70+
}
71+
72+
table.sortable td.num {
73+
text-align: right;
74+
}
75+
76+
table.sortable tbody tr:nth-child(odd) {
77+
background-color: #ddd;
78+
}
79+
80+
/* Focus and hover styling */
81+
82+
table.sortable th button:focus,
83+
table.sortable th button:hover {
84+
padding: 2px;
85+
border: 2px solid currentcolor;
86+
background-color: #e5f4ff;
87+
}
88+
89+
table.sortable th button:focus span,
90+
table.sortable th button:hover span {
91+
right: 2px;
92+
}
93+
94+
table.sortable th:not([aria-sort]) button:focus span::after,
95+
table.sortable th:not([aria-sort]) button:hover span::after {
96+
content: "▼";
97+
color: currentcolor;
98+
font-size: 100%;
99+
top: 0;
100+
}
101+

Diff for: assets/js/sortable-table.js

+168
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,168 @@
1+
/*
2+
* This content is licensed according to the W3C Software License at
3+
* https://www.w3.org/Consortium/Legal/2015/copyright-software-and-document
4+
*
5+
* File: sortable-table.js
6+
*
7+
* Desc: Adds sorting to a HTML data table that implements ARIA Authoring Practices
8+
*/
9+
10+
'use strict';
11+
12+
class SortableTable {
13+
constructor(tableNode) {
14+
this.tableNode = tableNode;
15+
16+
this.columnHeaders = tableNode.querySelectorAll('thead th');
17+
18+
this.sortColumns = [];
19+
20+
for (var i = 0; i < this.columnHeaders.length; i++) {
21+
var ch = this.columnHeaders[i];
22+
var buttonNode = ch.querySelector('button');
23+
if (buttonNode) {
24+
this.sortColumns.push(i);
25+
buttonNode.setAttribute('data-column-index', i);
26+
buttonNode.addEventListener('click', this.handleClick.bind(this));
27+
}
28+
}
29+
30+
this.optionCheckbox = document.querySelector(
31+
'input[type="checkbox"][value="show-unsorted-icon"]'
32+
);
33+
34+
if (this.optionCheckbox) {
35+
this.optionCheckbox.addEventListener(
36+
'change',
37+
this.handleOptionChange.bind(this)
38+
);
39+
if (this.optionCheckbox.checked) {
40+
this.tableNode.classList.add('show-unsorted-icon');
41+
}
42+
}
43+
}
44+
45+
setColumnHeaderSort(columnIndex) {
46+
if (typeof columnIndex === 'string') {
47+
columnIndex = parseInt(columnIndex);
48+
}
49+
50+
for (var i = 0; i < this.columnHeaders.length; i++) {
51+
var ch = this.columnHeaders[i];
52+
var buttonNode = ch.querySelector('button');
53+
if (i === columnIndex) {
54+
var value = ch.getAttribute('aria-sort');
55+
if (value === 'descending') {
56+
ch.setAttribute('aria-sort', 'ascending');
57+
this.sortColumn(
58+
columnIndex,
59+
'ascending',
60+
ch.classList.contains('num')
61+
);
62+
} else {
63+
ch.setAttribute('aria-sort', 'descending');
64+
this.sortColumn(
65+
columnIndex,
66+
'descending',
67+
ch.classList.contains('num')
68+
);
69+
}
70+
} else {
71+
if (ch.hasAttribute('aria-sort') && buttonNode) {
72+
ch.removeAttribute('aria-sort');
73+
}
74+
}
75+
}
76+
}
77+
78+
sortColumn(columnIndex, sortValue, isNumber) {
79+
function compareValues(a, b) {
80+
if (sortValue === 'ascending') {
81+
if (a.value === b.value) {
82+
return 0;
83+
} else {
84+
if (isNumber) {
85+
return a.value - b.value;
86+
} else {
87+
return a.value < b.value ? -1 : 1;
88+
}
89+
}
90+
} else {
91+
if (a.value === b.value) {
92+
return 0;
93+
} else {
94+
if (isNumber) {
95+
return b.value - a.value;
96+
} else {
97+
return a.value > b.value ? -1 : 1;
98+
}
99+
}
100+
}
101+
}
102+
103+
if (typeof isNumber !== 'boolean') {
104+
isNumber = false;
105+
}
106+
107+
var tbodyNode = this.tableNode.querySelector('tbody');
108+
var rowNodes = [];
109+
var dataCells = [];
110+
111+
var rowNode = tbodyNode.firstElementChild;
112+
113+
var index = 0;
114+
while (rowNode) {
115+
rowNodes.push(rowNode);
116+
var rowCells = rowNode.querySelectorAll('th, td');
117+
var dataCell = rowCells[columnIndex];
118+
119+
var data = {};
120+
data.index = index;
121+
data.value = dataCell.textContent.toLowerCase().trim();
122+
if (isNumber) {
123+
data.value = parseFloat(data.value);
124+
}
125+
dataCells.push(data);
126+
rowNode = rowNode.nextElementSibling;
127+
index += 1;
128+
}
129+
130+
dataCells.sort(compareValues);
131+
132+
// remove rows
133+
while (tbodyNode.firstChild) {
134+
tbodyNode.removeChild(tbodyNode.lastChild);
135+
}
136+
137+
// add sorted rows
138+
for (var i = 0; i < dataCells.length; i += 1) {
139+
tbodyNode.appendChild(rowNodes[dataCells[i].index]);
140+
}
141+
}
142+
143+
/* EVENT HANDLERS */
144+
145+
handleClick(event) {
146+
var tgt = event.currentTarget;
147+
this.setColumnHeaderSort(tgt.getAttribute('data-column-index'));
148+
}
149+
150+
handleOptionChange(event) {
151+
var tgt = event.currentTarget;
152+
153+
if (tgt.checked) {
154+
this.tableNode.classList.add('show-unsorted-icon');
155+
} else {
156+
this.tableNode.classList.remove('show-unsorted-icon');
157+
}
158+
}
159+
}
160+
161+
// Initialize sortable table buttons
162+
window.addEventListener('load', function () {
163+
var sortableTables = document.querySelectorAll('table.sortable');
164+
for (var i = 0; i < sortableTables.length; i++) {
165+
new SortableTable(sortableTables[i]);
166+
}
167+
});
168+

Diff for: docs/flux/flux-commands-table.html

+122
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,122 @@
1+
<!DOCTYPE html>
2+
<html>
3+
<head>
4+
<link rel="stylesheet" href="../../assets/css/sortTable.css">
5+
<script src="../../assets/js/sortable-table.js"></script>
6+
<script>
7+
function getValue(param) {
8+
// Declare variables
9+
var filter, table, tr, td, i, txtValue, column;
10+
11+
input3 = document.getElementById("3");
12+
filter3 = input3.querySelector('.name').value.toUpperCase();
13+
14+
input4 = document.getElementById("4");
15+
filter4 = input4.querySelector('.name').value.toUpperCase();
16+
17+
table = document.getElementById("myTable");
18+
tr = table.getElementsByTagName("tr");
19+
20+
// Loop through all table rows, and hide those who don't match the search query
21+
for (i = 0; i < tr.length; i++) {
22+
td3 = tr[i].getElementsByTagName("td")[3];
23+
td4 = tr[i].getElementsByTagName("td")[4];
24+
if (td3 && td4) {
25+
txtValue3 = td3.textContent || td3.innerText;
26+
txtValue4 = td4.textContent || td4.innerText;
27+
if ((txtValue3.toUpperCase().indexOf(filter3) > -1 || filter3==="*") && (txtValue4.toUpperCase().indexOf(filter4) > -1 || filter4==="*" )) {
28+
tr[i].style.display = "";
29+
} else {
30+
tr[i].style.display = "none";
31+
}
32+
}
33+
}
34+
}
35+
</script>
36+
</head>
37+
<body>
38+
39+
<div class="table-wrap">
40+
<table class="sortable" id="myTable">
41+
<caption>
42+
Flux commands
43+
<span class="sr-only"> (column headers with buttons are sortable).</span>
44+
</caption>
45+
<thead>
46+
<tr>
47+
<th>
48+
<button>
49+
Name
50+
<span aria-hidden="true"></span>
51+
</button>
52+
</th>
53+
<th class="no-sort">description</th>
54+
<th class="no-sort">options</th>
55+
<th id="3">
56+
<label for="filterColumn3">Filter IN Signature :</label>
57+
<select id="3" onchange="getValue();" class="name">
58+
<option value="*">*</option>
59+
<option value="StreamReceiver">StreamReceiver</option>
60+
<option value="String">String</option>
61+
<option value="Object">Object</option>
62+
<option value="Void">Void</option>
63+
</select>
64+
</th>
65+
<th id="4">
66+
<label for="filterColumn4">Filter OUT Signature:</label>
67+
<select id="4" onchange="getValue();" class="name">
68+
<option value="*">*</option>
69+
<option value="StreamReceiver">StreamReceiver</option>
70+
<option value="String">String</option>
71+
<option value="Object">Object</option>
72+
<option value="Void">Void</option>
73+
</select>
74+
</th>
75+
<th class="no-sort">example in Playground</th>
76+
<th class="no-sort">java class</th>
77+
</tr>
78+
</thead>
79+
<tbody>
80+
<tr>
81+
<td>add-oreaggregation</td>
82+
<td>Adds ore:Aggregation to an Europeana Data Model stream. The aggregation id is set by emitting literal('aggregation_id', id)</td>
83+
<td>-</td>
84+
<td>StreamReceiver</td>
85+
<td>StreamReceiver</td>
86+
<td>-</td>
87+
<td><a href="https://github.com/metafacture/metafacture-core/blob/master/metafacture-linkeddata/src/main/java/org/metafacture/linkeddata/OreAggregationAdder.java">org.metafacture.linkeddata.OreAggregationAdder</a></td>
88+
</tr>
89+
<tr>
90+
<td>add-preamble-epilogue</td>
91+
<td>Adds a String preamle and/or epilogue to the stream</td>
92+
<td>preamble (String), epilogue (String)</td>
93+
<td>String</td>
94+
<td>String</td>
95+
<td><a href="https://github.com/metafacture/metafacture-core/blob/master/metafacture-formatting/src/main/java/org/metafacture/formatting/PreambleEpilogueAdder.java">example in Playground</a></td>
96+
<td><a href="">org.metafacture.formatting.PreambleEpilogueAdder</a></td>
97+
</tr>
98+
<tr>
99+
<td>badd-preamble-epilogue</td>
100+
<td>bAdds a String preamle and/or epilogue to the stream</td>
101+
<td>preamble (String), epilogue (String)</td>
102+
<td>String</td>
103+
<td>StreamReceiver</td>
104+
<td><a href="https://github.com/metafacture/metafacture-core/blob/master/metafacture-formatting/src/main/java/org/metafacture/formatting/PreambleEpilogueAdder.java">example in Playground</a></td>
105+
<td><a href="">org.metafacture.formatting.PreambleEpilogueAdder</a></td>
106+
</tr>
107+
108+
<tr>
109+
<td>badd-preamble-epilogue</td>
110+
<td>bAdds a String preamle and/or epilogue to the stream</td>
111+
<td>preamble (String), epilogue (String)</td>
112+
<td>StreamReceiver</td>
113+
<td>String</td>
114+
<td><a href="https://github.com/metafacture/metafacture-core/blob/master/metafacture-formatting/src/main/java/org/metafacture/formatting/PreambleEpilogueAdder.java">example in Playground</a></td>
115+
<td><a href="">org.metafacture.formatting.PreambleEpilogueAdder</a></td>
116+
</tr>
117+
</tbody>
118+
</table>
119+
</div>
120+
</body>
121+
</html>
122+

0 commit comments

Comments
 (0)