wash.js
LEGAL
WASH SE, the Web Application SHell - Simplified Edition
(C)2004,2008 psema4Technologies
Licensed under the LGPL v2.1
SYNOPSIS
<html>
<head><title>WASH: The Web Application SHell</title>
<script type="text/javascript" src="wash.js"></script>
<style type="text/css">.code,.data {display: none;}</style>
</head>
<body onload="window.Console = new WASH({show:true});">
<div id="myFile" class="code">alert('This is myFile!');</div>
<div id="myOtherFile" class="data">This is myOtherFile!</div>
</body>
</html>
ABOUT
WASH is a core component of the Atomic OS project. This implementation creates a small
(< 10Kb) console object - providing a simple command line interpreter and access to a
single-folder filesystem simulated using JavaScript, DOM, and CSS.
To add a WASH console to any web application simply reference this JavaScript file from the
applications' HTML source file and create an instance of the WASH object:
<script type="text/javascript" src="wash.js"></script>
<script type="text/javascript">
// Create a default panel (hidden!) ...
window.Console = new WASH();
// ... or show it ...
// window.Console = new WASH({show:true});
// ... or position and resize it
// window.Console = new WASH({top:0, left:0, width:400, height:200});
</script>
By default, WASH will be hidden when it's created. Hide & show the WASH panel with
Console.hide() and Console.show() respectively.
To add mini-programs to a web application, create a <DIV> in the HTML document's body with
an ID="{your-filename}" and a CLASS="code". Fill the <DIV> with JavaScript.
To add other microfiles, create a <DIV> in the HTML document's body with an
ID="{your-filename}" and a CLASS="data". Fill the <DIV> with text content.
AUTHOR
Scott Elcomb (psema4-at-gmail-dot-com)
SEE ALSO
http://www.psema4.com/
http://sourceforge.net/projects/atomos
*/
function WASH(optsObj) {
this.opts = (optsObj) ? optsObj : {};
this.init = function(optsObj) {
var opts = (optsObj) ? optsObj : {};
var top = (opts.top) ? opts.top : 20;
var left = (opts.left) ? opts.left : 20;
var width = (opts.width) ? opts.width : 800;
var height = (opts.height) ? opts.height : 500;
this.panel = document.createElement('div');
this.stdout = document.createElement('textarea');
this.stdin = document.createElement('input');
this.panel.id = 'PANEL';
this.panel.style.position = 'absolute';
this.panel.style.top = top + 'px';
this.panel.style.left = left + 'px';
this.panel.style.width = width + 'px';
this.panel.style.height = height + 'px';
this.panel.style.padding = '4px';
this.panel.style.backgroundColor = '#ddd';
this.panel.style.border = '2px outset #ddd';
if (opts && opts.show) {
this.panel.style.visibility = 'visible';
} else {
this.panel.style.visibility = 'hidden';
}
this.stdout.id = 'STDOUT';
this.stdout.style.width = '100%';
this.stdout.style.height = (height - 40) + 'px';
this.stdout.style.backgroundColor = '#ddd';
this.stdin.id = 'STDIN';
this.stdin.type = 'text';
this.stdin.style.width = '100%';
this.panel.appendChild(this.stdout);
this.panel.appendChild(this.stdin);
document.getElementsByTagName('body')[0].appendChild(this.panel);
this.panel.component = this;
this.stdin.onkeypress = this.panel.component.keyHandler;
this.print("Welcome to WASH SE, the Web Application SHell - Simplified Edition\n");
this.print("(C)2004,2008 psema4Technologies\n");
this.print("Licensed under the LGPL v2.1\n\n");
this.print("Type ? for help.\n\n");
if (opts && opts.show) { this.stdin.focus(); }
}
this.show = function() {
this.panel.style.visibility = 'visible';
this.stdin.focus();
}
this.hide = function() {
this.panel.style.visibility = 'hidden';
}
this.print = function(buf) {
this.stdout.value += buf;
this.stdout.scrollTop = this.stdout.scrollHeight;
}
this.keyHandler = function(evt) {
// NOTE: In this routine the keyword 'this' points to the element that received the event -
// not the WASH object.
var e = (evt) ? evt : window.event;
if (e.keyCode && e.keyCode === 13) {
var Console = this.parentNode.component;
if (Console) {
Console.exec(Console.stdin.value);
Console.stdin.value = '';
Console.print("\n");
} else {
alert('WASH.keyHandler(): NO CONSOLE!');
}
}
}
this.exec = function(cmdline) {
var argv = cmdline.split(/\s+/);
var cmd = (argv[0]) ? argv[0] : 'NOP';
var args = '';
for (var i=1; i<argv.length; i++) { args += argv[i] + ' '; }
args = args.replace(/\s+$/, '');
if (cmd.toLowerCase() === 'nop') { return; }
this.print(cmdline + "\n");
switch(cmd.toLowerCase()) {
case 'cat':
var microFile = document.getElementById(argv[1]);
if (microFile
&& (microFile.className === 'code'
|| microFile.className === 'data')
&& microFile.childNodes[0].nodeType === 3
) {
var code = microFile.childNodes[0].data + ''
code = code.replace(/</g, '<'); // fix html entities
this.print(code + "\n");
}
break;
case 'clear':
this.stdout.value = '';
break;
case 'echo':
this.print(args + "\n");
break;
case 'eval':
var retval = eval(args+'');
if (retval !== undefined) { this.print(retval + "\n"); }
break;
case 'go':
window.Console.print("Going to '" + argv[1] + "'\n");
window.location = argv[1];
break;
case '?':
case 'help':
this.print("WASH Builtins\n\n");
this.print(" [filename] .............. Read and execute (if possible) a microfile\n");
this.print(" cat [filename] .......... Dumps the contents of a microfile\n");
this.print(" clear ................... Clears the console output\n");
this.print(" echo [text] ............. Echoes [text] to the console output\n");
this.print(" eval [expression] ....... Evaluates a JavaScript [expression]\n");
this.print(" go [url] ................ Go to a new URL. Warning: Replaces this web page!\n");
this.print(" help, ? ................. Displays the WASH Builtins help screen\n");
this.print(" ls ...................... Lists microfiles in this HTML document\n");
this.print(" reboot .................. Reload the current URL. Warning for 'go' applies here too.\n");
break;
case 'ls':
var files = new Array();
var els = document.getElementsByTagName('div');
this.print("Listing microfiles:\n\n");
for (var i=0; i < els.length; i++) {
if (els[i].className === 'code' || els[i].className === 'data') { files.push(els[i]); }
}
for (var i=0; i < files.length; i++) {
Console.print(" " + files[i].id + "\n");
}
break;
case 'reboot':
window.location = window.location + '';
break;
default:
var microFile = document.getElementById(cmd);
if (microFile) {
if (microFile.className === 'code' && microFile.childNodes[0].nodeType === 3) {
var code = microFile.childNodes[0].data + ''
code = code.replace(/</g, '<'); // fix html entities
var retval = eval(code);
if (retval !== undefined) { this.print(retval + "\n"); }
} else {
this.print("Command not executable.\n");
}
} else {
this.print("Command not found.\n");
}
}
}
this.init(this.opts);
}