tasmota-esp-web-tools
Version:
Web tools for ESP devices
267 lines (265 loc) • 8.57 kB
JavaScript
export class ColoredConsole {
constructor(targetElement) {
this.targetElement = targetElement;
this.state = {
bold: false,
italic: false,
underline: false,
strikethrough: false,
foregroundColor: null,
backgroundColor: null,
carriageReturn: false,
secret: false,
};
}
logs() {
return this.targetElement.innerText;
}
addLine(line) {
const re = /(?:\x1B|\\x1B)(?:\[(.*?)[@-~]|\].*?(?:\x07|\x1B\\))/g;
let i = 0;
if (this.state.carriageReturn) {
if (line !== "\n") {
// don't remove if \r\n
this.targetElement.removeChild(this.targetElement.lastChild);
}
this.state.carriageReturn = false;
}
if (line.includes("\r")) {
this.state.carriageReturn = true;
}
const lineSpan = document.createElement("span");
lineSpan.classList.add("line");
this.targetElement.appendChild(lineSpan);
const addSpan = (content) => {
if (content === "")
return;
const span = document.createElement("span");
if (this.state.bold)
span.classList.add("log-bold");
if (this.state.italic)
span.classList.add("log-italic");
if (this.state.underline)
span.classList.add("log-underline");
if (this.state.strikethrough)
span.classList.add("log-strikethrough");
if (this.state.secret)
span.classList.add("log-secret");
if (this.state.foregroundColor !== null)
span.classList.add(`log-fg-${this.state.foregroundColor}`);
if (this.state.backgroundColor !== null)
span.classList.add(`log-bg-${this.state.backgroundColor}`);
span.appendChild(document.createTextNode(content));
lineSpan.appendChild(span);
if (this.state.secret) {
const redacted = document.createElement("span");
redacted.classList.add("log-secret-redacted");
redacted.appendChild(document.createTextNode("[redacted]"));
lineSpan.appendChild(redacted);
}
};
while (true) {
const match = re.exec(line);
if (match === null)
break;
const j = match.index;
addSpan(line.substring(i, j));
i = j + match[0].length;
if (match[1] === undefined)
continue;
for (const colorCode of match[1].split(";")) {
switch (parseInt(colorCode)) {
case 0:
// reset
this.state.bold = false;
this.state.italic = false;
this.state.underline = false;
this.state.strikethrough = false;
this.state.foregroundColor = null;
this.state.backgroundColor = null;
this.state.secret = false;
break;
case 1:
this.state.bold = true;
break;
case 3:
this.state.italic = true;
break;
case 4:
this.state.underline = true;
break;
case 5:
this.state.secret = true;
break;
case 6:
this.state.secret = false;
break;
case 9:
this.state.strikethrough = true;
break;
case 22:
this.state.bold = false;
break;
case 23:
this.state.italic = false;
break;
case 24:
this.state.underline = false;
break;
case 29:
this.state.strikethrough = false;
break;
case 30:
this.state.foregroundColor = "black";
break;
case 31:
this.state.foregroundColor = "red";
break;
case 32:
this.state.foregroundColor = "green";
break;
case 33:
this.state.foregroundColor = "yellow";
break;
case 34:
this.state.foregroundColor = "blue";
break;
case 35:
this.state.foregroundColor = "magenta";
break;
case 36:
this.state.foregroundColor = "cyan";
break;
case 37:
this.state.foregroundColor = "white";
break;
case 39:
this.state.foregroundColor = null;
break;
case 41:
this.state.backgroundColor = "red";
break;
case 42:
this.state.backgroundColor = "green";
break;
case 43:
this.state.backgroundColor = "yellow";
break;
case 44:
this.state.backgroundColor = "blue";
break;
case 45:
this.state.backgroundColor = "magenta";
break;
case 46:
this.state.backgroundColor = "cyan";
break;
case 47:
this.state.backgroundColor = "white";
break;
case 40:
case 49:
this.state.backgroundColor = null;
break;
}
}
}
const atBottom = this.targetElement.scrollTop >
this.targetElement.scrollHeight - this.targetElement.offsetHeight - 50;
addSpan(line.substring(i));
// Keep scroll at bottom
if (atBottom) {
this.targetElement.scrollTop = this.targetElement.scrollHeight;
}
}
}
export const coloredConsoleStyles = `
.log {
flex: 1;
background-color: #1c1c1c;
font-family: "SFMono-Regular", Consolas, "Liberation Mono", Menlo, Courier,
monospace;
font-size: 12px;
padding: 16px;
overflow: auto;
line-height: 1.45;
border-radius: 3px;
white-space: pre-wrap;
overflow-wrap: break-word;
color: #ddd;
}
.log-bold {
font-weight: bold;
}
.log-italic {
font-style: italic;
}
.log-underline {
text-decoration: underline;
}
.log-strikethrough {
text-decoration: line-through;
}
.log-underline.log-strikethrough {
text-decoration: underline line-through;
}
.log-secret {
-webkit-user-select: none;
-moz-user-select: none;
-ms-user-select: none;
user-select: none;
}
.log-secret-redacted {
opacity: 0;
width: 1px;
font-size: 1px;
}
.log-fg-black {
color: rgb(128, 128, 128);
}
.log-fg-red {
color: rgb(255, 0, 0);
}
.log-fg-green {
color: rgb(0, 255, 0);
}
.log-fg-yellow {
color: rgb(255, 255, 0);
}
.log-fg-blue {
color: rgb(0, 0, 255);
}
.log-fg-magenta {
color: rgb(255, 0, 255);
}
.log-fg-cyan {
color: rgb(0, 255, 255);
}
.log-fg-white {
color: rgb(187, 187, 187);
}
.log-bg-black {
background-color: rgb(0, 0, 0);
}
.log-bg-red {
background-color: rgb(255, 0, 0);
}
.log-bg-green {
background-color: rgb(0, 255, 0);
}
.log-bg-yellow {
background-color: rgb(255, 255, 0);
}
.log-bg-blue {
background-color: rgb(0, 0, 255);
}
.log-bg-magenta {
background-color: rgb(255, 0, 255);
}
.log-bg-cyan {
background-color: rgb(0, 255, 255);
}
.log-bg-white {
background-color: rgb(255, 255, 255);
}
`;