Skip to content

Commit dcd4409

Browse files
authored
Merge pull request #87 from sheldor1510/sortable-filterable-tables
Made admin panel tables sortable and filterable
2 parents dbe4bb4 + 58af24c commit dcd4409

File tree

7 files changed

+195
-12
lines changed

7 files changed

+195
-12
lines changed

resources/templates/footer.php

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,8 @@
2525

2626
</body>
2727

28+
<script src="<?php echo $CONFIG["site"]["prefix"]; ?>/js/filter.js"></script>
29+
<script src="<?php echo $CONFIG["site"]["prefix"]; ?>/js/sort.js"></script>
2830
<script src="<?php echo $CONFIG["site"]["prefix"]; ?>/js/global.js"></script>
2931
<script src="<?php echo $CONFIG["site"]["prefix"]; ?>/js/tables.js"></script>
3032

resources/templates/header.php

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@
3232
<link rel="stylesheet" type="text/css" href="<?php echo $CONFIG["site"]["prefix"]; ?>/css/navbar.css">
3333
<link rel="stylesheet" type="text/css" href="<?php echo $CONFIG["site"]["prefix"]; ?>/css/modal.css">
3434
<link rel="stylesheet" type="text/css" href="<?php echo $CONFIG["site"]["prefix"]; ?>/css/tables.css">
35+
<link rel="stylesheet" type="text/css" href="<?php echo $CONFIG["site"]["prefix"]; ?>/css/filters.css">
3536

3637
<meta name="viewport" content="width=device-width, initial-scale=1.0">
3738
<meta name="description" content="<?php echo $CONFIG["site"]["description"] ?>">

webroot/admin/pi-mgmt.php

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,7 @@
6262
<h1>PI Management</h1>
6363
<hr>
6464

65-
<input type="text" id="tableSearch" placeholder="Search...">
65+
<!-- <input type="text" id="tableSearch" placeholder="Search..."> -->
6666

6767
<h5>Pending PI Requests</h5>
6868
<table class="searchable">
@@ -104,11 +104,12 @@
104104

105105
<h5>List of PIs</h5>
106106

107-
<table class="searchable longTable">
107+
<table class="searchable longTable sortable filterable">
108108
<tr class="key">
109-
<td>Name</td>
110-
<td>Unity ID</td>
111-
<td>Mail</td>
109+
<input type="text" style="margin-right:5px;" placeholder="Filter by..." id="common-filter" class="filterSearch">
110+
<td id="name"><span class="filter">⫧ </span>Name</td>
111+
<td id="unityID"><span class="filter">⫧ </span>Unity ID</td>
112+
<td id="mail"><span class="filter">⫧ </span>Mail</td>
112113
<td>Actions</td>
113114
</tr>
114115

webroot/admin/user-mgmt.php

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -23,15 +23,16 @@
2323
<h1>User Management</h1>
2424
<hr>
2525

26-
<input type="text" id="tableSearch" placeholder="Search...">
26+
<!-- <input type="text" id="tableSearch" placeholder="Search..."> -->
2727

28-
<table class="searchable longTable">
28+
<table class="searchable longTable sortable filterable">
2929
<tr class="key">
30-
<td>Name</td>
31-
<td>UID</td>
32-
<td>Org</td>
33-
<td>Mail</td>
34-
<td>Groups</td>
30+
<input type="text" style="margin-right:5px;" placeholder="Filter by..." id="common-filter" class="filterSearch">
31+
<td id="name"><span class="filter">⫧ </span>Name</td>
32+
<td id="uid"><span class="filter">⫧ </span>UID</td>
33+
<td id="org"><span class="filter">⫧ </span>Org</td>
34+
<td id="mail"><span class="filter">⫧ </span>Mail</td>
35+
<td id="groups"><span class="filter">⫧ </span>Groups</td>
3536
<td>Actions</td>
3637
</tr>
3738

webroot/css/filters.css

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
.filterSearch {
2+
max-width: fit-content !important;
3+
}
4+
5+
#uid-filter, #org-filter, #mail-filter, #groups-filter {
6+
margin-right: 5px;
7+
}
8+
9+
#name-filter, #unityID-filter {
10+
margin-right: 100px;
11+
}
12+
13+
.key td:hover {
14+
cursor: pointer;
15+
}

webroot/js/filter.js

