A console for the Web written in completely in JavaScript. The console supports Web versions of some Linux commands. This work is based, in part, on earlier work by Eric Bidelman.
A Pen by Andrew Mitchell Barfield on CodePen.
A console for the Web written in completely in JavaScript. The console supports Web versions of some Linux commands. This work is based, in part, on earlier work by Eric Bidelman.
A Pen by Andrew Mitchell Barfield on CodePen.
This is the main script for the<br/>"HTML5 Web Terminal" pen. | |
<!-- See: http://codepen.io/AndrewBarfield/pen/qEqWMq --> |
var util = util || {}; | |
util.toArray = function(list) { | |
return Array.prototype.slice.call(list || [], 0); | |
}; | |
var Terminal = Terminal || function(cmdLineContainer, outputContainer) { | |
window.URL = window.URL || window.webkitURL; | |
window.requestFileSystem = window.requestFileSystem || window.webkitRequestFileSystem; | |
var cmdLine_ = document.querySelector(cmdLineContainer); | |
var output_ = document.querySelector(outputContainer); | |
const CMDS_ = [ | |
'cat', 'clear', 'date', 'echo', 'help', 'uname', 'whoami' | |
]; | |
var fs_ = null; | |
var cwd_ = null; | |
var history_ = []; | |
var histpos_ = 0; | |
var histtemp_ = 0; | |
window.addEventListener('click', function(e) { | |
cmdLine_.focus(); | |
}, false); | |
cmdLine_.addEventListener('click', inputTextClick_, false); | |
cmdLine_.addEventListener('keydown', historyHandler_, false); | |
cmdLine_.addEventListener('keydown', processNewCommand_, false); | |
// | |
function inputTextClick_(e) { | |
this.value = this.value; | |
} | |
// | |
function historyHandler_(e) { | |
if (history_.length) { | |
if (e.keyCode == 38 || e.keyCode == 40) { | |
if (history_[histpos_]) { | |
history_[histpos_] = this.value; | |
} else { | |
histtemp_ = this.value; | |
} | |
} | |
if (e.keyCode == 38) { // up | |
histpos_--; | |
if (histpos_ < 0) { | |
histpos_ = 0; | |
} | |
} else if (e.keyCode == 40) { // down | |
histpos_++; | |
if (histpos_ > history_.length) { | |
histpos_ = history_.length; | |
} | |
} | |
if (e.keyCode == 38 || e.keyCode == 40) { | |
this.value = history_[histpos_] ? history_[histpos_] : histtemp_; | |
this.value = this.value; // Sets cursor to end of input. | |
} | |
} | |
} | |
// | |
function processNewCommand_(e) { | |
if (e.keyCode == 9) { // tab | |
e.preventDefault(); | |
// TODO(ericbidelman): Implement tab suggest. | |
} else if (e.keyCode == 13) { // enter | |
// Save shell history. | |
if (this.value) { | |
history_[history_.length] = this.value; | |
histpos_ = history_.length; | |
} | |
// Duplicate current input and append to output section. | |
var line = this.parentNode.parentNode.cloneNode(true); | |
line.removeAttribute('id') | |
line.classList.add('line'); | |
var input = line.querySelector('input.cmdline'); | |
input.autofocus = false; | |
input.readOnly = true; | |
output_.appendChild(line); | |
// Parse out command, args, and trim off whitespace. | |
// TODO(ericbidelman): Support multiple comma separated commands. | |
if (this.value && this.value.trim()) { | |
var args = this.value.split(' ').filter(function(val, i) { | |
return val; | |
}); | |
var cmd = args[0].toLowerCase(); | |
args = args.splice(1); // Remove cmd from arg list. | |
} | |
switch (cmd) { | |
case 'cat': | |
var url = args.join(' '); | |
if (!url) { | |
output('Usage: ' + cmd + ' http://s.codepen.io/...'); | |
output('Example: ' + cmd + ' http://s.codepen.io/AndrewBarfield/pen/LEbPJx.js'); | |
break; | |
} | |
$.get( url, function(data) { | |
var encodedStr = data.replace(/[\u00A0-\u9999<>\&]/gim, function(i) { | |
return '&#'+i.charCodeAt(0)+';'; | |
}); | |
output('<pre>' + encodedStr + '</pre>'); | |
}); | |
break; | |
case 'clear': | |
output_.innerHTML = ''; | |
this.value = ''; | |
return; | |
case 'date': | |
output( new Date() ); | |
break; | |
case 'echo': | |
output( args.join(' ') ); | |
break; | |
case 'help': | |
output('<div class="ls-files">' + CMDS_.join('<br>') + '</div>'); | |
break; | |
case 'uname': | |
output(navigator.appVersion); | |
break; | |
case 'whoami': | |
var result = "<img src=\"" + codehelper_ip["Flag"]+ "\"><br><br>"; | |
for (var prop in codehelper_ip) | |
result += prop + ": " + codehelper_ip[prop] + "<br>"; | |
output(result); | |
break; | |
default: | |
if (cmd) { | |
output(cmd + ': command not found'); | |
} | |
}; | |
window.scrollTo(0, getDocHeight_()); | |
this.value = ''; // Clear/setup line for next input. | |
} | |
} | |
// | |
function formatColumns_(entries) { | |
var maxName = entries[0].name; | |
util.toArray(entries).forEach(function(entry, i) { | |
if (entry.name.length > maxName.length) { | |
maxName = entry.name; | |
} | |
}); | |
var height = entries.length <= 3 ? | |
'height: ' + (entries.length * 15) + 'px;' : ''; | |
// 12px monospace font yields ~7px screen width. | |
var colWidth = maxName.length * 7; | |
return ['<div class="ls-files" style="-webkit-column-width:', | |
colWidth, 'px;', height, '">']; | |
} | |
// | |
function output(html) { | |
output_.insertAdjacentHTML('beforeEnd', '<p>' + html + '</p>'); | |
} | |
// Cross-browser impl to get document's height. | |
function getDocHeight_() { | |
var d = document; | |
return Math.max( | |
Math.max(d.body.scrollHeight, d.documentElement.scrollHeight), | |
Math.max(d.body.offsetHeight, d.documentElement.offsetHeight), | |
Math.max(d.body.clientHeight, d.documentElement.clientHeight) | |
); | |
} | |
// | |
return { | |
initFS: function() { | |
output('<img align="left" src="http://www.w3.org/html/logo/downloads/HTML5_Badge_128.png" style="padding: 0px 10px 30px 0px"><h2>HTML5 Web Terminal</h2><p>' + new Date() + '</p><p>Enter "help" for more information.</p>'); | |
}, | |
output: output | |
} | |
}; |
/* latin */ | |
@font-face { | |
font-family: 'Roboto'; | |
font-style: normal; | |
font-weight: 400; | |
src: local('Roboto Regular'), local('Roboto-Regular'), url(http://fonts.gstatic.com/s/roboto/v14/fg2nPs59wPnJ0blURyMU3PesZW2xOQ-xsNqO47m55DA.woff2) format('woff2'); | |
unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2212, U+2215, U+E0FF, U+EFFD, U+F000; | |
} | |
body { | |
margin: 20px; | |
font: 40px/40px 'Roboto', sans-serif; | |
color:#fff; | |
background-color: #593f6b; | |
} |