termwebui
old portfolio website with terminal interface
git clone https://9o.is/git/termwebui.git
index.html
(7939B)
1 <!DOCTYPE html>
2 <html lang="en-us">
3
4 <head>
5 <meta charset="utf-8">
6
7 <script language="JavaScript">
8 document.oncontextmenu =new Function("return false;")
9 </script>
10
11 <style type="text/css">
12
13 html, body, p, em, div, span, label, input, textarea, pre {
14 background-color: black;
15 color: white;
16 font-family: monospace !important;
17 font-size: 12px;
18
19 border: none !important;
20 margin: 0 !important;
21 padding: 0 !important;
22
23 -webkit-touch-callout: none;
24 -webkit-user-select: none;
25 -khtml-user-select: none;
26 -moz-user-select: none;
27 -ms-user-select: none;
28 user-select: none;
29 }
30
31 html, body, #terminal {
32 overflow: hidden;
33 }
34
35 #terminal {
36 width: 600px;
37 word-break: break-all;
38 }
39
40 #scroller {
41 position: relative;
42 width: 620px;
43 overflow-y: scroll;
44 }
45
46 .green { color: green;}
47 .blue { color: blue;}
48 .red { color: red;}
49 .orange { color: orange;}
50 .ls-item { margin-right: 15px !important; }
51
52 </style>
53 </head>
54
55 <body onselectstart="return false">
56 <div id="terminal">
57 <div id="scroller">
58 <div id="output"></div>
59 <div id="input"></div>
60 </div>
61 </div>
62
63 <script>
64
65 var Terminal = {
66 HOSTNAME: "jcabrra",
67 ROOT: "https://jsterm-jcabrra.c9.io",
68 PWD: "/",
69 PS1: "$ "
70 };
71
72 Terminal.interface = (function(){
73
74 var scroller = document.getElementById("scroller");
75
76 var setTitle = function() {
77 document.title = "["+Terminal.HOSTNAME+"] Terminal: "+Terminal.PWD;
78 };
79
80 setInterval(function() {
81 setTitle();
82 }, 100);
83
84 return {
85 scrollToBottom: function() {
86 scroller.scrollTop = scroller.scrollHeight;
87 },
88 resize: function() {
89 scroller.style.height = window.innerHeight + "px";
90 }
91 }
92 })();
93
94 Terminal.input = (function(){
95
96 var value = "";
97 var pointer = 0;
98
99
100 var display = (function(){
101
102 var display = document.getElementById("input");
103 var animation = "<span class='green'>"+String.fromCharCode(9608)+"</span>";
104 var cursor = true;
105 var cursorText = animation;
106
107 setInterval(function(){
108 display.innerHTML = Terminal.PS1 + (cursor ? cursorText : value);
109 }, 50);
110
111 setInterval(function(){
112 cursor = cursor ? false : true;
113 }, 500);
114
115 return {
116 resetCursor: function() {
117 cursor = true;
118 cursorText =
119 value.substring(0, pointer) +
120 animation + value.substring(pointer + 1, value.length);
121 }
122 }
123 })();
124
125 var history = (function(){
126
127 var history = [""];
128 var pointer = 0;
129
130 return {
131 reset: function(input) {
132 history.unshift("");
133 pointer = 0;
134 },
135 up: function() {
136 if(pointer < history.length - 1) {
137 pointer++;
138 }
139 },
140 down: function() {
141 if(pointer > 0) {
142 pointer--;
143 }
144 },
145 get: function() {
146 return history[pointer];
147 },
148 set: function(input) {
149 history[pointer] = input;
150 }
151 }
152 })();
153
154 var getHistory = function() {
155 var newValue = history.get();
156 value = newValue;
157 pointer = newValue.length;
158 display.resetCursor();
159 };
160
161 return {
162 set: function(char) {
163 value =
164 value.substring(0, pointer) + char +
165 value.substring(pointer, value.length);
166 pointer++;
167 history.set(value);
168 display.resetCursor();
169 },
170 delete: function() {
171 if(pointer > 0) {
172 value =
173 value.substring(0, pointer - 1) +
174 value.substring(pointer, value.length);
175 pointer--;
176 history.set(value);
177 display.resetCursor();
178 }
179 },
180 up: function() {
181 history.up();
182 getHistory();
183 },
184 down: function() {
185 history.down();
186 getHistory();
187 },
188 left: function() {
189 if(pointer > 0) {
190 pointer--;
191 display.resetCursor();
192 }
193 },
194 right: function() {
195 if(pointer <= value.length) {
196 pointer++;
197 display.resetCursor();
198 }
199 },
200 reset: function() {
201 value = "";
202 pointer = 0;
203 display.resetCursor();
204 history.reset();
205 },
206 value: function() {
207 return value;
208 }
209 }
210 })();
211
212 Terminal.output = (function(){
213
214 var display = document.getElementById("output");
215
216 return {
217 commit: function(text) {
218 var out = document.createElement("div");
219 out.innerHTML = text;
220 display.appendChild(out);
221 }
222 }
223 })();
224
225 Terminal.cmd = (function(){
226
227 var commands = [];
228
229 var valid = function(cmd) {
230 var fn = ["name", "exec"];
231
232 for(var i=0; i<fn.length;i++) {
233 if(!cmd[fn[i]]) {
234 return false;
235 }
236 }
237 return true;
238 };
239
240 var find = function(name) {
241 for(var i=0; i<commands.length;i++) {
242 if(commands[i].name === name) {
243 return commands[i];
244 }
245 }
246 };
247
248 return {
249 register: function(cmd) {
250 if(valid(cmd)) {
251 commands.push(cmd);
252 }
253 },
254 execute: function(command) {
255 var values = command.split(" ");
256 var cmd = find(values[0]);
257 if(typeof cmd !== 'undefined') {
258 cmd.exec(values);
259 }
260 }
261 }
262 })();
263
264 (function(){
265 var banner = {
266 name: 'banner',
267 exec: function() {
268 var value = "My Banner!\nYeah!"
269 Terminal.output.commit(value);
270 }
271 };
272
273 Terminal.cmd.register(banner);
274 })();
275
276 (function(){
277 var date = {
278 name: 'date',
279 exec: function() {
280 var value = new Date().toString()
281 Terminal.output.commit(value);
282 }
283 };
284
285 Terminal.cmd.register(date);
286 })();
287
288 (function(){
289 var pwd = {
290 name: 'pwd',
291 exec: function() {
292 Terminal.output.commit(Terminal.PWD);
293 }
294 };
295
296 Terminal.cmd.register(pwd);
297 })();
298
299 (function(){
300 var img = {
301 name: 'img',
302 exec: function() {
303 // TODO: http://thecodeplayer.com/walkthrough/cool-ascii-animation-using-an-image-sprite-canvas-and-javascript
304 }
305 };
306
307 Terminal.cmd.register(img);
308 })();
309
310 (function(){
311 var ls = {
312 name: 'ls',
313 exec: function() {
314 var xhr = new XMLHttpRequest();
315 xhr.onreadystatechange = function() {
316 if (xhr.readyState === 4 && xhr.status === 200) {
317 var obj = null;
318 try {
319 console.log(xhr.responseText);
320 obj = JSON.parse(xhr.responseText);
321 } catch(e) {
322 console.error('The server returned JSON but contains an error: '+e);
323 } finally {
324 var value = "";
325
326 var dir_len = obj.directories.length;
327 for(var i=0; i<dir_len; i++) {
328 value += "<span class='ls-item orange'>" +
329 obj.directories[i] + "</span>";
330 }
331
332 var files_len = obj.files.length;
333 for(var i=0; i<files_len; i++) {
334 value += "<span class='ls-item'>" +
335 obj.files[i] + "</span>";
336 }
337
338 Terminal.output.commit(value);
339 }
340 }
341 };
342 xhr.setRequestHeader("If-Modified-Since", "Sat, 1 Jan 2005 00:00:00 GMT");
343 xhr.open('GET', Terminal.ROOT + Terminal.PWD + ".ls", true);
344 xhr.send(null);
345 }
346 };
347
348 Terminal.cmd.register(ls);
349 })();
350
351 (function(){
352 var cat = {
353 name: 'cat',
354 exec: function(values) {
355 var xhr = new XMLHttpRequest();
356 xhr.onreadystatechange = function() {
357 if (xhr.readyState === 4 && xhr.status === 200) {
358 Terminal.output.commit(xhr.responseText);
359 }
360 }
361 xhr.open('GET', Terminal.ROOT + Terminal.PWD + values[1], true);
362 xhr.setRequestHeader("Content-Type", "text/plain; charset=UTF-8");
363 xhr.send(null);
364 }
365 };
366
367 Terminal.cmd.register(cat);
368 })();
369
370 // cd (url should reflect pwd)
371
372 Terminal.filesystem = (function(){
373
374
375 return {
376
377 }
378 })();
379
380
381 window.onkeypress = function(event) {
382 event.preventDefault();
383
384 switch(event.keyCode) {
385 case 13: // [Enter]
386 var value = Terminal.input.value();
387 Terminal.input.reset();
388 Terminal.output.commit(Terminal.PS1 + value);
389 Terminal.cmd.execute(value);
390 break;
391 case 8: // [backspace]
392 Terminal.input.delete();
393 break;
394 case 37: // [left arrow]
395 Terminal.input.left();
396 break;
397 case 38: // [up arrow]
398 Terminal.input.up();
399 break;
400 case 39: // [right arrow]
401 Terminal.input.right();
402 break;
403 case 40: // [down arrow]
404 Terminal.input.down();
405 break;
406 default:
407 var char = event.charCode;
408 if(char > 31 && char < 127) {
409 char = String.fromCharCode(char);
410 Terminal.input.set(char);
411 }
412 break;
413 }
414
415 Terminal.interface.scrollToBottom();
416 }
417
418 window.onload = function() {
419 Terminal.interface.resize();
420 };
421
422 window.onresize = function(event) {
423 Terminal.interface.resize();
424 };
425
426 </script>
427
428 </body>
429 </html>