Lines changed: 90 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,90 @@
1+
function getQueryVariable(variable) {
2+
var query = window.location.search.substring(1);
3+
var vars = query.split("&");
4+
for (var i = 0; i < vars.length; i++) {
5+
var pair = vars[i].split("=");
6+
7+
if (pair[0] == variable) {
8+
return pair[1];
9+
}
10+
}
11+
return false;
12+
}
13+
14+
function updateQueryStringParameter(uri, key, value) {
15+
let currentURL = new URL(window.location.href);
16+
let params = currentURL.searchParams;
17+
if (params.has(key)) {
18+
params.delete(key);
19+
}
20+
params.append(key, value);
21+
window.history.pushState("object or string", "Title", currentURL.href);
22+
}
23+
24+
function updateFilterInput() {
25+
const commonFilterInputBox = document.querySelector(".filterSearch");
26+
commonFilterInputBox.style.display = "none";
27+
commonFilterInputBox.style.visibility = "hidden";
28+
commonFilterInputBox.value = "";
29+
30+
var filter = getQueryVariable("filter");
31+
if (filter) {
32+
commonFilterInputBox.style.display = "inline-block";
33+
commonFilterInputBox.style.visibility = "visible";
34+
35+
if (filter == "uid") {
36+
commonFilterInputBox.placeholder = "Filter by " + filter.toUpperCase() + '...';
37+
} else {
38+
commonFilterInputBox.placeholder = "Filter by " + filter.charAt(0).toUpperCase() + filter.slice(1) + '...';
39+
}
40+
41+
if (getQueryVariable("value") != false) {
42+
commonFilterInputBox.value = getQueryVariable("value");
43+
filterRows();
44+
}
45+
46+
commonFilterInputBox.addEventListener("keyup", function(e) {
47+
updateQueryStringParameter(window.location.href, "value", e.target.value);
48+
filterRows();
49+
});
50+
}
51+
}
52+
53+
updateFilterInput();
54+
55+
var filters = document.querySelectorAll("span.filter");
56+
filters.forEach(function(filter) {
57+
filter.addEventListener("click", function(e) {
58+
e.preventDefault();
59+
e.stopPropagation();
60+
if (e.target.parentElement.id != getQueryVariable("filter")) {
61+
updateQueryStringParameter(window.location.href, "filter", e.target.parentElement.id);
62+
updateQueryStringParameter(window.location.href, "value", "");
63+
filterRows();
64+
} else {
65+
updateQueryStringParameter(window.location.href, "filter", "");
66+
updateQueryStringParameter(window.location.href, "value", "");
67+
filterRows();
68+
}
69+
updateFilterInput();
70+
});
71+
});
72+
73+
function filterRows() {
74+
var filter = getQueryVariable("filter");
75+
var filterValue = getQueryVariable("value");
76+
77+
if (filter) {
78+
var table = document.querySelector("table.filterable");
79+
var rows = Array.from(table.querySelectorAll("tr:nth-child(n+2)"));
80+
var column = table.querySelector("tr.key").querySelector("td#" + filter).cellIndex;
81+
rows.forEach(function(row) {
82+
if (row.cells[column].textContent.trim().toLowerCase().indexOf(filterValue.toLowerCase()) == -1) {
83+
row.style.display = "none";
84+
} else {
85+
row.style.display = "";
86+
}
87+
}
88+
);
89+
}
90+
}

webroot/js/sort.js

Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
var table = document.querySelector("table.sortable");
2+
table.querySelectorAll("td").forEach(function(td) {
3+
td.addEventListener("click", function(e) {
4+
if (td.parentElement.classList.contains("key") && td.innerHTML != "Actions") {
5+
if (e.target.classList.contains("filter")) {
6+
updateQueryStringParameter(window.location.href, "filter", e.target.parentElement.id);
7+
updateFilterInput();
8+
} else {
9+
var column = td.cellIndex;
10+
var rows = Array.from(table.querySelectorAll("tr:nth-child(n+2)"));
11+
var order = td.classList.toggle("asc") ? 1 : -1;
12+
rows.sort(function(a, b) {
13+
return order * (a.cells[column].textContent.trim().localeCompare(b.cells[column].textContent.trim(), undefined, {
14+
numeric: true
15+
}));
16+
});
17+
rows.forEach(function(row) {
18+
table.appendChild(row);
19+
});
20+
var keys = document.querySelectorAll("tr.key");
21+
keys.forEach(function(key) {
22+
key.querySelectorAll("td").forEach(function(td) {
23+
td.innerHTML = td.innerHTML.replace(/ | /, "");
24+
});
25+
});
26+
var orderSymbol = order == 1 ? "&#x25B2;" : "&#x25BC;";
27+
td.innerHTML = td.innerHTML + " " + orderSymbol;
28+
updateQueryStringParameter(window.location.href, "sort", td.id);
29+
updateQueryStringParameter(window.location.href, "order", order == 1 ? "asc" : "desc");
30+
}
31+
}
32+
});
33+
});
34+
35+
function getQueryVariable(variable) {
36+
var query = window.location.search.substring(1);
37+
var vars = query.split("&");
38+
for (var i = 0; i < vars.length; i++) {
39+
var pair = vars[i].split("=");
40+
41+
if (pair[0] == variable) {
42+
return pair[1];
43+
}
44+
}
45+
return false;
46+
}
47+
48+
function updateQueryStringParameter(uri, key, value) {
49+
let currentURL = new URL(window.location.href);
50+
let params = currentURL.searchParams;
51+
if (params.has(key)) {
52+
params.delete(key);
53+
}
54+
params.append(key, value);
55+
window.history.pushState("object or string", "Title", currentURL.href);
56+
}
57+
58+
window.onload = function() {
59+
var sort = getQueryVariable("sort");
60+
var order = getQueryVariable("order");
61+
if (sort) {
62+
var sortElement = document.getElementById(sort);
63+
if (sortElement) {
64+
if (order == "asc") {
65+
sortElement.click();
66+
} else if (order == "desc") {
67+
sortElement.click();
68+
sortElement.click();
69+
}
70+
}
71+
}
72+
filterRows();
73+
}

0 commit comments

Comments
 (0)