portfolio/assets/js/terminal.js
2025-12-28 19:49:58 -05:00

197 lines
5.5 KiB
JavaScript

class Terminal {
constructor() {
this.terminalElem = document.getElementById("term")
this.terminalContainerElem = document.getElementById("term-container")
this.promptContainerElem = document.getElementById("prompt-container")
this.promptsAndResponses = []
this.commands = []
this.commandPosition = this.commands.length
this.currentPrompt = null
this.active = false;
this.initialized = false;
}
show() {
if (!this.initialized) {
this.initialized = true;
this.initialize()
} else {
this.terminalElem.style.display = "block"
this.terminalContainerElem.style.display = "block"
if (this.currentPrompt) {
this.currentPrompt.focus()
}
}
terminalMode = true;
}
hide () {
this.terminalElem.style.display = "none"
this.terminalContainerElem.style.display = "none"
terminalMode = false;
}
createPrompt() {
this.commandPosition = this.commands.length
var promptContainerElem = document.createElement("div")
promptContainerElem.classList.add("prompt-container")
var label = document.createElement("label")
label.innerHTML = '>>>'
var prompt = document.createElement("input")
prompt.setAttribute("autofocus", true)
var self = this
prompt.addEventListener("keypress", function(event) {
if (event.key === "Enter") {
if (terminalMode && this.value !== ''){
event.preventDefault();
this.disabled = true;
self.handlePrompt(this.value);
}
}
})
var clearFixDiv = document.createElement("div")
clearFixDiv.classList.add("clearfix")
promptContainerElem.appendChild(label);
promptContainerElem.appendChild(prompt);
this.terminalElem.appendChild(promptContainerElem);
prompt.focus()
this.currentPrompt = prompt
this.promptsAndResponses.push(promptContainerElem)
}
initialize() {
this.resize()
this.show();
this.createPrompt();
}
resize() {
this.terminalElem.style.width = canvas.getBoundingClientRect().width - 40 + 'px';
this.terminalElem.style.height = canvas.getBoundingClientRect().height - 80 + 'px';
this.terminalElem.style.minHeight = canvas.getBoundingClientRect().width - 80 + 'px';
}
handlePrompt(promptText) {
this.commands.push(promptText);
this.determineResult(promptText);
this.createPrompt();
}
determineResult(promptText) {
var returnText
if (promptText === 'help') {
returnText = `Documented Commands:<br>
========================================<br>
help &nbsp&nbsp&nbsp&nbspShows the help screen<br>
about &nbsp&nbsp&nbspProvides background of the terminal<br>
clear &nbsp&nbsp&nbspClears the terminal<br>
echo &nbsp&nbsp&nbsp&nbspDisplay a line of text<br>
exit &nbsp&nbsp&nbsp&nbspExits the terminal<br>
history &nbspPrints command history<br>
<br>
Terminal Functionality:<br>
========================================<br>
Up Arrow - cycle through commands<br>
Down Arrow - cycle through commands<br>
Ctrl+c - discard current prompt<br>
Ctrl+d - exit<br>
`
} else if (promptText.split(" ")[0] == 'echo') {
promptText = promptText.replaceAll('"', '')
promptText = promptText.split(' ').slice(1)
returnText = promptText.join(' ')
} else if (promptText === 'history') {
returnText = this.commands.join('<br>')
} else if (promptText == 'exit') {
this.hide()
} else if (promptText == 'about') {
returnText = 'I built this terminal emulator in JavaScript. While the functionality is quite simple, I wanted to showcase my love for linux and working in the terminal. All actions that can be done in the main world like: looking at my portfolio, downloading my resume, or playing one of the games I made can be done through this terminal. <br><br> I also added some quality of life commands like clear, exit, echo and more for the fun of it. That\'s right! This is what I do for fun :)'
} else if (promptText == 'clear') {
this.clear()
} else if (['vim', 'nvim', 'nano', 'ed'].includes(promptText)) {
returnText = 'Did you really think I coded a text editor in here!?'
} else {
returnText = 'Unkown command, please type "help" for options'
}
if (returnText) {
var responseElem = document.createElement('span')
responseElem.innerHTML = returnText
this.terminalElem.appendChild(responseElem)
this.promptsAndResponses.push(responseElem)
}
}
clear() {
for (let i = 0; i < this.promptsAndResponses.length; i++) {
this.promptsAndResponses[i].style.display = "none";
}
}
getKeystroke() {
var self = this
_listener = function (event) {
console.log(event.code)
if (
["ArrowUp", "ArrowDown", "ControlLeft"].indexOf(event.code,) > -1
) {
event.preventDefault();
}
if (event.ctrlKey && event.key === 'd') {
event.preventDefault();
}
if (event.key === "ArrowUp") {
if (self.commands.length > 0) {
var nextCommandPosition = self.commandPosition - 1
if (nextCommandPosition < 0) {
nextCommandPosition = self.commands.length - 1
}
self.currentPrompt.value = self.commands[nextCommandPosition]
self.commandPosition = nextCommandPosition;
}
}
if (event.key === "ArrowDown") {
if (self.commands.length > 0) {
var nextCommandPosition = self.commandPosition + 1
if (nextCommandPosition > self.commands.length - 1) {
nextCommandPosition = 0
}
self.currentPrompt.value = self.commands[nextCommandPosition]
self.commandPosition = nextCommandPosition;
}
}
if (event.ctrlKey && event.key === 'c') {
self.createPrompt()
}
if (event.ctrlKey && event.key === 'd') {
self.hide()
}
}
document.addEventListener("keydown", _listener);
}
}