Skip to content

Instantly share code, notes, and snippets.

@AndrewBarfield
Created December 31, 2014 16:52
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save AndrewBarfield/bd0ac9877aadb8a03510 to your computer and use it in GitHub Desktop.
Save AndrewBarfield/bd0ac9877aadb8a03510 to your computer and use it in GitHub Desktop.
HTML5 Web Terminal Script

HTML5 Web Terminal Script

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.

License.

This is the main script for the<br/>&quot;HTML5 Web Terminal&quot; 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;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment