Added URL switching support to mobile app.

Ylian Saint-Hilaire committed Feb 17, 2021 at 11:32 UTC 235bdd911db74a06ec977918ac7b949388a03e92
1 file changed +90 -30
views/default-mobile.handlebars
+90 -30
@@ -1135,10 +1135,21 @@
1135 for (var i in webState) { localStorage.setItem(i, webState[i]); }
1136 if (webState && !webState.loctag) { delete localStorage.removeItem('loctag'); }
1137
1138 + // Fetch URL arguments & do sanitation
1139 var urlargs = parseUriArgs();
1140 + if (urlargs.key != null) { urlargs.key = "" + urlargs.key; }
1141 if (urlargs.key && (isAlphaNumeric(urlargs.key) == false)) { delete urlargs.key; }
1142 if (urlargs.locale && (isAlphaNumeric(urlargs.locale) == false)) { delete urlargs.locale; }
1141 - var args = urlargs;
1143 + delete urlargs.viewmode;
1144 + delete urlargs.gotonode;
1145 + delete urlargs.gotomesh;
1146 + delete urlargs.panel;
1147 +
1148 + // Check if we are in debug mode
1149 + var args = parseUriArgs();
1150 + if (args.key && (isAlphaNumeric(args.key) == false)) { delete args.key; }
1151 + if (args.locale && (isAlphaNumeric(args.locale) == false)) { delete args.locale; }
1152 +
1153 var debugLevel = parseInt('{{{debuglevel}}}');
1154 var features = parseInt('{{{features}}}');
1155 var features2 = parseInt('{{{features2}}}');
@@ -1259,7 +1270,6 @@
1270 meshserver.send({ action: 'meshes' });
1271 meshserver.send({ action: 'nodes' });
1272 meshserver.send({ action: 'files' });
1262 - if (xxcurrentView < 2) { go(2); }
1273 authCookieRenewTimer = setInterval(function () { meshserver.send({ action: 'authcookie' }); }, 1800000); // Request a cookie refresh every 30 minutes.
1274 }
1275 QV('topMenuIcon', state == 2);
@@ -1353,7 +1363,7 @@
1363 for (var m in message.meshes) { meshes[message.meshes[m]._id] = message.meshes[m]; }
1364 if (currentMesh != null) { currentMesh = meshes[currentMesh._id]; }
1365 updateMeshes();
1356 - updateDevices();
1366 + mainUpdate(4);
1367 break;
1368 }
1369 case 'usergroups': {
@@ -1400,7 +1410,7 @@
1410
1411 //onSortSelectChange();
1412 //onSearchInputChanged();
1403 - updateDevices();
1413 + mainUpdate(4);
1414 //refreshMap(false, true);
1415 if (xxcurrentView == 0) { if ('{{viewmode}}' != '') { go(parseInt('{{viewmode}}')); } else { setDialogMode(0); go(2); } }
1416 if ('{{currentNode}}' != '') { gotoDevice('{{currentNode}}', parseInt('{{viewmode}}')); }
@@ -1564,10 +1574,9 @@
1574 // Update the web page
1575 if ((webstate.loctag != null) && (webstate.loctag != oldLoctag)) {
1576 if (webstate.loctag != null) { args.locale = webstate.loctag; } else { delete args.locale; }
1567 - updateDevices();
1568 - updateMeshes();
1577 + mainUpdate(4 + 128);
1578 } else if (webstate.stars != null) {
1570 - updateDevices();
1579 + mainUpdate(4);
1580 if (Q('SearchInput').value == '*') { onSearchInputChanged(); }
1581 }
1582 if (currentNode) { refreshDevice(currentNode._id); }
@@ -1633,8 +1642,7 @@
1642 // A new mesh was created
1643 if ((meshes[message.event.meshid] == null) && ((userinfo.manageAllDeviceGroups) || (message.event.links[userinfo._id] != null))) { // Check if this is a mesh create for a mesh we own. If site administrator, we get all messages so need to ignore some.
1644 meshes[message.event.meshid] = { _id: message.event.meshid, name: message.event.name, mtype: message.event.mtype, desc: message.event.desc, links: message.event.links };
1636 - updateMeshes();
1637 - updateDevices();
1645 + mainUpdate(4 + 128);
1646 meshserver.send({ action: 'files' });
1647 }
1648 break;
@@ -1676,8 +1684,7 @@
1684 if (xxcurrentView >= 10 && xxcurrentView < 20 && currentNode && !IsNodeViewable(currentNode)) { setDialogMode(0); go(2); currentNode = null; }
1685 }
1686 }
1679 - updateMeshes();
1680 - updateDevices();
1687 + mainUpdate(4 + 128);
1688 meshserver.send({ action: 'files' });
1689
1690 // If we are looking at a mesh that is now deleted, move back to "My Account"
@@ -1696,7 +1703,7 @@
1703 var newnodes = [];
1704 for (var i in nodes) { if (nodes[i].meshid != message.event.meshid) { newnodes.push(nodes[i]); } }
1705 nodes = newnodes;
1699 - updateDevices();
1706 + mainUpdate(4);
1707
1708 // If we are looking at a mesh that is now deleted, move back to "My Account"
1709 if (xxcurrentView >= 20 && xxcurrentView < 30 && currentMesh._id == message.event.meshid) { setDialogMode(0); go(2); }
@@ -1718,7 +1725,7 @@
1725 nodes.push(node);
1726 //onSortSelectChange();
1727 //onSearchInputChanged();
1721 - updateDevices();
1728 + mainUpdate(4);
1729 //updateMapMarkers();
1730 break;
1731 }
@@ -1733,7 +1740,7 @@
1740 // TODO: Correctly disconnect from this node (Desktop/Terminal/Files...)
1741 }
1742 nodes.splice(index, 1);
1736 - updateDevices();
1743 + mainUpdate(4);
1744 //updateMapMarkers();
1745 }
1746 break;
@@ -1788,7 +1795,7 @@
1795 //drawNotifications();
1796 refreshDevice(node._id);
1797 //updateMapMarkers();
1791 - updateDevices();
1798 + mainUpdate(4);
1799 if (currentNode == node) { updateDeviceDetails(); }
1800
1801 //if ((currentNode == node) && (xxdialogMode != null) && (xxdialogTag == '@xxmap')) { p10showNodeLocationDialog(); }
@@ -1811,7 +1818,7 @@
1818 node.meshid = message.event.newMeshId;
1819 node.meshnamel = meshes[message.event.newMeshId]?meshes[message.event.newMeshId].name.toLowerCase():'*';
1820 }
1814 - updateDevices();
1821 + mainUpdate(4);
1822 refreshDevice(message.event.nodeid);
1823 } else {
1824 // This is a new device, add it.
@@ -1828,7 +1835,7 @@
1835
1836 // Web page update
1837 //mainUpdate(1 | 2 | 4 | 16);
1831 - updateDevices();
1838 + mainUpdate(4);
1839 }
1840 break;
1841 }
@@ -1846,7 +1853,7 @@
1853 // Clear sesssion information if needed
1854 if ((node.conn & 1) == 0) { delete node.sessions; }
1855
1849 - updateDevices();
1856 + mainUpdate(4);
1857 refreshDevice(node._id);
1858 //updateMapMarkers();
1859 }
@@ -1885,10 +1892,8 @@
1892 if (Object.keys(node.sessions).length == 0) { delete node.sessions; }
1893 }
1894
1888 - updateDevices();
1895 refreshDevice(message.event.nodeid);
1890 -
1891 - //mainUpdate(4);
1896 + mainUpdate(4);
1897 //if ((currentNode != null) && (currentNode._id == message.event.nodeid)) { gotoDevice(currentNode._id, xxcurrentView, true); }
1898
1899 // If we are looking at the sessions dialog box for this device now, update it
@@ -1914,6 +1919,50 @@
1919 }
1920 }
1921
1922 + // To boost the speed of the web page when even floods occur, this method perform a delayed update on the web page.
1923 + var updateNaggleTimer = null;
1924 + var updateNaggleFlags = 0;
1925 + function mainUpdate(flags) {
1926 + updateNaggleFlags |= flags;
1927 + if (updateNaggleTimer == null) {
1928 + updateNaggleTimer = setTimeout(function () {
1929 + if (updateNaggleFlags & 4) { updateDevices(); updateDeviceDetails(); }
1930 + if (updateNaggleFlags & 128) { updateMeshes(); }
1931 + updateNaggleTimer = null;
1932 + updateNaggleFlags = 0;
1933 + gotoStartViewPage();
1934 + }, 150);
1935 + }
1936 + }
1937 +
1938 + // Go to the correct starting view page
1939 + function gotoStartViewPage() {
1940 + var xviewmode = parseInt('{{viewmode}}');
1941 + if (xxcurrentView > 1) return;
1942 + if ('{{currentNode}}'.toLowerCase() != '') { // The .toLowerCase here is the minifier will not optimize this out.
1943 + if (getNodeFromId('{{currentNode}}') == null) return; // This node is not loaded yet
1944 + gotoDevice('{{currentNode}}', xviewmode);
1945 + } else if (args.gotonode != null) {
1946 + if (args.gotonode.length == 96) { args.gotonode = btoa(hex2rstr(args.gotonode)).split('+').join('@').split('/').join('$'); } // This is a HEX encoded NodeID, convert it to Base64
1947 + if (getNodeFromId('node/' + domain + '/' + args.gotonode) == null) return; // This node is not loaded yet
1948 + if (args.panel) { currentDevicePanel = parseInt(args.panel); }
1949 + gotoDevice('node/' + domain + '/' + args.gotonode, xviewmode);
1950 + } else if (args.gotomesh != null) {
1951 + if (meshes['mesh/' + domain + '/' + args.gotomesh] == null) return; // This device group is not loaded yet
1952 + gotoMesh('mesh/' + domain + '/' + args.gotomesh);
1953 + go(xviewmode);
1954 + } else if (!isNaN(xviewmode)) {
1955 + go(xviewmode);
1956 + } else {
1957 + setDialogMode(0);
1958 + go(1);
1959 + }
1960 + delete args.gotonode;
1961 + delete args.gotomesh;
1962 + delete args.panel;
1963 + if (xxcurrentView < 2) { go(2); }
1964 + }
1965 +
1966 //
1967 // Menu System
1968 //
@@ -2448,7 +2497,7 @@
2497 function onRealNameCheckBox() {
2498 showRealNames = Q('RealNameCheckBox').checked;
2499 putstore('showRealNames', showRealNames ? 1 : 0);
2451 - updateDevices();
2500 + mainUpdate(4);
2501 }
2502
2503 function onOnlineCheckBox(e) {
@@ -2523,7 +2572,7 @@
2572 // Check power state
2573 var onlineOnly = Q('OnlineCheckBox').checked;
2574 if (onlineOnly) { for (var d in nodes) { if ((nodes[d].conn == null) || (nodes[d].conn == 0)) { nodes[d].v = false; } } }
2526 - updateDevices();
2575 + mainUpdate(4);
2576 }
2577
2578 var gotKeyPressEvent = false;
@@ -2585,10 +2634,6 @@
2634 }
2635 }
2636
2588 - // Since the update device call can be quite frequent, we can moderate it and only call it at most 5 times a second.
2589 - var updateDevicesTimer = null;
2590 - function updateDevices() { if (updateDevicesTimer != null) return; updateDevicesTimer = setTimeout(updateDevicesEx, 200); }
2591 -
2637 var sort = 0;
2638 var deviceHeaderId = 0;
2639 var deviceHeaderCount;
@@ -2597,8 +2642,7 @@
2642 var deviceHeaderTotal = 0;
2643 var deviceHeaders = {};
2644 var deviceHeadersTitles = {};
2600 - function updateDevicesEx() {
2601 - if (updateDevicesTimer != null) { clearTimeout(updateDevicesTimer); updateDevicesTimer = null; }
2645 + function updateDevices() {
2646 var r = '', c = 0, current = null, count = 0, displayedMeshes = {}, groups = {}, groupCount = {};
2647
2648 // 3 wide, list view or desktop view
@@ -2895,7 +2939,7 @@
2939 function onSortSelectChange(skipsave) {
2940 sort = document.getElementById('sortselect').selectedIndex;
2941 if (!skipsave) { putstore('sort', sort); }
2898 - updateDevicesEx();
2942 + mainUpdate(4);
2943 }
2944
2945 function deviceHeaderSet() {
@@ -3216,6 +3260,7 @@
3260 if ((currentDevicePanel != 3) && (currentNode != null)) { menus.push({ n: "Details", f: 'setupDeviceMenu(3)' }); }
3261 if ((currentDevicePanel != 4) && (currentNode != null) && (meshrights & 0x00000010)) { menus.push({ n: "Console", f: 'setupDeviceMenu(4)' }); }
3262 updateFooterMenu(menus);
3263 + updateCurrentUrl();
3264 }
3265
3266 function deviceActionFunction() {
@@ -5427,6 +5472,21 @@
5472 // Edit this line when adding a new screen
5473 for (var i = 0; i < 32; i++) { QV('p' + i, i == x); }
5474 xxcurrentView = x;
5475 + updateCurrentUrl();
5476 + }
5477 +
5478 + // Change the URL
5479 + function updateCurrentUrl() {
5480 + if (((features & 0x10000000) == 0) && (xxcurrentView > 0)) {
5481 + var urlviewmode = '';
5482 + if ((xxcurrentView >= 10) && (xxcurrentView <= 19)) { // Device Link
5483 + if (currentNode != null) { urlviewmode = '?viewmode=' + xxcurrentView + '&gotonode=' + currentNode._id.split('/')[2] + ((currentDevicePanel > 0)?('&panel=' + currentDevicePanel):''); }
5484 + } else if ((xxcurrentView >= 20) && (xxcurrentView <= 29)) { // Device Group Link
5485 + if (currentMesh != null) { urlviewmode = '?viewmode=' + xxcurrentView + '&gotomesh=' + currentMesh._id.split('/')[2]; }
5486 + } else if (xxcurrentView > 1) { urlviewmode = '?viewmode=' + xxcurrentView; }
5487 + for (var i in urlargs) { urlviewmode += (((urlviewmode == '') ? '?' : '&') + i + '=' + urlargs[i]); }
5488 + try { window.history.replaceState({}, document.title, window.location.pathname + urlviewmode); } catch (ex) { }
5489 + }
5490 }
5491
5492 //