import './style.css';
import { initMenus } from './menu';
let isConsoleExpanded = false;
let isAutoScroll = true;
let consoleContentList = [];
let consoleContent;
let isFileSystemExpanded = true;
let isFirmwareUpdateExpanded = false;
let consolePanel;
let fileSystem;
let firmware;
let consoleHeader;
let consoleBody;
let fileSystemHeader;
let fileSystemBody;
let filecontentFooter;
let firmwareHeader;
let firmwareBody;
let filesInput;
let fwInput;
let filesButton;
let firmwareButton;
let refreshButton;
let createDirButton;
let message;
let messageLimited;
let websocketStarted = false;
let wsSource;
let wsMsg = '';
let logOff = false;
let pageId = '';
let currentPath = '/';
const version = '3.0.0.a6';
let xmlhttpupload;
let prgfiletext;
let prgfile;
let uploadType = 0;
let restartTime;
let loginLink;
let loginModal;
let loginUser = '';
let loginMsg;
let fspath = '/files';
let hostpath = '/';
window.onload = function () {
consolePanel = document.getElementById('consolePanel');
fileSystem = document.getElementById('fileSystem');
firmware = document.getElementById('firmware');
consoleHeader = document.getElementById('consoleHeader');
consoleBody = document.getElementById('consoleBody');
fileSystemHeader = document.getElementById('fileSystemHeader');
fileSystemBody = document.getElementById('fileSystemBody');
filecontentFooter = document.getElementById('filecontentFooter');
firmwareHeader = document.getElementById('firmwareHeader');
firmwareBody = document.getElementById('firmwareBody');
consoleContent = document.getElementById('consoleContent');
fwInput = document.getElementById('filefw');
filesInput = document.getElementById('files');
message = document.getElementById('MSG');
messageLimited = document.getElementById('MSGLimited');
prgfiletext = document.getElementById('prgfiletext');
prgfile = document.getElementById('prgfile');
document.getElementById('cmdBtn').addEventListener('click', function () {
let input = document.getElementById('customCmdTxt');
if (input.value.trim().length == 0) return;
let url = new URL('http://' + window.location.host + '/command');
url.searchParams.append('cmd', input.value.trim());
httpGet(url, processCmdJson);
consoleContentUpdate(
"" + input.value.trim() + '\n'
);
input.value = '';
});
document
.getElementById('loginInput')
.addEventListener('keydown', function (event) {
if (event.keyCode === 13) {
document.getElementById('passwordInput').focus();
}
});
document
.getElementById('passwordInput')
.addEventListener('keydown', function (event) {
if (event.keyCode === 13) {
document.getElementById('loginbutton').click();
}
});
document
.getElementById('customCmdTxt')
.addEventListener('keyup', function (event) {
if (event.keyCode === 13) {
document.getElementById('cmdBtn').click();
}
});
consoleHeader.addEventListener('click', function () {
isConsoleExpanded = !isConsoleExpanded;
if (isConsoleExpanded) consoleBody.style.display = 'block';
else consoleBody.style.display = 'none';
});
loginMsg = document.getElementById('loginMsg');
loginLink = document.getElementById('loginLink');
loginModal = document.getElementById('loginpage');
loginLink.addEventListener('click', function () {
loginModal.classList.remove('hide');
});
document
.getElementById('disconnectbutton')
.addEventListener('click', function () {
document.getElementById('loginInput').value = '';
document.getElementById('loginbutton').click();
});
document
.getElementById('loginbutton')
.addEventListener('click', function () {
loginModal.classList.add('hide');
let user = document.getElementById('loginInput').value.trim();
loginUser = user;
let password = document
.getElementById('passwordInput')
.value.trim();
let url = new URL('http://' + window.location.host + '/login');
url.searchParams.append('USER', user);
url.searchParams.append('PASSWORD', password);
url.searchParams.append('SUBMIT', 'yes');
let xmlhttp = new XMLHttpRequest();
xmlhttp.onreadystatechange = function () {
if (xmlhttp.readyState == 4) {
if (xmlhttp.status != 200) {
if (xmlhttp.status == 401) {
handle401();
} else {
console.log(xmlhttp.status);
ErrorMSG(
'Error: board does not answered properly ' +
xmlhttp.status
);
}
} else {
getFWData();
}
}
};
xmlhttp.open('GET', url, true);
xmlhttp.send();
document.getElementById('passwordInput').value = '';
});
refreshButton = document.getElementById('refresh');
refreshButton.addEventListener('click', function () {
SendFileCommand('list', 'all');
});
firmwareButton = document.getElementById('uploapFW');
firmwareButton.addEventListener('click', function () {
prgupdatetext.innerHTML = '';
fwInput.click();
});
filesButton = document.getElementById('uploadFiles');
filesButton.innerHTML = fileIcon(true);
filesButton.addEventListener('click', function () {
filesInput.click();
});
fwInput.addEventListener('change', function () {
if (fwInput.value) {
if (!confirm('Confirm Firmware Update ?')) {
console.log('abort');
fwInput.value = '';
return;
}
uploadFirmware();
}
});
filesInput.addEventListener('change', function () {
console.log('upload');
if (filesInput.value) {
uploadFiles();
}
});
document
.getElementById('monitor_enable_autoscroll')
.addEventListener('click', function () {
if (document.getElementById('monitor_enable_autoscroll').checked) {
isAutoScroll = true;
autoscroll();
} else {
isAutoScroll = false;
}
});
consoleBody.style.display = 'none';
fileSystemHeader.addEventListener('click', function () {
isFileSystemExpanded = !isFileSystemExpanded;
if (isFileSystemExpanded) {
fileSystemBody.style.display = 'block';
fileSystemBody.scrollIntoView();
} else {
fileSystemBody.style.display = 'none';
}
});
firmwareHeader.addEventListener('click', function () {
isFirmwareUpdateExpanded = !isFirmwareUpdateExpanded;
if (isFirmwareUpdateExpanded) {
firmwareBody.style.display = 'block';
firmwareBody.scrollIntoView();
} else firmwareBody.style.display = 'none';
});
firmwareBody.style.display = 'none';
createDirButton = document.getElementById('createdir');
createDirButton.innerHTML = dirIcon(true);
createDirButton.addEventListener('click', function () {
let filename = prompt('Directory name', '');
if (filename != null && filename.trim().length > 0) {
SendFileCommand('createdir', filename.trim());
}
});
getFWData();
initMenus();
};
function handle401() {
loginModal.classList.remove('hide');
loginLink.classList.remove('hide');
if (loginUser.length > 0) {
loginMsg.classList.remove('hide');
} else {
loginMsg.classList.add('hide');
}
firmware.classList.add('hide');
fileSystem.classList.add('hide');
consolePanel.classList.add('hide');
}
function padNumber(num, size) {
let s = num.toString().padStart(size, '0');
return s;
}
function getPCTime() {
let d = new Date();
return (
d.getFullYear() +
'-' +
padNumber(d.getMonth() + 1, 2) +
'-' +
padNumber(d.getDate(), 2) +
'T' +
padNumber(d.getHours(), 2) +
':' +
padNumber(d.getMinutes(), 2) +
':' +
padNumber(d.getSeconds(), 2)
);
}
function isLimitedEnvironment(wifiMode) {
let sitesList = [
'clients3.google.com', //Android Captive Portal Detection
'connectivitycheck.',
//Apple iPhone, iPad with iOS 6 Captive Portal Detection
'apple.com',
'.akamaitechnologies.com',
//Apple iPhone, iPad with iOS 7, 8, 9 and recent versions of OS X
'www.appleiphonecell.com',
'www.itools.info',
'www.ibook.info',
'www.airport.us',
'www.thinkdifferent.us',
'.akamaiedge.net',
//Windows
'.msftncsi.com',
'microsoft.com',
];
if (wifiMode != 'AP') return false;
for (let i = 0; i < sitesList.length; i++) {
if (document.location.host.indexOf(sitesList[i]) != -1) return true;
}
return false;
}
function autoscroll() {
if (isAutoScroll) consoleContent.scrollTop = consoleContent.scrollHeight;
}
function consoleContentUpdate(message) {
if (message) {
consoleContentList = consoleContentList.concat(message);
consoleContentList = consoleContentList.slice(-300);
let output = '';
for (let i = 0; i < consoleContentList.length; i++) {
output += consoleContentList[i];
}
document.getElementById('consoleContent').innerHTML = output;
autoscroll();
}
}
function processCmdJson(text) {
let json;
try {
json = JSON.parse(text);
consoleContentUpdate(JSON.stringify(json, null, ' ') + '\n');
} catch (e) {
consoleContentUpdate(text + '\n');
}
}
function processFWJson(text) {
let json;
try {
json = JSON.parse(text);
} catch (e) {
ErrorMSG('Error: json data are incorrect!
' + text);
consoleContentUpdate(text);
return;
}
if (!json.status || !json.cmd || !json.data) {
ErrorMSG('Wrong version of webUI');
consoleContentUpdate(text);
return;
}
json = json.data;
if (json.FWVersion) {
let verLink = document.getElementById('verLink');
verLink.innerHTML = 'v' + json.FWVersion;
verLink.addEventListener('click', function () {
let url = new URL('http://' + window.location.host + '/config');
window.open(url, '_blank');
});
} else {
ErrorMSG(
'Error: json data are incorrect!
' +
JSON.stringify(json, null, '
')
);
return;
}
document.getElementById('espLink').addEventListener('click', function () {
let url = new URL('http://' + window.location.host);
window.open(url);
});
consolePanel.classList.remove('hide');
if (
(json.FlashFileSystem && json.FlashFileSystem != 'none') ||
(json.SDConnection && json.SDConnection != 'none')
) {
fileSystem.classList.remove('hide');
if (json.FlashFileSystem && json.FlashFileSystem == 'none') {
fspath = '/sdfiles';
}
}
if (json.WebUpdate == 'Enabled') firmware.classList.remove('hide');
if (typeof json.HostPath != 'undefined') hostpath = json.HostPath;
console.log('HostPath: ' + hostpath);
if (json.WiFiMode && json.WebSocketIP) {
if (isLimitedEnvironment(json.WiFiMode)) {
let address =
'http://' +
json.WebSocketIP +
(window.location.port == 80 ? '' : ':' + window.location.port);
InfoMSGLimited(
'It seems you are in limited environment,
please open a browser using
' +
address +
'
to get all features working'
);
}
}
if (json.Hostname) document.title = json.Hostname;
startSocket(json.WebSocketIP, json.WebSocketPort, json.WebCommunication);
SendFileCommand('list', 'all');
}
function startSocket(ip, port, sync) {
if (websocketStarted) {
wsSource.close();
}
wsSource = new WebSocket(
'ws://' + ip + ':' + port + (sync == 'Asynchronous' ? '/ws' : ''),
['webui-v3']
);
wsSource.binaryType = 'arraybuffer';
wsSource.onopen = function (e) {
websocketStarted = true;
};
wsSource.onclose = function (e) {
websocketStarted = false;
//seems sometimes it disconnect so wait 3s and reconnect
//if it is not a log off
if (!logOff)
setTimeout(() => {
startSocket(ip, port, sync);
}, 3000);
};
wsSource.onerror = function (e) {
ErrorMSG('Error: websocket error!
');
console.log('Error: websocket error!');
};
wsSource.onmessage = function (e) {
let msg = '';
//bin
if (e.data instanceof ArrayBuffer) {
let bytes = new Uint8Array(e.data);
for (let i = 0; i < bytes.length; i++) {
msg += String.fromCharCode(bytes[i]);
if (bytes[i] == 10 || bytes[i] == 13) {
wsMsg += msg;
if (!wsMsg.startsWith('ESP3D says: command forwarded')) {
consoleContentUpdate(wsMsg);
}
wsMsg = '';
msg = '';
}
}
wsMsg += msg;
} else {
msg = e.data;
let tval = msg.split(':');
if (tval.length >= 2) {
if (tval[0] == 'currentID') {
pageId = tval[1];
}
if (tval[0] == 'activeID') {
if (pageId != tval[1]) {
logOff = true;
wsSource.close();
InfoMSG(
'
It seems you are connect from another location, you are now disconnected.'
);
document.title = document.title + '(disconnected)';
consolePanel.classList.add('hide');
firmware.classList.add('hide');
fileSystem.classList.add('hide');
document
.getElementById('verLink')
.classList.add('disabled');
loginModal.classList.add('hide');
loginUser = '';
document.getElementById('loginInput').value = '';
document.getElementById('passwordInput').value = '';
document.cookie = '';
}
}
if (tval[0] == 'ERROR') {
xmlhttpupload.abort();
uploadError(tval[2], tval[1]);
}
}
}
};
}
function uploadError(msg, nb) {
let status = 'Upload failed';
if (nb != 0 && typeof nb != 'undefined') {
status = msg + '(' + nb + ')';
}
alert(status + '!');
if (uploadType == 1) {
let currentstatus = filecontentFooter.innerHTML;
if (currentstatus.length > 0) {
filecontentFooter.innerHTML =
'Status: ' +
status +
'  ' +
currentstatus.substring(currentstatus.indexOf('|'));
} else {
filecontentFooter.innerHTML = status;
}
} else if (uploadType == 2) {
prgupdatetext.innerHTML = status;
}
//location.reload();
}
function ErrorMSG(msg) {
message.innerHTML = msg;
message.className = 'text-error';
}
function InfoMSGLimited(msg) {
messageLimited.innerHTML = msg;
messageLimited.className = 'text-error';
}
function InfoMSG(msg) {
message.innerHTML = msg;
message.className = 'text-primary';
}
function getFWData() {
let url = new URL('http://' + window.location.host + '/command');
url.searchParams.append(
'cmd',
'[ESP800]json=YES version=' + version + ' time=' + getPCTime()
);
httpGet(url, processFWJson);
}
function SendFileCommand(action, filename) {
let url = new URL('http://' + window.location.host + fspath);
url.searchParams.append('action', action);
url.searchParams.append('filename', filename);
url.searchParams.append('path', currentPath);
httpGet(url, dispatchFileStatus);
}
function trashIcon() {
return "";
}
function backIcon() {
return "";
}
function fileIcon(plus = false) {
return (
"'
);
}
function dirIcon(plus = false) {
return (
"'
);
}
function dispatchFileStatus(jsonresponse) {
let json;
let currentpath = currentPath;
if (!currentpath.endsWith('/')) currentpath += '/';
currentpath += hostpath;
if (!currentpath.endsWith('/')) currentpath += '/';
let currentpath2 = currentpath.replaceAll('//', '/');
currentpath = currentpath2;
console.log('currentpath: ' + currentpath);
let eventslisteners = [];
let showESP3Dbutton = false;
try {
json = JSON.parse(jsonresponse);
//ugly but code is smaller
filecontentFooter.innerHTML =
'Status: ' +
json.status +
' | Total space: ' +
json.total +
' | Used space: ' +
json.used +
' | Occupation: ' +
"