Added filter bar to mobile web app.

This commit is contained in:
Ylian Saint-Hilaire 2020-05-22 17:59:42 -07:00
parent 4fac0d2bc3
commit 6fe4bb9756
5 changed files with 369 additions and 258 deletions

Binary file not shown.

Binary file not shown.

View File

@ -22,8 +22,8 @@
},
"_letsencrypt": {
"__comment__": "Requires NodeJS 8.x or better, Go to https://letsdebug.net/ first before trying Let's Encrypt.",
"email": "myemail@myserver.com",
"names": "myserver.com,customer1.myserver.com",
"email": "myemail@mydomain.com",
"names": "myserver.mydomain.com",
"production": false
}
}

File diff suppressed because it is too large Load Diff

View File

@ -270,8 +270,16 @@
<div id=p1message style=text-align:center;width:100%></div>
</div>
</div>
<div id=p2 style=display:none>
<div id=xdevices></div>
<div id=p2 style="display:none;position:absolute;top:0;left:0;right:0;bottom:0">
<div id=xdevices style="position:absolute;overflow-y:auto;top:0;left:0;right:0;bottom:30px"></div>
<div id=xdevicesBar style="position:absolute;overflow-y:auto;height:30px;left:0;right:0;bottom:0px;background-color:#aaa">
<div style="margin:4px">
<span style="width:20px;display:inline-block;text-align:center;cursor:pointer" onclick=clearSearchInput()><b>X</b></span>
<input id=SearchInput type=text placeholder=Filter onchange=onDeviceSearchChanged(event) onkeyup=onDeviceSearchChanged(event) autocomplete=off />&nbsp;
<label class=noselect><input type=checkbox id=RealNameCheckBox onclick=onRealNameCheckBox() />OS Name</label>
<label class=noselect><input type=checkbox id=OnlineCheckBox onclick=onOnlineCheckBox(event) />Online</label>
</div>
</div>
</div>
<div id=p3 style=display:none;position:absolute;bottom:0;top:0;width:100%>
<table cellspacing=0 style="margin:0;padding:0;border-spacing:0;border:0;">
@ -1787,6 +1795,83 @@
// MY DEVICES
//
function onRealNameCheckBox() {
showRealNames = Q('RealNameCheckBox').checked;
putstore('showRealNames', showRealNames ? 1 : 0);
updateDevices();
}
function onOnlineCheckBox(e) {
putstore('onlineOnly', Q('OnlineCheckBox').checked ? 1 : 0);
onSearchInputChanged();
}
function onDeviceSearchChanged(e) {
onSearchInputChanged();
}
function clearSearchInput() {
Q('SearchInput').value = '';
onSearchInputChanged();
}
function onSearchInputChanged() {
var x = Q('SearchInput').value.toLowerCase().trim(); putstore('_search', Q('SearchInput').value);
var userSearch = null, ipSearch = null, groupSearch = null, tagSearch = null;
if (x.startsWith("user:".toLowerCase())) { userSearch = x.substring("user:".length); }
else if (x.startsWith("u:".toLowerCase())) { userSearch = x.substring("u:".length); }
else if (x.startsWith("ip:".toLowerCase())) { ipSearch = x.substring("ip:".length); }
else if (x.startsWith("group:".toLowerCase())) { groupSearch = x.substring("group:".length); }
else if (x.startsWith("g:".toLowerCase())) { groupSearch = x.substring("g:".length); }
else if (x.startsWith("tag:".toLowerCase())) { tagSearch = Q('SearchInput').value.trim().substring("tag:".length); }
else if (x.startsWith("t:".toLowerCase())) { tagSearch = Q('SearchInput').value.trim().substring("t:".length); }
if (x == '') {
// No search
for (var d in nodes) { nodes[d].v = true; }
} else if (ipSearch != null) {
// IP address search
for (var d in nodes) { nodes[d].v = ((nodes[d].ip != null) && (nodes[d].ip.indexOf(ipSearch) >= 0)); }
} else if (groupSearch != null) {
// Group filter
for (var d in nodes) { nodes[d].v = (meshes[nodes[d].meshid].name.toLowerCase().indexOf(groupSearch) >= 0); }
} else if (tagSearch != null) {
// Tag filter
for (var d in nodes) {
nodes[d].v = ((nodes[d].tags == null) && (tagSearch == '')) || ((nodes[d].tags != null) && (nodes[d].tags.indexOf(tagSearch) >= 0));
}
} else if (userSearch != null) {
// User search
for (var d in nodes) {
nodes[d].v = false;
if (nodes[d].users && nodes[d].users.length > 0) { for (var i in nodes[d].users) { if (nodes[d].users[i].toLowerCase().indexOf(userSearch) >= 0) { nodes[d].v = true; } } }
}
} else {
// Device name search
try {
var rs = x.split(/\s+/).join('|'), rx = new RegExp(rs); // In some cases (like +), this can throw an exception.
for (var d in nodes) {
nodes[d].v = (rx.test(nodes[d].name.toLowerCase())) || (nodes[d].rnamel != null && rx.test(nodes[d].rnamel.toLowerCase()));
if ((nodes[d].v == false) && nodes[d].tags) {
for (var s in nodes[d].tags) {
if (rx.test(nodes[d].tags[s].toLowerCase())) {
nodes[d].v = true;
break;
} else {
nodes[d].v = false;
}
}
}
}
} catch (ex) { for (var d in nodes) { nodes[d].v = true; } }
}
// Check power state
var onlineOnly = Q('OnlineCheckBox').checked;
if (onlineOnly) { for (var d in nodes) { if ((nodes[d].conn == null) || (nodes[d].conn == 0)) { nodes[d].v = false; } } }
updateDevices();
}
function ondeskkeypress(e) {
toggleSoftKeys(0);
Q('DeskSoftInput').value = '';
@ -1948,8 +2033,15 @@
if (typeof deviceHeaderCount[nodes[i].state] == 'undefined') { deviceHeaderCount[nodes[i].state] = 1; } else { deviceHeaderCount[nodes[i].state]++; }
}
// If there is nothing to display, explain the problem
var viewNothing = false;
if ((r == '') && (nodes.length > 0) && (Q('SearchInput').value != '')) {
viewNothing = true;
r = '<div style="margin:30px">' + "No devices matching this search." + '</div>';
}
// Display all empty device groups, we need to do this because users can add devices to these at any time.
if (sort == 0) {
if ((sort == 0) && (Q('SearchInput').value == '')) {
for (var i in meshes) {
var mesh = meshes[i];
if ((displayedMeshes[mesh._id] == null) && (IsMeshViewable(mesh))) {
@ -2395,7 +2487,7 @@
function p10showDeleteNodeDialog(nodeid) {
if (xxdialogMode) return;
setDialogMode(2, "Delete Node", 3, p10showDeleteNodeDialogEx, format("Delete {0}?", EscapeHtml(currentNode.name)) + '<br /><br /><input id=p10check type=checkbox onchange=p10validateDeleteNodeDialog() />' + "Confirm", nodeid);
setDialogMode(2, "Delete Node", 3, p10showDeleteNodeDialogEx, format("Delete {0}?", EscapeHtml(currentNode.name)) + '<br /><br /><label><input id=p10check type=checkbox onchange=p10validateDeleteNodeDialog() />' + "Confirm" + '</label>', nodeid);
p10validateDeleteNodeDialog();
}