/** @file WebPage.h @brief Here is saved root WEB page @author Miroslav Pivovarsky Contact: miroslav.pivovarsky@gmail.com https://codebeautify.org/remove-extra-spaces @bug: no know bug */ #ifndef _WEB_PAGE_H_ #define _WEB_PAGE_H_ #define MSG_REBOOT_MCU "Reboot process started, wait several seconds for mcu to boot up. You can close this window now." #define MSG_SAVE_OK_REBOOT "Save OK. Please reboot MCU" ///< WEB app msg save OK #define MSG_SAVE_OK_WIFI "Save OK. Connecting to Wi-Fi. Please wait several second." #define MSG_SAVE_OK "Save cfg OK" ///< WEB app msg save OK #define MSG_SAVE_NOTOK "Save cfg NOT OK!" ///< WEB app msg save NOT OK #define MSG_SCANNING "Scanning Wi-Fi networks. Wait 8s..." ///< WEB app msg Scanning wifi #define MSG_UPDATE_START "Start updating." /* ------------------------------------------------------------------------------------------------------------ */ const char index_html[] PROGMEM = R"rawliteral( Prusa ESP32-cam

Trigger interval: s
















Prusa Connect ESP32 cam

Author

Miroslav Pivovarsky

Licence | General Terms and Conditions | Privacy Policy | Cookie Preferences
)rawliteral"; /* ------------------------------------------------------------------------------------------------------------ */ const char page_auth_html[] PROGMEM = R"rawliteral(
Set web authentication
WEB authentication
Username
Password Show Password
Confirm Password Show Password
)rawliteral"; /* ------------------------------------------------------------------------------------------------------------ */ const char page_wifi_html[] PROGMEM = R"rawliteral(

Connection status

Status:

SSID:

Signal: % / dBm

IP Address:

mDNS: https://.local


Available networks

Network name (SSID) Signal strength (RSSI) Channel Encryption


Connect to Wi-Fi network
Wi-Fi network name (SSID)
Password
)rawliteral"; /* ------------------------------------------------------------------------------------------------------------ */ const char page_config_html[] PROGMEM = R"rawliteral(
Basic image settings
Connect Token 
Fingerprint
Trigger Interval [s] 
Image qualityLow High
Resolution
BrightnessLow High
ContrastLow High
SaturationLow High
Horizontal mirror
Vertical flip
LED light
LED flash
Flash durationLow High
Flash duration ms
Advanced image settings
Automatic white balancing
Automatic white balancing gain
Automatic white balancing mode
Automatic Exposure Control
Second Level Automatic Exposure Control
Automatic exposure levelLow High
Automatic exposure timeLow High
Automatic exposure time ms
Automatic gain control
Automatic gain control levelLow High
Bad pixel correction
White pixel correction
Raw gamma correction
Lens correction
)rawliteral"; /* ------------------------------------------------------------------------------------------------------------ */ const char page_system_html[] PROGMEM = R"rawliteral(
System status
PrusaConnect Status
Wi-Fi mode
Wi-Fi service AP SSID
Uptime
Software version
Software build
Available software update Check update from cloud
System configuration
mDNS record.local 
Log level
Get logs

Firmware update
Status:Ready
Processing:
0%
)rawliteral"; /* ------------------------------------------------------------------------------------------------------------ */ const char styles_css[] PROGMEM = R"rawliteral( body { font-family: sans-serif; } /* index styles */ .p1 { color: #797979; font: normal normal normal 18px/5px sans-serif; letter-spacing: 0px; } .p2 { text-align: left; font: normal normal bold 14px/20px sans-serif; letter-spacing: 0px; color: #808080; opacity: 1; display: inline-block; } .p3 { text-align: left; font: normal normal normal 14px/20px sans-serif; letter-spacing: 0px; color: #808080; opacity: 1; display: inline-block; } .p4 { text-align: left; font: normal normal normal 14px/20px sans-serif; letter-spacing: 0px; color: #808080; opacity: 1; } .p5 { text-align: center; font: normal normal bold 14px/20px sans-serif; letter-spacing: 0px; color: #000000; opacity: 1; } /* NAVIGATION BAR */ nav { display: flex; background-color: transparent; } .top_bar { display: flex; width: 100%; } .top_bar li { display: inline-block; padding: 5px; } .top_bar li a { text-decoration: none; cursor: pointer; display: flex; align-items: center; } .top_bar li a:hover { text-decoration: underline #fa6831; text-underline-position: under; text-underline-offset: 8px; text-decoration-thickness: 2px; } #links li a.active { text-decoration: underline #fa6831; text-underline-position: under; text-underline-offset: 8px; text-decoration-thickness: 2px; } /* CFG BAR */ cfg { display: flex; flex-direction: column; text-align: center; font: normal normal bold 14px/20px sans-serif; letter-spacing: 0px; color: #2A2A2A; opacity: 1; } cfg_bar li { display: inline-block; padding: 14px; font-size: 16px; left: 50%; } cfg_bar li a { text-decoration: none; cursor: pointer; color: #212529; } cfg_bar li a:hover { color: #fa6831; } /* CONTAINER */ .container { display: table; height: 100%; width: 100%; } .container_left-half { grid-column: 1; display: table-cell; vertical-align: middle; width: 50%; text-align: center; } .container_right-half { grid-column: 2; display: table-cell; vertical-align: middle; width: 50%; } /* CHECKBOX SLIDER */ .switch { position: relative; display: inline-block; width: 30px; height: 17px; vertical-align: middle; } .switch input { opacity: 0; width: 0; height: 0; } .checkbox_slider { position: absolute; cursor: pointer; top: 0; left: 0; right: 0; bottom: 0; background-color: #ccc; -webkit-transition: .4s; transition: .4s; } .checkbox_slider:before { position: absolute; content: ""; height: 13px; width: 13px; left: 2px; bottom: 2px; background-color: white; -webkit-transition: .4s; transition: .4s; } input:checked+.checkbox_slider { background-color: #797979; } input:focus+.checkbox_slider { box-shadow: 0 0 1px #797979; } input:checked+.checkbox_slider:before { -webkit-transform: translateX(13px); -ms-transform: translateX(13px); transform: translateX(13px); } .checkbox_slider.round { border-radius: 13px; } .checkbox_slider.round:before { border-radius: 50%; } /* BUTTON */ .btn { width: 306px; height: 30px; text-align: center; font: normal normal bold 14px/5px sans-serif; color: #000000; background-color: white; border-radius: 5px; border: 1px solid #343a40; } .btn:hover { background-color: #FA6831; color: white; } /* BOTTON table */ #botton { width: 100%; text-align: center; background: #F5F5F5 0% 0% no-repeat padding-box; opacity: 1; bottom: 0; } /* ----- styles config ----- */ .pc1 { text-align: right; font: normal normal normal 11px/5px sans-serif; letter-spacing: 0px; color: #797979; opacity: 1; } .pc2 { text-align: left; font: normal normal normal 12px/5px sans-serif; letter-spacing: 0px; color: #000000; opacity: 1; } .pc3 { text-align: right; font: normal normal normal bold 12px/17px sans-serif; letter-spacing: 0px; color: #2A2A2A; opacity: 1; } /* data table */ #data { font-family: Arial, Helvetica, sans-serif; border-collapse: collapse; width: 100%; table-layout: fixed; } #data td, #data th { padding: 8px; } #data th { padding-top: 12px; padding-bottom: 12px; text-align: left; } /* BUTTON */ .btn_save { width: 69px; height: 24px; text-align: center; font: normal normal bold 14px/5px sans-serif; color: #000000; background-color: white; border-radius: 5px; border: 1px solid #343a40; } .btn_save:hover { background-color: #FA6831; color: white; } /* RANGE */ .slider { -webkit-appearance: none; width: 133px; height: 10px; border-radius: 5px; background: linear-gradient(to right, #d3d3d3 50%, #FA6831 50%); outline: none; } .slider::-webkit-slider-thumb { -webkit-appearance: none; appearance: none; width: 16px; height: 16px; border-radius: 50%; background: #FA6831; cursor: pointer; } .slider::-moz-range-thumb { width: 16px; height: 16px; border-radius: 50%; background: #FA6831; cursor: pointer; } /* ----- styles wifi ----- */ .w1 { text-align: left; font: normal normal bold 12px/17px sans-serif; letter-spacing: 0px; color: #2A2A2A; opacity: 1; } .w2 { font: normal normal normal 11px/5px sans-serif; letter-spacing: 0px; color: #797979; opacity: 1; } .w2 span { vertical-align: middle; } #center_tb { border-collapse: collapse; width: 100%; table-layout: fixed; text-align: left; } /* wifi_ntw table */ #wifi_ntw { font: normal normal normal 12px/5px sans-serif; border-collapse: collapse; width: 100%; table-layout: fixed; text-align: left; } #wifi_ntw td { border-bottom: 1px solid #ddd; padding: 8px; } #wifi_ntw tr:nth-child(even) { background: #F8F8F8 0% 0% no-repeat padding-box; } #wifi_ntw tr:hover { background-color: #ddd; } #wifi_ntw th { background-color: transparent; text-align: left; font: normal normal bold 13px/11px sans-serif; letter-spacing: 0px; color: #2A2A2A; opacity: 1; } #wifi_ntw tr { border-bottom: 1px solid #ccc; } #wifi_ntw img { width: 19px; height: 12px; } /* BUTTON */ .btn_save_w { width: 178px; height: 24px; text-align: center; font: normal normal bold 14px/5px sans-serif; color: #000000; background-color: white; border-radius: 5px; border: 1px solid #343a40; } .btn_save_w:hover { background-color: #FA6831; color: white; } /* ----- styles auth ----- */ .pa1 { text-align: right; font: normal normal normal 11px/5px sans-serif; letter-spacing: 0px; color: #797979; opacity: 1; } .pa2 { text-align: left; font: normal normal bold 12px/17px sans-serif; letter-spacing: 0px; color: #2A2A2A; opacity: 1; } .pa3 { text-align: right; font: normal normal normal bold 12px/17px sans-serif; letter-spacing: 0px; color: #2A2A2A; opacity: 1; } /* BUTTON */ .btn_save_a { width: 178px; height: 24px; text-align: center; font: normal normal bold 14px/5px sans-serif; color: #000000; background-color: white; border-radius: 5px; border: 1px solid #343a40; } .btn_save_a:hover { background-color: #FA6831; color: white; } .toggle-password { position: relative; cursor: pointer; } .toggle-password img { position: absolute; top: 50%; right: 0; transform: translateY(-50%); } .password-container { display: flex; align-items: center; } #auth_password.reveal { -webkit-text-security: none; } #auth_password { -webkit-text-security: disc; } /* ----- styles system ----- */ .ps1 { text-align: right; font: normal normal normal 11px/5px sans-serif; letter-spacing: 0px; color: #797979; opacity: 1; } .ps2 { text-align: left; font: normal normal normal 12px/5px sans-serif; letter-spacing: 0px; color: #000000; opacity: 1; } .ps3 { text-align: right; font: normal normal normal bold 12px/17px sans-serif; letter-spacing: 0px; color: #2A2A2A; opacity: 1; } /* data table */ #data { font-family: Arial, Helvetica, sans-serif; border-collapse: collapse; width: 100%; table-layout: fixed; } #data td, #data th { padding: 8px; } #data th { padding-top: 12px; padding-bottom: 12px; text-align: left; } /* update table */ update { font-family: Arial, Helvetica, sans-serif; border-collapse: collapse; width: 100%; table-layout: fixed; } #update td, #update th { padding: 8px; } #update th { padding-top: 12px; padding-bottom: 12px; text-align: left; } /* BUTTON */ .btn_update { width: 178px; height: 24px; text-align: center; font: normal normal bold 14px/5px sans-serif; color: #000000; background-color: white; border-radius: 5px; border: 1px solid #343a40; } .btn_update:hover { background-color: #FA6831; color: white; } .underlined-text { text-decoration: underline; color: blue; cursor: pointer; } /* progress bar*/ .progress-container { width: 100%; background-color: #ccc; } .progress-bar { width: 0px; height: 15px; background-color: #FA6831; text-align: center; line-height: 15px; color: white; } /* advanced cam cfg */ .content { display: none; } .btn_collapsible { width: 300px; height: 24px; text-align: center; font: normal normal bold 14px/5px sans-serif; color: #000000; background-color: white; border-radius: 5px; border: 1px solid #343a40; } .btn_collapsible:hover { background-color: #FA6831; color: white; } )rawliteral"; /* ------------------------------------------------------------------------------------------------------------ */ const char scripts_js[] PROGMEM = R"rawliteral( function get_data(val) { jQuery.ajax({ url: 'json_input', type: 'GET', timeout: 5000, success: function(data) { console.log("Incommming data: "); console.log(data); var obj = JSON.parse(data); console.log(obj); if (!document.querySelector('#light-icon img')) { var img = document.createElement('img'); img.src = (obj.led == "true") ? 'light-on-icon.svg' : 'light-off-icon.svg'; document.getElementById('light-icon').appendChild(img); } if (val == "config") { $("#fingerprint").text(obj.fingerprint); $("#refreshInterval").text(obj.refreshInterval); document.getElementById('tokenid').value = obj.token; document.getElementById('refreshid').value = obj.refreshInterval; document.getElementById('photo_qualityid').value = obj.photoquality; document.getElementById('framesizeid').value = obj.framesize; document.getElementById('brightnessid').value = obj.brightness; document.getElementById('contrastid').value = obj.contrast; document.getElementById('saturationid').value = obj.saturation; document.getElementById('hmirrorid').checked = obj.hmirror; document.getElementById('vflipid').checked = obj.vflip; document.getElementById('lencid').checked = obj.lensc; document.getElementById('exposure_ctrlid').checked = obj.exposure_ctrl; document.getElementById('awbid').checked = obj.awb; document.getElementById('awb_gainid').checked = obj.awb_gain; document.getElementById('wb_modeid').value = obj.wb_mode; document.getElementById('ledid').checked = obj.led; document.getElementById('flashid').checked = obj.flash; document.getElementById('flash_timeid').value = obj.flash_time; document.getElementById('bpcid').checked = obj.bpc; document.getElementById('wpcid').checked = obj.wpc; document.getElementById('raw_gamaid').checked = obj.raw_gama; document.getElementById('aec2id').checked = obj.aec2; document.getElementById('ae_levelid').value = obj.ae_level; document.getElementById('aec_valueid').value = obj.aec_value; document.getElementById('gain_ctrlid').checked = obj.gain_ctrl; document.getElementById('agc_gainid').value = obj.agc_gain; document.getElementById("flash_time_value").innerText = obj.flash_time; document.getElementById("aec_value_value").innerText = obj.aec_value; $("#status_hmirror").text((obj.hmirror == "true") ? "On" : "Off"); $("#status_vflip").text((obj.vflip == "true") ? "On" : "Off"); $("#status_lensc").text((obj.lensc == "true") ? "On" : "Off"); $("#status_exposure_ctrl").text((obj.exposure_ctrl == "true") ? "On" : "Off"); $("#status_awb").text((obj.awb == "true") ? "On" : "Off"); $("#status_awb_gain").text((obj.awb_gain == "true") ? "On" : "Off"); $("#status_led").text((obj.led == "true") ? "On" : "Off"); $("#status_flash").text((obj.flash == "true") ? "On" : "Off"); $("#status_bpc").text((obj.bpc == "true") ? "On" : "Off"); $("#status_wpc").text((obj.wpc == "true") ? "On" : "Off"); $("#status_raw_gama").text((obj.raw_gama == "true") ? "On" : "Off"); $("#status_aec2").text((obj.aec2 == "true") ? "On" : "Off"); $("#status_gain_ctrl").text((obj.gain_ctrl == "true") ? "On" : "Off"); sliderCheck(); } if (val == "auth") { document.getElementById('authid').checked = obj.auth; $("#status_auth").text((obj.auth == "true") ? "On" : "Off"); document.getElementById('auth_username').value = obj.auth_username; } if (val == "wifi") { $("#ssid").text(obj.ssid); $("#rssi").text(obj.rssi); $("#rssi_percentage").text(obj.rssi_percentage); $("#ip").text(obj.ip); $("#mdns").text(obj.mdns); $("#wifi_network_status").text(obj.wifi_network_status); if (!document.querySelector('#main-wifi-signal wifi_img')) { var wifi_img = document.createElement('wifi_img'); wifi_img.width = 19; wifi_img.height = 12; wifi_img.src = getIconPath(obj.rssi); document.getElementById('main-wifi-signal').appendChild(wifi_img); } } if (val == "system") { $("#uptime").text(obj.uptime); $("#sw_ver").text(obj.sw_ver); $("#sw_build").text(obj.sw_build); $("#last_upload_status").text(obj.last_upload_status); $("#wifi_mode").text(obj.wifi_mode); $("#sw_new_ver").text(obj.sw_new_ver); $("#service_ap_ssid").text(obj.service_ap_ssid); document.getElementById('mdnsid').value = obj.mdns; document.getElementById('loglevelid').value = obj.log_level; } }, error: function(html) { console.log("json Timeout or error"); //alert("jquery timeout or comunication error"); } }); } function sliderCheck() { var ranges = document.querySelectorAll(".slider"); ranges.forEach(function(range) { var percent = (range.value - range.min) / (range.max - range.min) * 100; var gradient = "linear-gradient(to right, #FA6831 " + percent + "%, #d3d3d3 " + percent + "%)"; range.style.background = gradient; range.oninput = function() { var percent = (this.value - this.min) / (this.max - this.min) * 100; var gradient = "linear-gradient(to right, #FA6831 " + percent + "%, #d3d3d3 " + percent + "%)"; this.style.background = gradient; } }); } function getIconPath(rssi) { let path; if (rssi == 0) { path = 'wifi-icon-0.svg'; } else if (rssi <= -70) { path = 'wifi-icon-1.svg'; } else if (rssi > -70 && rssi <= -60) { path = 'wifi-icon-2.svg'; } else if (rssi > -60 && rssi <= -50) { path = 'wifi-icon-3.svg'; } else { path = 'wifi-icon-4.svg'; } return path; } var OpenImageclickCount = 0; function openImage() { var img = document.getElementById("photo"); if (OpenImageclickCount % 2 == 0) { img.style.position = "fixed"; img.style.top = "5%"; img.style.left = "5%"; img.style.width = "auto"; img.style.height = "auto"; img.style.maxWidth = "100%"; img.style.maxHeight = "90%"; img.style.zIndex = "9999"; } else { img.style.position = ""; img.style.top = ""; img.style.left = ""; img.style.width = ""; img.style.height = ""; img.style.zIndex = ""; } OpenImageclickCount++; } function actionButton(url, reload, msg) { var xhr = new XMLHttpRequest(); if (msg != '') { alert(msg); } xhr.onreadystatechange = function() { if (xhr.readyState == 4 && xhr.status == 200) { if (reload == true) { setTimeout(function() { location.reload(); }, 200); } } }; xhr.open('GET', url, true); xhr.send(); } function setActive(link) { var links = document.querySelectorAll('#links li a'); links.forEach(function(item) { item.classList.remove('active'); }); link.classList.add('active'); } var links = document.querySelectorAll('#links li a'); links.forEach(function(link) { link.addEventListener('click', function() { setActive(link); }); }); function addClickListener(id) { var link = document.getElementById(id); if (!link.hasOwnProperty('clickListener')) { link.addEventListener('click', function(event) { event.preventDefault(); window.open(link.href, '_blank'); }); link.clickListener = true; } } /* wifi page */ function setWifi(val_ssid, val_pass) { var xmlHttp = new XMLHttpRequest(); xmlHttp.open("GET", "wifi_cfg?wifi_ssid=" + encodeURIComponent(val_ssid) + "&wifi_pass=" + encodeURIComponent(val_pass), false); xmlHttp.send(null); alert(xmlHttp.responseText); get_data("wifi"); } function scanWifi() { var xmlHttp = new XMLHttpRequest(); xmlHttp.open("GET", "wifi_scan?", false); xmlHttp.send(null); alert(xmlHttp.responseText); get_data("wifi"); setTimeout(function() { GetDataAndPrintTableWiFi(); }, 8000); } function GetDataAndPrintTableWiFi() { $("#wifi_ntw").find("tr:gt(0)").remove(); $.ajax({ url: 'json_wifi', type: 'GET', timeout: 15000, dataType: 'json', data: {}, success: function(data) { for (var i = 0; i < data.length; i++) { const IconName = "wifi-icon-" + i; var row = $('' + data[i].ssid + '
' + data[i].channel + '' + data[i].encryption + ''); $('#wifi_ntw').append(row); if (!document.querySelector('#' + IconName + ' img')) { var img = document.createElement('img'); img.src = getIconPath(data[i].rssi); document.getElementById(IconName).prepend(img); document.getElementById(IconName).append(data[i].rssi_percentage); document.getElementById(IconName).append("% / "); document.getElementById(IconName).append(data[i].rssi); document.getElementById(IconName).append("dBm"); } } }, error: function(jqXHR, textStatus, errorThrown) { console.log('Error:' + textStatus + '-' + errorThrown); } }); } /* auth page */ function setAuth(val_name, val_pass) { var xmlHttp = new XMLHttpRequest(); xmlHttp.open("GET", "basicauth_cfg?" + "auth_username=" + encodeURIComponent(val_name) + "&auth_password=" + encodeURIComponent(val_pass), false); xmlHttp.send(null); alert(xmlHttp.responseText); get_data("auth"); } function changeValue(val, url, reload) { var xmlHttp = new XMLHttpRequest(); xmlHttp.open("GET", url + val, false); xmlHttp.send(null); if ((url == "set_int?refresh=") || (url == "set_token?token=") || (url == "set_mdns?mdns=")) { alert(xmlHttp.responseText); } if (url == "set_flash_time?flash_time=") { document.getElementById("flash_time_value").innerText = val; } get_data(reload); } function togglePasswordVisibility() { const passwordInput = document.getElementById("auth_password"); const eyeIcon = document.getElementById("eye-icon"); if (passwordInput.getAttribute("type") === "password") { passwordInput.setAttribute("type", "text"); passwordInput.classList.add("reveal"); eyeIcon.src = "eye-slash.svg"; eyeIcon.alt = "Hide Password"; } else { passwordInput.setAttribute("type", "password"); passwordInput.classList.remove("reveal"); eyeIcon.src = "eye.svg"; eyeIcon.alt = "Show Password"; } } /* system page */ if (typeof uploadingFirmware === 'undefined') { var uploadingFirmware = false; } if (typeof FileSize === 'undefined') { var FileSize = 0; } function uploadFile() { alert("Started updating..."); const firmwareInput = document.getElementById('firmwareInput'); const statusDiv = document.getElementById('status'); const file = firmwareInput.files[0]; FileSize = file.size; SetFirmwareSize(file.size); if (file) { statusDiv.innerText = 'Updating...'; uploadingFirmware = true; const formData = new FormData(); formData.append('firmware', file); fetch('/upload', { method: 'POST', body: formData, }) .then((response) => { if (response.ok) { response.text().then((data) => { const jsonData = JSON.parse(data); updateProgress(); uploadingFirmware = false; if (jsonData.errorMessage) { alert(`Error message: ${jsonData.errorMessage}`); } }); } else { uploadingFirmware = false; response.text().then((errorMessage) => { alert(`Error message: ${errorMessage}`); }); } }) .catch((error) => { console.error('Error:', error); uploadingFirmware = false; }); } else { statusDiv.innerText = 'No file selected'; } } function SetFirmwareSize(val) { var xmlHttp = new XMLHttpRequest(); xmlHttp.open("GET", "set_firmware_size?size=" + val, false); xmlHttp.send(null); } function updateProgress() { if (!uploadingFirmware) { return; } fetch('/UpdateProcessing', { method: 'GET', }) .then((response) => { if (response.ok) { return response.json(); } else { throw new Error('Failed to fetch progress'); } }) .then((data) => { const statusDiv = document.getElementById('status'); var progressBar = document.getElementById("myProgressBar"); progressBar.style.width = data.processed_percent + "%"; progressBar.innerHTML = data.processed_percent + "%"; statusDiv.innerText = data.message; uploadingFirmware = data.updating; if (data.updating == false && !updateCompleted) { alert('Operation done. Please reboot MCU.'); uploadingFirmware = false; updateCompleted = true; clearInterval(updateInterval); } }) .catch((error) => { console.error('Error:', error); var progressBar = document.getElementById("myProgressBar"); progressBar.innerHTML = "Error"; clearInterval(updateInterval); }); } function checkUpdate() { var xmlHttp = new XMLHttpRequest(); alert("Connecting to server... Please wait several second"); xmlHttp.open("GET", "/check_web_ota_update", false); xmlHttp.send(null); alert(xmlHttp.responseText); get_data("system"); } function updateWeb() { alert("Started updating from cloud."); var xmlHttp = new XMLHttpRequest(); xmlHttp.open("GET", "web_ota_update?update=true", false); xmlHttp.send(null); uploadingFirmware = true; } function validatePasswords() { var password = document.getElementById("auth_password").value; var confirmPassword = document.getElementById("auth_password_confirm").value; var saveButton = document.querySelector(".btn_save_a"); var passwordStatus = document.getElementById("pass_match"); if (password === confirmPassword) { passwordStatus.innerHTML = "✔️"; saveButton.disabled = false; } else { passwordStatus.innerHTML = "❌"; saveButton.disabled = true; } } if (document.getElementById("auth_password")) { document.getElementById("auth_password").addEventListener("input", validatePasswords); } if (document.getElementById("auth_password_confirm")) { document.getElementById("auth_password_confirm").addEventListener("input", validatePasswords); } if ((document.getElementById("auth_password")) && (document.getElementById("auth_password_confirm"))) { validatePasswords(); } function setupCollapsibleButtons() { $(".btn_collapsible").click(function(){ $(this).toggleClass("active"); var content = $(this).parent().next(); if (content.css("display") === "block") { content.css("display", "none"); } else { content.css("display", "block"); } }); } )rawliteral"; /* ------------------------------------------------------------------------------------------------------------ */ const char license_html[] PROGMEM = R"rawliteral(

The software for device falls under the GPL-3.0 license terms. To read the license terms please visit this page.

)rawliteral"; /* ------------------------------------------------------------------------------------------------------------ */ const char gtac_html[] PROGMEM = R"rawliteral(

To read the General Terms and Conditions, please visit this page.

)rawliteral"; /* ------------------------------------------------------------------------------------------------------------ */ const char privacypolicy_html[] PROGMEM = R"rawliteral(

To read the Privacy Policy, please visit this page.

)rawliteral"; /* ------------------------------------------------------------------------------------------------------------ */ const char cookies_html[] PROGMEM = R"rawliteral(

To read the Cookie policy, please visit this page.

)rawliteral"; #endif /* EOF */