@@ -234,6 +241,7 @@ Digi Demo - Multimedia
+
diff --git a/connectcore-demo-example/network.html b/connectcore-demo-example/network.html
new file mode 100644
index 0000000..231e82f
--- /dev/null
+++ b/connectcore-demo-example/network.html
@@ -0,0 +1,508 @@
+
+
+
+
+Digi Demo - Network
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+

+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
Configure ethernet parameters.
+
+ MAC Address:
+
+
+
+ Connected:
+
+
+
+ IP mode:
+
+
+
+
+
+
+
+
+
+
+
+
+
+
Configure ethernet 1 parameters.
+
+ MAC Address:
+
+
+
+ Connected:
+
+
+
+ IP mode:
+
+
+
+
+
+
+
+
+
+
+
+
+
+
Configure wifi parameters.
+
+ MAC Address:
+
+
+
+ Connected:
+
+
+
+
+ Encryption type:
+
+
+
+
+ IP mode:
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/connectcore-demo-example/static/css/general.css b/connectcore-demo-example/static/css/general.css
index 04c351e..cb27134 100644
--- a/connectcore-demo-example/static/css/general.css
+++ b/connectcore-demo-example/static/css/general.css
@@ -373,7 +373,7 @@ body {
/* POPUP */
.popup {
z-index: 999;
- position: absolute;
+ position: fixed;
transform: translate(-50%, -50%);
background-color: white;
padding: 20px 10px;
@@ -1895,6 +1895,11 @@ body {
width: 170px;
}
+.param-value {
+ display: inline-block;
+ position: relative;
+}
+
.input-control {
position: relative;
-webkit-transition: none !important;
@@ -1905,12 +1910,99 @@ body {
width: 80px !important;
padding: 0px !important;
margin: 0px !important;
+ text-align: left !important;
+ padding-left: 5px !important;
+}
+
+.input-control-wide {
+ width: 180px !important;
}
.input-control-error {
background-color: #f3b1b1 !important;
}
+.input-control-disabled {
+ background-color: transparent !important;
+ border: none !important;
+ pointer-events: none !important;
+ color: #939393 !important;
+}
+
+.select-control {
+ position: relative;
+ -webkit-transition: none !important;
+ -moz-transition: none !important;
+ -ms-transition: none !important;
+ -o-transition: none !important;
+ transition: none !important;
+ width: 80px !important;
+ padding: 0px !important;
+ margin: 0px !important;
+ text-align-last: left !important;
+ padding-left: 5px !important;
+}
+
+.switch-control {
+ position: relative;
+ display: inline-block;
+ width: 48px;
+ height: 22px;
+ margin-bottom: 0px;
+}
+
+.switch-control input {
+ opacity: 0;
+ width: 0;
+ height: 0;
+}
+
+.slider-control {
+ position: absolute;
+ cursor: pointer;
+ top: 0;
+ left: 0;
+ right: 0;
+ bottom: 0;
+ background-color: #ccc;
+ -webkit-transition: .4s;
+ transition: .4s;
+}
+
+.slider-control:before {
+ position: absolute;
+ content: "";
+ height: 16px;
+ width: 16px;
+ left: 3px;
+ bottom: 3px;
+ background-color: white;
+ -webkit-transition: .4s;
+ transition: .4s;
+}
+
+input:checked + .slider-control {
+ background-color: #2196F3;
+}
+
+input:focus + .slider-control {
+ box-shadow: 0 0 1px #2196F3;
+}
+
+input:checked + .slider-control:before {
+ -webkit-transform: translateX(26px);
+ -ms-transform: translateX(26px);
+ transform: translateX(26px);
+}
+
+.slider-control.round {
+ border-radius: 11px;
+}
+
+.slider-control.round:before {
+ border-radius: 50%;
+}
+
.error-label {
color: red;
font-size: 12px;
@@ -1919,6 +2011,11 @@ body {
padding-left: 10px;
}
+.buttons-container {
+ with: 100%;
+ position: relative;
+}
+
.config-button {
padding: 5px;
cursor: pointer;
@@ -1935,6 +2032,43 @@ body {
background-color: #c3c3c3;
pointer-events: none;
}
+
+input[type=text], input[type=password], select {
+ background-color: #f6f6f6;
+ border: none;
+ color: #0d0d0d;
+ padding: 12px 30px;
+ text-align: center;
+ text-decoration: none;
+ display: inline-block;
+ font-size: 14px;
+ margin: 0px 0px 25px 0px;
+ width: 85%;
+ border: 2px solid #f6f6f6;
+ -webkit-transition: all 0.5s ease-in-out;
+ -moz-transition: all 0.5s ease-in-out;
+ -ms-transition: all 0.5s ease-in-out;
+ -o-transition: all 0.5s ease-in-out;
+ transition: all 0.5s ease-in-out;
+ -webkit-border-radius: 5px 5px 5px 5px;
+ border-radius: 5px 5px 5px 5px;
+}
+
+input[type=text]:focus, input[type=password]:focus, select:focus {
+ background-color: #fff;
+ border-bottom: 2px solid var(--digi-green);
+}
+
+select {
+ -moz-appearance:none; /* Firefox */
+ -webkit-appearance:none; /* Safari and Chrome */
+ appearance:none;
+ text-align-last: center;
+ background-image: url("../images/combo_arrow_gray.png");
+ background-repeat: no-repeat, repeat;
+ background-position: right .7em top 50%;
+ background-size: .65em auto;
+}
/* END CONFIG CONTROLS */
/* MANAGEMENT */
@@ -2206,3 +2340,20 @@ body {
margin-top: 5px;
}
/* END MANAGEMENT */
+
+/* NETWORK */
+.interface-header {
+ padding: 15px 20px 10px 20px;
+ align-items: center;
+ font-size: 16px;
+ font-weight: bold;
+}
+
+.interface-panel-container {
+ padding: 0px 20px 15px 20px;
+}
+
+.interface-title {
+ font-size: 1.25em;
+}
+/* END NETWORK */
diff --git a/connectcore-demo-example/static/js/common.js b/connectcore-demo-example/static/js/common.js
index 54246bc..140cf5b 100644
--- a/connectcore-demo-example/static/js/common.js
+++ b/connectcore-demo-example/static/js/common.js
@@ -42,6 +42,7 @@ const ID_CPU_TEMPERATURE = "cpu_temperature";
const ID_CPU_UPTIME = "cpu_uptime";
const ID_CURRENT_DIR = "current_dir";
const ID_DATA = "data";
+const ID_DESC = "desc";
const ID_DEVICE_NAME = "device-name";
const ID_DEVICE_TYPE = "device_type";
const ID_DEVICES = "devices";
@@ -133,9 +134,12 @@ const VALUE_SUCCESSFUL = "successful";
const VALUE_TOP = "top";
const VALUE_UNKNOWN = "unknown";
+const CLASS_ARROW_DOWN = "fa-caret-down";
+const CLASS_ARROW_UP = "fa-caret-up";
const CLASS_D_NONE = "d-none";
const CLASS_DISABLED_DIV = "disabled-div";
const CLASS_ELEMENT_GRAYED = "element-grayed";
+const CLASS_INPUT_DISABLED = "input-control-disabled";
const CLASS_INPUT_ERROR = "input-control-error";
const CLASS_CONFIG_BUTTON_DISABLED = "config-button-disabled";
const CLASS_SELECTED = "selected";
@@ -487,6 +491,11 @@ function isDashboardShowing() {
return window.location.pathname.indexOf("index") > -1;
}
+// Returns whether the network page is showing or not.
+function isNetworkShowing() {
+ return window.location.pathname.indexOf("network") > -1;
+}
+
// Returns whether the management page is showing or not.
function isManagementShowing() {
return window.location.pathname.indexOf("management") > -1;
diff --git a/connectcore-demo-example/static/js/dashboard.js b/connectcore-demo-example/static/js/dashboard.js
index ceb539a..2261599 100644
--- a/connectcore-demo-example/static/js/dashboard.js
+++ b/connectcore-demo-example/static/js/dashboard.js
@@ -92,8 +92,6 @@ const STREAM_BT_STATE = PREFIX_STREAM + IFACE_BT + "/state";
const PANEL_ARROW_WIDTH_100 = 20;
const PANEL_BOARD_WIDTH_100 = 1200;
-const CLASS_ARROW_DOWN = "fa-caret-down";
-const CLASS_ARROW_UP = "fa-caret-up";
const CLASS_LED_PANEL_AREA_ON = "led-panel-area-on";
const CLASS_PANEL_AREA_SELECTED = "panel-area-selected";
const CLASS_PANEL_AREA_ICON_SELECTED = "panel-area-icon-selected";
diff --git a/connectcore-demo-example/static/js/devices.js b/connectcore-demo-example/static/js/devices.js
index c52cc40..146bed5 100644
--- a/connectcore-demo-example/static/js/devices.js
+++ b/connectcore-demo-example/static/js/devices.js
@@ -325,6 +325,11 @@ class ConnectCoreDevice {
return this.#ethernetIP[index];
}
+ // Returns whether the device supports Wifi or not.
+ hasWifi() {
+ return this.#wifiMAC != null && this.#wifiMAC != "undefined"
+ }
+
// Returns the device WiFi MAC address.
getWifiMAC() {
return this.#wifiMAC;
diff --git a/connectcore-demo-example/static/js/network.js b/connectcore-demo-example/static/js/network.js
new file mode 100644
index 0000000..6fd2869
--- /dev/null
+++ b/connectcore-demo-example/static/js/network.js
@@ -0,0 +1,459 @@
+/*
+ * Copyright 2022, Digi International Inc.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+// Constants.
+const ELEMENT_ETHERNET = "ethernet";
+const ELEMENT_WIFI = "wifi";
+
+const FIELD_DEFAULT_GATEWAY = "_default_gateway";
+const FIELD_DNS1_ADDRESS = "_dns1_addr";
+const FIELD_DNS2_ADDRESS = "_dns2_addr";
+const FIELD_ENABLE = "_enable";
+const FIELD_ENCRYPTION_TYPE = "_enc_type";
+const FIELD_ERROR = "_error";
+const FIELD_MAC_ADDRESS = "_mac";
+const FIELD_IP_ADDRESS = "_ip_addr";
+const FIELD_IP_MODE = "_ip_mode";
+const FIELD_PARAM = "_param";
+const FIELD_PASSWORD = "_password";
+const FIELD_SAVE_BUTTON = "_save_button";
+const FIELD_SSID = "_ssid";
+const FIELD_SUBNET_MASK = "_subnet_mask";
+
+const ID_DNS1 = "dns1";
+const ID_DNS2 = "dns2";
+const ID_ENABLE = "enable";
+const ID_ETH0_TITLE = "eth0_title";
+const ID_GATEWAY = "gateway";
+const ID_IP = "ip";
+const ID_IP_MODE = "type";
+const ID_INTERFACE = "interface";
+const ID_MAC = "mac";
+const ID_NETMASK = "netmask";
+const ID_PANEL_CONTAINER = "_panel_container";
+const ID_PASSWORD = "psk";
+const ID_SECURITY_MODE = "sec_mode";
+const ID_SSID = "ssid";
+const ID_TOGGLE_BUTTON = "_toggle_button";
+
+const IP_MODE_DHCP = "dhcp";
+const IP_MODE_STATIC = "static";
+
+const ERROR_IP_VALUE_FORMAT = "Value must follow this format: XXX.XXX.XXX.XXX";
+const ERROR_PASSWORD_INVALID = "Password must be between 8 and 63 characters long";
+const ERROR_SSID_INVALID = "SSID value is not valid";
+const ERROR_UNKNOWN = "Unknown error saving configuration.";
+
+const MESSAGE_LOADING_CONFIGURATION = "Loading configuration...";
+const MESSAGE_SAVING_CONFIGURATION = "Saving configuration...";
+const MESSAGE_CONFIGURATION_SAVED = "Configuration saved successfully!";
+
+const PREFIX_ETHERNET = "eth";
+const PREFIX_WIFI = "wlan";
+
+const REGEX_IP = '^(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$';
+const REGEX_SSID = '^[^!#;+\\]/"\t][^+\\]/"\t]{0,31}$';
+const REGEX_PASSWORD = '^[\u0020-\u007e]{8,63}$';
+
+const ALL_ELEMENTS = "all";
+
+// Variables.
+var readingNetworkInfo = false;
+var passwordChanged = false;
+
+// Initializes the network page.
+function initializeNetworkPage() {
+ // Sanity checks.
+ if (!isNetworkShowing())
+ return;
+ // Read network configuration.
+ readElements = [ELEMENT_ETHERNET, ELEMENT_WIFI];
+ readConfiguration(readElements, ALL_ELEMENTS);
+}
+
+// Gets the device configuration the given elements.
+function readConfiguration(readElements, parseElement) {
+ // Execute only in the network page.
+ if (!isNetworkShowing() || readingNetworkInfo)
+ return;
+ // Flag reading variable.
+ readingNetworkInfo = true;
+ // Hide the info popup.
+ showInfoPopup(false);
+ // Show the loading popup.
+ showLoadingPopup(true, MESSAGE_LOADING_CONFIGURATION);
+ // Send request to retrieve configuration.
+ $.post(
+ "http://" + getServerAddress() + "/ajax/get_config",
+ JSON.stringify({
+ "elements": readElements
+ }),
+ function(data) {
+ // Process only in the network page.
+ if (!isNetworkShowing())
+ return;
+ // Process answer.
+ processReadConfigurationResponse(data, parseElement);
+ }
+ ).fail(function(response) {
+ // Flag reading variable.
+ readingNetworkInfo = false;
+ // Clear the element being read.
+ elementReading = "";
+ // Process only in the network page.
+ if (!isNetworkShowing())
+ return;
+ // Hide the loading panel.
+ showLoadingPopup(false);
+ // Process error.
+ processAjaxErrorResponse(response);
+ // Update controls.
+ updateAllControls();
+ });
+}
+
+// Processes the response of the read configuration request.
+function processReadConfigurationResponse(response, parseElement) {
+ // Check if there was any error in the request.
+ if (!checkErrorResponse(response, false)) {
+ // Fill network info.
+ fillNetworkInfo(JSON.parse(response[ID_DATA]), parseElement);
+ } else {
+ // Flag reading variable.
+ readingNetworkInfo = false;
+ // Hide the loading panel.
+ showLoadingPopup(false);
+ }
+}
+
+// Fills network information.
+function fillNetworkInfo(response, parseElement) {
+ var numEthernetIfaces = 0;
+ var numWifiIfaces = 0;
+ for (const [element, elementData] of Object.entries(response)) {
+ if (element != ELEMENT_ETHERNET && element != ELEMENT_WIFI)
+ continue;
+ for (const [iface, ifaceData] of Object.entries(elementData)) {
+ if (!iface.startsWith(PREFIX_WIFI) && !iface.startsWith(PREFIX_ETHERNET))
+ continue;
+ if (parseElement != ALL_ELEMENTS && iface != parseElement)
+ continue;
+ var enabled = ifaceData[ID_ENABLE];
+ var ipMode = ifaceData[ID_IP_MODE];
+ if (iface.startsWith(PREFIX_ETHERNET))
+ numEthernetIfaces += 1;
+ else if (iface.startsWith(PREFIX_WIFI))
+ numWifiIfaces += 1;
+ // Fill MAC.
+ document.getElementById(iface + FIELD_MAC_ADDRESS).innerText = ifaceData[ID_MAC];
+ // Set enable state.
+ document.getElementById(iface + FIELD_ENABLE).checked = enabled;
+ // Set IP mode.
+ if (ipMode == 0)
+ document.getElementById(iface + FIELD_IP_MODE).value = IP_MODE_STATIC;
+ else
+ document.getElementById(iface + FIELD_IP_MODE).value = IP_MODE_DHCP;
+ // Fill the rest of the fields.
+ document.getElementById(iface + FIELD_IP_ADDRESS).value = ifaceData[ID_IP];
+ document.getElementById(iface + FIELD_SUBNET_MASK).value = ifaceData[ID_NETMASK];
+ document.getElementById(iface + FIELD_DEFAULT_GATEWAY).value = ifaceData[ID_GATEWAY];
+ document.getElementById(iface + FIELD_DNS1_ADDRESS).value = ifaceData[ID_DNS1];
+ document.getElementById(iface + FIELD_DNS2_ADDRESS).value = ifaceData[ID_DNS2];
+ // Specific Wifi fields.
+ if (iface.startsWith(PREFIX_WIFI)) {
+ document.getElementById(iface + FIELD_SSID).value = ifaceData[ID_SSID];
+ document.getElementById(iface + FIELD_ENCRYPTION_TYPE).selectedIndex = ifaceData[ID_SECURITY_MODE];
+ if (ifaceData[ID_SECURITY_MODE] != 0)
+ document.getElementById(iface + FIELD_PASSWORD).value = "dummy_password";
+ passwordChanged = false;
+ }
+ // Update controls.
+ updateInterfaceControls(iface);
+ }
+ }
+ // Update interfaces visibility.
+ if (parseElement == ALL_ELEMENTS) {
+ if (numEthernetIfaces == 1) {
+ document.getElementById(IFACE_ETH1).style.display = "none";
+ document.getElementById(ID_ETH0_TITLE).innerHTML = "Ethernet";
+ }
+ if (numWifiIfaces == 0)
+ document.getElementById(IFACE_WIFI).style.display = "none";
+ }
+ // Flag reading variable.
+ readingNetworkInfo = false;
+ // Hide the loading panel.
+ showLoadingPopup(false);
+}
+
+// Updates all controls of the page.
+function updateAllControls() {
+ updateInterfaceControls(IFACE_ETH0);
+ updateInterfaceControls(IFACE_ETH1);
+ updateInterfaceControls(IFACE_WIFI);
+}
+
+// Updates the given interface controls based on its configuration.
+function updateInterfaceControls(iface) {
+ // Initialize variables.
+ var ipGroup = document.getElementById(iface + FIELD_IP_ADDRESS + FIELD_PARAM);
+ var ipField = document.getElementById(iface + FIELD_IP_ADDRESS);
+ var subnetGroup = document.getElementById(iface + FIELD_SUBNET_MASK + FIELD_PARAM);
+ var subnetField = document.getElementById(iface + FIELD_SUBNET_MASK);
+ var gatewayGroup = document.getElementById(iface + FIELD_DEFAULT_GATEWAY + FIELD_PARAM);
+ var gatewayField = document.getElementById(iface + FIELD_DEFAULT_GATEWAY);
+ var dns1Group = document.getElementById(iface + FIELD_DNS1_ADDRESS + FIELD_PARAM);
+ var dns1Field = document.getElementById(iface + FIELD_DNS1_ADDRESS);
+ var dns2Group = document.getElementById(iface + FIELD_DNS2_ADDRESS + FIELD_PARAM);
+ var dns2Field = document.getElementById(iface + FIELD_DNS2_ADDRESS);
+ var ipModeGroup = document.getElementById(iface + FIELD_IP_MODE + FIELD_PARAM);
+ var ipModeField = document.getElementById(iface + FIELD_IP_MODE);
+ var enableField = document.getElementById(iface + FIELD_ENABLE);
+ var enabled = enableField.checked;
+ var ipMode = ipModeField.value;
+ var ssidGroup, encryptionTypeGroup, encryptionTypeField, passwordGroup, usePassword;
+ if (iface.startsWith(PREFIX_WIFI)) {
+ ssidGroup = document.getElementById(iface + FIELD_SSID + FIELD_PARAM);
+ encryptionTypeGroup = document.getElementById(iface + FIELD_ENCRYPTION_TYPE + FIELD_PARAM);
+ encryptionTypeField = document.getElementById(iface + FIELD_ENCRYPTION_TYPE);
+ passwordGroup = document.getElementById(iface + FIELD_PASSWORD + FIELD_PARAM);
+ usePassword = encryptionTypeField.value != 0;
+ if (usePassword)
+ passwordGroup.style.display = "block";
+ else
+ passwordGroup.style.display = "none";
+ }
+ // Determine if IP fields can be edited.
+ if (ipMode == IP_MODE_DHCP) {
+ if (!ipField.classList.contains(CLASS_INPUT_DISABLED))
+ ipField.classList.add(CLASS_INPUT_DISABLED);
+ if (!subnetField.classList.contains(CLASS_INPUT_DISABLED))
+ subnetField.classList.add(CLASS_INPUT_DISABLED);
+ if (!gatewayField.classList.contains(CLASS_INPUT_DISABLED))
+ gatewayField.classList.add(CLASS_INPUT_DISABLED);
+ if (!dns1Field.classList.contains(CLASS_INPUT_DISABLED))
+ dns1Field.classList.add(CLASS_INPUT_DISABLED);
+ if (!dns2Field.classList.contains(CLASS_INPUT_DISABLED))
+ dns2Field.classList.add(CLASS_INPUT_DISABLED);
+ } else if (ipMode == IP_MODE_STATIC) {
+ if (ipField.classList.contains(CLASS_INPUT_DISABLED))
+ ipField.classList.remove(CLASS_INPUT_DISABLED);
+ if (subnetField.classList.contains(CLASS_INPUT_DISABLED))
+ subnetField.classList.remove(CLASS_INPUT_DISABLED);
+ if (gatewayField.classList.contains(CLASS_INPUT_DISABLED))
+ gatewayField.classList.remove(CLASS_INPUT_DISABLED);
+ if (dns1Field.classList.contains(CLASS_INPUT_DISABLED))
+ dns1Field.classList.remove(CLASS_INPUT_DISABLED);
+ if (dns2Field.classList.contains(CLASS_INPUT_DISABLED))
+ dns2Field.classList.remove(CLASS_INPUT_DISABLED);
+ }
+ // Validate the network interface.
+ validateInterface(iface);
+}
+
+// Validates the given network interface.
+function validateInterface(iface) {
+ // Initialize vars.
+ var valid = true;
+ var saveButton = document.getElementById(iface + FIELD_SAVE_BUTTON);
+ var enableField = document.getElementById(iface + FIELD_ENABLE);
+ var ipModeField = document.getElementById(iface + FIELD_IP_MODE);
+ var ipField = document.getElementById(iface + FIELD_IP_ADDRESS);
+ var subnetField = document.getElementById(iface + FIELD_SUBNET_MASK);
+ var gatewayField = document.getElementById(iface + FIELD_DEFAULT_GATEWAY);
+ var dns1Field = document.getElementById(iface + FIELD_DNS1_ADDRESS);
+ var dns2Field = document.getElementById(iface + FIELD_DNS2_ADDRESS);
+ var ipMode = ipModeField.value;
+ var forceValid = false;
+ // Validate fields.
+ if (ipMode == IP_MODE_DHCP)
+ forceValid = true;
+ valid &= validateIPField(iface + FIELD_IP_ADDRESS, iface + FIELD_IP_ADDRESS + FIELD_ERROR, forceValid);
+ valid &= validateIPField(iface + FIELD_SUBNET_MASK, iface + FIELD_SUBNET_MASK + FIELD_ERROR, forceValid);
+ valid &= validateIPField(iface + FIELD_DEFAULT_GATEWAY, iface + FIELD_DEFAULT_GATEWAY + FIELD_ERROR, forceValid);
+ valid &= validateIPField(iface + FIELD_DNS1_ADDRESS, iface + FIELD_DNS1_ADDRESS + FIELD_ERROR, forceValid);
+ valid &= validateIPField(iface + FIELD_DNS2_ADDRESS, iface + FIELD_DNS2_ADDRESS + FIELD_ERROR, forceValid);
+ if (iface.startsWith(PREFIX_WIFI)) {
+ valid &= validateField(iface + FIELD_SSID, iface + FIELD_SSID + FIELD_ERROR, REGEX_SSID, ERROR_SSID_INVALID, false);
+ if (parseInt(document.getElementById(iface + FIELD_ENCRYPTION_TYPE).value) != 0)
+ valid &= validateField(iface + FIELD_PASSWORD, iface + FIELD_PASSWORD + FIELD_ERROR, REGEX_PASSWORD, ERROR_PASSWORD_INVALID, false);
+ }
+ // Check errors.
+ if (!valid) {
+ if (!saveButton.classList.contains(CLASS_CONFIG_BUTTON_DISABLED))
+ saveButton.classList.add(CLASS_CONFIG_BUTTON_DISABLED);
+ } else {
+ if (saveButton.classList.contains(CLASS_CONFIG_BUTTON_DISABLED))
+ saveButton.classList.remove(CLASS_CONFIG_BUTTON_DISABLED);
+ }
+}
+
+// Validates the given IP field.
+function validateIPField(fieldID, errorID, forceValid) {
+ return validateField(fieldID, errorID, REGEX_IP, ERROR_IP_VALUE_FORMAT, forceValid);
+}
+
+// Validates the given field.
+function validateField(fieldID, errorID, regexPattern, errorMessage, forceValid) {
+ // Initialize vars.
+ var field = document.getElementById(fieldID);
+ var fieldError = document.getElementById(errorID);
+ var isValid = true;
+ var error = "";
+ // Sanity checks.
+ if (field == null || fieldError == null)
+ return false;
+ // Check if value is valid.
+ if (!forceValid) {
+ var value = field.value;
+ if (value.length == 0) {
+ isValid = false;
+ error = ERROR_FIELD_EMPTY;
+ } else if (!value.match(regexPattern)) {
+ isValid = false;
+ error = errorMessage;
+ }
+ }
+ // Update controls.
+ if (isValid) {
+ if (field.classList.contains(CLASS_INPUT_ERROR))
+ field.classList.remove(CLASS_INPUT_ERROR);
+ fieldError.innerHTML = " ";
+ fieldError.style.display = "none";
+ } else {
+ if (!field.classList.contains(CLASS_INPUT_ERROR))
+ field.classList.add(CLASS_INPUT_ERROR);
+ fieldError.innerHTML = error;
+ fieldError.style.display = "block";
+ }
+ return isValid;
+}
+
+// Retrieves the given network interface form data.
+function getInterfaceData(element, iface) {
+ // Initialize variables.
+ var data = {};
+ var ifaceData = {};
+ var networkData = {};
+ var enable = document.getElementById(iface + FIELD_ENABLE).checked;
+ var ipMode = document.getElementById(iface + FIELD_IP_MODE).value;
+ // Fill network data.
+ networkData[ID_ENABLE] = enable;
+ if (ipMode == IP_MODE_STATIC) {
+ networkData[ID_IP_MODE] = 0;
+ networkData[ID_IP] = document.getElementById(iface + FIELD_IP_ADDRESS).value;
+ networkData[ID_NETMASK] = document.getElementById(iface + FIELD_SUBNET_MASK).value;
+ networkData[ID_GATEWAY] = document.getElementById(iface + FIELD_DEFAULT_GATEWAY).value;
+ networkData[ID_DNS1] = document.getElementById(iface + FIELD_DNS1_ADDRESS).value;
+ networkData[ID_DNS2] = document.getElementById(iface + FIELD_DNS2_ADDRESS).value;
+ } else {
+ networkData[ID_IP_MODE] = 1;
+ }
+ if (iface.startsWith(PREFIX_WIFI)) {
+ networkData[ID_SSID] = document.getElementById(iface + FIELD_SSID).value;
+ networkData[ID_SECURITY_MODE] = parseInt(document.getElementById(iface + FIELD_ENCRYPTION_TYPE).value);
+ if (networkData[ID_SECURITY_MODE] != 0 && passwordChanged)
+ networkData[ID_PASSWORD] = document.getElementById(iface + FIELD_PASSWORD).value;
+ }
+ ifaceData[iface] = networkData;
+ data[element] = ifaceData;
+ return data;
+}
+
+// Saves the network settings for the given interface.
+function saveInterface(element, iface) {
+ // Execute only in the network page.
+ if (!isNetworkShowing())
+ return;
+ // Hide the info popup.
+ showInfoPopup(false);
+ // Show the loading popup.
+ showLoadingPopup(true, MESSAGE_SAVING_CONFIGURATION);
+ // Send request to set new configuration.
+ $.post(
+ "http://" + getServerAddress() + "/ajax/set_config",
+ JSON.stringify({
+ "configuration": getInterfaceData(element, iface)
+ }),
+ function(data) {
+ // Process only in the network page.
+ if (!isNetworkShowing())
+ return;
+ // Process answer.
+ processSaveInterfaceResponse(data, element, iface);
+ }
+ ).fail(function(response) {
+ // Process only in the network page.
+ if (!isNetworkShowing())
+ return;
+ // Hide the loading panel.
+ showLoadingPopup(false);
+ // Process error.
+ processAjaxErrorResponse(response);
+ });
+}
+
+// Processes the save network request response.
+function processSaveInterfaceResponse(response, element, iface) {
+ // Check for error in the response.
+ if (!checkErrorResponse(response, false)) {
+ var statusFound = false;
+ // Check status in the response.
+ if (response[ID_DATA] != null) {
+ data = JSON.parse(response[ID_DATA]);
+ for (const [elementEntry, elementData] of Object.entries(data)) {
+ if (elementEntry != element)
+ continue;
+ for (const [ifaceEntry, ifaceData] of Object.entries(elementData)) {
+ if (ifaceEntry != iface)
+ continue;
+ if (ifaceData[ID_STATUS] != null) {
+ statusFound = true;
+ if (ifaceData[ID_STATUS] != 0)
+ toastr.error(ifaceData[ID_DESC]);
+ else
+ toastr.success(MESSAGE_CONFIGURATION_SAVED);
+ }
+ }
+ }
+ }
+ if (!statusFound)
+ toastr.error(ERROR_UNKNOWN);
+ }
+ // Hide the loading panel.
+ showLoadingPopup(false);
+}
+
+// Toggles the visibility of the given interface panel.
+function togglePanelVisibility(interface) {
+ // Initialize variables.
+ var panelButton = document.getElementById(interface + ID_TOGGLE_BUTTON);
+ // Sanity checks.
+ if (panelButton == null)
+ return;
+ // Check visibility.
+ if (panelButton.classList.contains(CLASS_ARROW_UP)) {
+ $("#" + interface + ID_PANEL_CONTAINER).slideUp("fast", function() {
+ panelButton.classList.remove(CLASS_ARROW_UP);
+ panelButton.classList.add(CLASS_ARROW_DOWN);
+ });
+ } else {
+ $("#" + interface + ID_PANEL_CONTAINER).slideDown("fast", function() {
+ panelButton.classList.remove(CLASS_ARROW_DOWN);
+ panelButton.classList.add(CLASS_ARROW_UP);
+ });
+ }
+}
\ No newline at end of file