|
| 1 | +document.addEventListener('DOMContentLoaded', () => { |
| 2 | + const terminal = document.querySelector('.terminal'); |
| 3 | + const maximizeButton = document.querySelector('.maximize'); |
| 4 | + const terminalBody = document.getElementById('terminal-body'); |
| 5 | + let currentUser = 'user'; // Default user, will be updated on page load |
| 6 | + let currentHostname = 'localhost'; // Default hostname, will be updated on page load |
| 7 | + let currentCwd = '~'; // Default working directory, will be updated on page load |
| 8 | + let streamRequest = null; // Track the current request for cancellation |
| 9 | + |
| 10 | + // Maximize button functionality |
| 11 | + maximizeButton.addEventListener('click', () => { |
| 12 | + terminal.classList.toggle('terminal--fullscreen'); |
| 13 | + }); |
| 14 | + |
| 15 | + // Function to fetch initial user and cwd |
| 16 | + function fetchInitialInfo() { |
| 17 | + const initialRequest = new XMLHttpRequest(); |
| 18 | + initialRequest.open('POST', 'execute.php', true); |
| 19 | + initialRequest.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded'); |
| 20 | + initialRequest.onreadystatechange = function () { |
| 21 | + if (this.readyState === 4 && this.status === 200) { |
| 22 | + const response = JSON.parse(this.responseText); |
| 23 | + currentUser = response.user; |
| 24 | + currentHostname = response.hostname; |
| 25 | + currentCwd = response.cwd; |
| 26 | + addInputField(); // Show prompt after loading |
| 27 | + } |
| 28 | + }; |
| 29 | + initialRequest.send('action=initial'); |
| 30 | + } |
| 31 | + |
| 32 | + // Function to send the command to the backend |
| 33 | + function processCommand(command) { |
| 34 | + const promptLine = document.createElement('div'); |
| 35 | + promptLine.classList.add('output'); |
| 36 | + promptLine.innerHTML = `<span class="prompt">${currentUser}@${currentHostname} ${currentCwd} %</span> ${command}`; |
| 37 | + terminalBody.appendChild(promptLine); |
| 38 | + |
| 39 | + removeInputField(); |
| 40 | + |
| 41 | + streamRequest = new XMLHttpRequest(); |
| 42 | + streamRequest.open('POST', 'execute.php', true); |
| 43 | + streamRequest.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded'); |
| 44 | + |
| 45 | + let lastProcessedIndex = 0; |
| 46 | + |
| 47 | + streamRequest.onreadystatechange = function () { |
| 48 | + if (this.readyState === 3 || this.readyState === 4) { |
| 49 | + const newData = this.responseText.substring(lastProcessedIndex); |
| 50 | + processResponse(newData); |
| 51 | + lastProcessedIndex = this.responseText.length; |
| 52 | + } |
| 53 | + |
| 54 | + if (this.readyState === 4) { |
| 55 | + addInputField(); |
| 56 | + } |
| 57 | + }; |
| 58 | + |
| 59 | + streamRequest.send(`command=${encodeURIComponent(command)}&action=run`); |
| 60 | + } |
| 61 | + |
| 62 | + // Function to process the received response and output to the terminal |
| 63 | + function processResponse(responseText) { |
| 64 | + const lines = responseText.trim().split('\n'); |
| 65 | + |
| 66 | + lines.forEach((line) => { |
| 67 | + try { |
| 68 | + const response = JSON.parse(line); |
| 69 | + |
| 70 | + if (response.user && response.cwd && response.hostname) { |
| 71 | + currentUser = response.user; |
| 72 | + currentHostname = response.hostname; |
| 73 | + currentCwd = response.cwd; |
| 74 | + } |
| 75 | + |
| 76 | + if (response.output) { |
| 77 | + const resultLine = document.createElement('div'); |
| 78 | + resultLine.classList.add('output'); |
| 79 | + resultLine.innerHTML = response.output.replace(/\n/g, '<br>'); |
| 80 | + terminalBody.appendChild(resultLine); |
| 81 | + terminalBody.scrollTop = terminalBody.scrollHeight; |
| 82 | + } |
| 83 | + } catch (e) { |
| 84 | + console.error("Error parsing JSON: ", line); |
| 85 | + } |
| 86 | + }); |
| 87 | + } |
| 88 | + |
| 89 | + function addInputField() { |
| 90 | + const inputLine = document.createElement('div'); |
| 91 | + inputLine.classList.add('input-line'); |
| 92 | + inputLine.innerHTML = `<span class="prompt">${currentUser}@${currentHostname} ${currentCwd} %</span> <input type="text" class="input" id="terminal-input" autofocus>`; |
| 93 | + |
| 94 | + terminalBody.appendChild(inputLine); |
| 95 | + terminalBody.scrollTop = terminalBody.scrollHeight; |
| 96 | + |
| 97 | + const newInput = document.getElementById('terminal-input'); |
| 98 | + newInput.focus(); |
| 99 | + newInput.addEventListener('keydown', (e) => { |
| 100 | + if (e.key === 'Enter') { |
| 101 | + const command = newInput.value.trim(); |
| 102 | + if (command) { |
| 103 | + processCommand(command); |
| 104 | + } |
| 105 | + newInput.value = ''; |
| 106 | + } |
| 107 | + if (e.key === 'c' && (e.ctrlKey || e.metaKey)) { |
| 108 | + killProcess(); |
| 109 | + } |
| 110 | + }); |
| 111 | + } |
| 112 | + |
| 113 | + function removeInputField() { |
| 114 | + const existingInput = document.querySelector('.input-line'); |
| 115 | + if (existingInput) { |
| 116 | + terminalBody.removeChild(existingInput); |
| 117 | + } |
| 118 | + } |
| 119 | + |
| 120 | + function killProcess() { |
| 121 | + if (streamRequest) { |
| 122 | + const killRequest = new XMLHttpRequest(); |
| 123 | + killRequest.open('POST', 'execute.php', true); |
| 124 | + killRequest.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded'); |
| 125 | + killRequest.onreadystatechange = function () { |
| 126 | + if (this.readyState === 4 && this.status === 200) { |
| 127 | + const response = JSON.parse(this.responseText); |
| 128 | + const resultLine = document.createElement('div'); |
| 129 | + resultLine.classList.add('output'); |
| 130 | + resultLine.innerHTML = `<span style="color: red;">${response.output}</span>`; |
| 131 | + terminalBody.appendChild(resultLine); |
| 132 | + terminalBody.scrollTop = terminalBody.scrollHeight; |
| 133 | + addInputField(); |
| 134 | + } |
| 135 | + }; |
| 136 | + killRequest.send('action=kill'); |
| 137 | + } |
| 138 | + } |
| 139 | + |
| 140 | + // Fetch initial info and add input field |
| 141 | + fetchInitialInfo(); |
| 142 | +}); |
0 commit comments