Blueno/demonic-web/src/cerberus.js

220 lines
6.1 KiB
JavaScript

export { run };
import '../assets/demonic-web.css';
import 'xterm/css/xterm.css';
import { DemonicWeb } from './demonic-web.js';
import { Terminal } from 'xterm';
let darkTheme = {
brightMagenta: '#ed68d9',
brightGreen: '#5af78e',
brightBlue: '#678cfa',
brightCyan: '#9aedfe',
background: '#000000',
foreground: '#ffffff',
cursor: '#ffffff',
};
let lightTheme = {
brightMagenta: '#ed68d9',
brightGreen: '#008000',
brightBlue: '#678cfa',
brightCyan: '#02bfe5',
background: '#fffafa',
foreground: '#000000',
cursor: '#000000',
};
function run(args) {
if (document.readyState == "complete" || document.readyState == "loaded")
return bootup(args)
else
document.addEventListener('DOMContentLoaded', () => bootup(args));
}
function bootup(args) {
const url = args.url || 'wss://liambeckman.com:8181';
let container = args.elem;
if (container == null)
container = document.getElementsByClassName('demonic-web')[0];
// xterm.js constructor
const terminal = new Terminal({
convertEol: true,
});
terminal.open(container);
// User prompt
const MAGENTA='\x1b[1;35m';
const GREEN='\x1b[1;32m';
const CYAN='\x1b[1;36m';
const NC='\x1b[0m';
const userPrompt = args.userPrompt ||
`${CYAN}demo${NC}${MAGENTA} @ ${NC}${CYAN}demonic${NC} ${GREEN}>${NC} `;
terminal.write(userPrompt);
// Command
if (args.write != false)
terminal.write(args.data);
terminal.focus();
let demonicWeb = new DemonicWeb(terminal, url, userPrompt);
demonicWeb.connect();
// Resize terminal
new ResizeObserver(() => {
if (demonicWeb.getReadyState() == WebSocket.OPEN)
demonicWeb.fit();
}).observe(container);
// Status bar
let termElement = container.querySelector('.terminal');
let statusBar = container.querySelector('#status');
if (statusBar == null) {
statusBar = document.createElement('div');
statusBar.id = 'status';
container.insertBefore(statusBar, termElement);
}
if (args.statusBar == false)
statusBar.classList.add('hide');
// Current WebSocket address
let urlSpan = document.createElement('span');
urlSpan.innerHTML = url;
urlSpan.classList.add('urlSpan');
urlSpan.title = 'Set WebSocket Address';
urlSpan.innerHTML = url;
urlSpan.onclick = () => getNewUrl(demonicWeb, urlSpan);
// 'connecting' event listener
demonicWeb.eventEmitter.addListener('connecting', () => {
statusBar.classList.remove('connected');
statusBar.innerHTML = 'Status: Connecting...';
statusBar.appendChild(urlSpan);
terminal.setOption('cursorBlink', false);
});
// 'connected' event listener
let init = true;
demonicWeb.eventEmitter.addListener('connected', () => {
statusBar.classList.add('connected');
statusBar.innerHTML = 'Status: Connected!';
statusBar.appendChild(urlSpan);
terminal.setOption('cursorBlink', true);
if (init) {
demonicWeb.send(args);
init = false;
}
});
// Examples
const examples = document.getElementById('demonic-examples');
if (examples != null) {
examples.addEventListener('click', (event) => {
const example = event.target;
if (example == examples)
return;
const data = example.innerHTML;
demonicWeb.clearLine();
demonicWeb.write(data);
demonicWeb.send(data);
terminal.focus();
});
}
// Theme
let theme = (args.theme == 'light') ? lightTheme : darkTheme;
terminal.setOption('theme', theme);
// Buttons
let buttons = document.createElement('div');
buttons.className = 'buttons';
termElement.appendChild(buttons);
// Menu button
let menuBtn = document.createElement('button');
menuBtn.textContent = '☰';
menuBtn.title = 'Open Menu';
buttons.appendChild(menuBtn);
menuBtn.onclick = () => {
menu.classList.toggle('hide');
}
window.addEventListener('click', (e) => {
if (e.target != menuBtn && !menu.contains(e.target))
menu.classList.add('hide');
});
terminal.onKey(e => {
// Escape key
if (e.key == '\u001b')
menu.classList.add('hide');
});
let menu = document.createElement('ul');
menu.classList.add('demonic-menu');
menu.classList.add('hide');
termElement.appendChild(menu);
// Change theme button
let themeItem = document.createElement('li');
themeItem.textContent = '☯ Change Theme';
menu.appendChild(themeItem);
themeItem.onclick = () => {
theme = (theme == lightTheme) ? darkTheme : lightTheme;
terminal.setOption('theme', theme);
buttons.classList.toggle('dark-text');
}
// Toggle status button
let statusItem = document.createElement('li');
statusItem.textContent = '🛈 Toggle Status Bar';
menu.appendChild(statusItem);
statusItem.onclick = () => statusBar.classList.toggle('hide');
// Set WebSocket address button
let wsItem = document.createElement('li');
wsItem.textContent = '✉ Set WebSocket Address';
menu.appendChild(wsItem);
wsItem.onclick = () => getNewUrl(demonicWeb, urlSpan);
// Fullscreen button
let fullItem = document.createElement('li');
fullItem.textContent = '⛶ Toggle Fullscreen';
menu.appendChild(fullItem);
fullItem.onclick = () => container.classList.toggle('fullscreen');
// Close button
let closeItem = document.createElement('li');
closeItem.textContent = '✕ Close Terminal';
closeItem.classList.add('close');
menu.appendChild(closeItem);
closeItem.onclick = () => {
demonicWeb.close();
container.remove();
}
return demonicWeb;
}
function getNewUrl(demonicWeb, urlSpan) {
let url = prompt('Enter WebSocket Address:', demonicWeb.url);
if (url != null) {
urlSpan.innerHTML = url;
demonicWeb.close();
demonicWeb.url = url;
demonicWeb.connect();
}
}