A Text Console in JavaScript

Below is a simple text console implemented in JavaScript. To see it in action, copy it into an .html file and open that file in a web browser that runs JavaScript. Or, for an online version, visit https://thiscouldbebetter.neocities.org/textconsole.html.

Click on the blank console window to select it, then start typing at the prompt (there’s currently no visible cursor). The typed text will appear in the console window. Press the Enter key to finish the line, after which the program will repeat the typed text back, and present another prompt.

Obviously, this program is not very exciting in and of itself. I wrote it as a first step towards emulating the workflow of a traditional text-based console (or “command-line”) application in client-side JavaScript.

TextConsole

<html>
<body>

<div id="divMain"></div>

<script type="text/javascript">

// main

function TextConsoleTest()
{
	this.main = function()
	{
		Globals.Instance.initialize
		(
			new TextConsole
			(
				10, // numberOfLines
				new Coords(320, 200) // sizeInPixels
			)
		);
	}
}

// classes 

function Coords(x, y)
{
	this.x = x;
	this.y = y;
}

function Globals()
{
	// do nothing
}
{
	Globals.Instance = new Globals();

	Globals.prototype.initialize = function(textConsole)
	{
		this.textConsole = textConsole;
		this.textConsole.initialize();
	}
}

function TextConsole(numberOfLines, sizeInPixels)
{
	this.numberOfLines = numberOfLines;
	this.sizeInPixels = sizeInPixels;

	this.characterHeightInPixels = this.sizeInPixels.y / this.numberOfLines;

	this.textLines = [];
	for (var y = 0; y < this.numberOfLines; y++)
	{
		this.textLines[y] = "";
	}
	this.indexOfTextLineCurrent = 0;
}
{
	// constants

	TextConsole.CharactersUnshifted = 
		"``````````" // 0-9
		+ "``````````" // 10-19
		+ "``````````" // 20-29
		+ "`` ```````" // 30-39
		+ "````````01" // 40-49
		+ "23456789``" // 50-59
		+ "`````abcde" // 60-69
		+ "fghijklmno" // 70-79
		+ "pqrstuvwxy" // 80-89
		+ "z`````````" // 9x
		+ "``````````" // 10x
		+ "``````````" // 11x
		+ "``````````" // 12x
		+ "``````````" // 13x
		+ "``````````" // 14x
		+ "``````````" // 15x
		+ "``````````" // 16x
		+ "``````````" // 17x
		+ "``````;=,-" // 18x
		+ "./````````" // 19x
		+ "``````````" // 20x
		+ "`````````[" // 21x
		+ "\\]'```````"; // 22x

	TextConsole.CharactersShifted =	
		"``````````" // 0-9
		+ "``````````" // 10-19
		+ "``````````" // 20-29
		+ "`` ```````" // 30-39
		+ "````````)!" // 40-49
		+ "@#$%^&*(``" // 50-59
		+ "`````ABCDE" // 60-69
		+ "FGHIJKLMNO" // 70-79
		+ "PQRSTUVWXY" // 80-89
		+ "Z`````````" // 9x
		+ "``````````" // 10x
		+ "``````````" // 11x
		+ "``````````" // 12x
		+ "``````````" // 13x
		+ "``````````" // 14x
		+ "``````````" // 15x
		+ "``````````" // 16x
		+ "``````````" // 17x
		+ "``````:+<_" // 18x
		+ ">?````````" // 19x
		+ "``````````" // 20x
		+ "`````````{" // 21x
		+ "|}\"```````"; // 22x

	// instance methods

	TextConsole.prototype.draw = function()
	{
		if (this.canvas == null)
		{
			this.canvas = document.createElement("canvas");
			this.canvas.width = this.sizeInPixels.x;
			this.canvas.height = this.sizeInPixels.y;

			this.graphics = this.canvas.getContext("2d");
			this.graphics.font = this.characterHeightInPixels + "px Arial";

			var divMain = document.getElementById("divMain");
			divMain.appendChild(this.canvas);
		}

		this.graphics.fillStyle = "Black";
		this.graphics.fillRect
		(
			0, 0,
			this.sizeInPixels.x,
			this.sizeInPixels.y
		);

		this.graphics.fillStyle = "Green";

		for (var y = 0; y < this.numberOfLines; y++)
		{
			var textLineIndex = this.indexOfTextLineCurrent + y + 1;
			if (textLineIndex >= this.numberOfLines)
			{
				textLineIndex -= this.numberOfLines;
			}
			var textLine = this.textLines[textLineIndex];
			this.graphics.fillText
			(
				textLine,
				this.characterHeightInPixels,
				y * this.characterHeightInPixels
			);
		}
	}

	TextConsole.prototype.initialize = function()
	{
		document.body.onkeydown = this.handleEventKeyDown.bind(this);
		this.textLineCurrentSet(">");
		this.update();
	}

	TextConsole.prototype.textLineCurrent = function()
	{
		return this.textLines[this.indexOfTextLineCurrent];
	}

	TextConsole.prototype.textLineCurrentAdvance = function(textLineToAppend)
	{
		this.indexOfTextLineCurrent++;
		if (this.indexOfTextLineCurrent >= this.numberOfLines)
		{
			this.indexOfTextLineCurrent = 0;
		}
		this.textLineCurrentSet(">");
	}

	TextConsole.prototype.textLineCurrentAppend = function(textToAppend)
	{
		this.textLineCurrentSet(this.textLineCurrent() + textToAppend);
	}

	TextConsole.prototype.textLineCurrentBackspace = function()
	{
		var textLine = this.textLineCurrent();
		if (textLine.length > 1)
		{
			textLine = textLine.substr(0, textLine.length - 1);
		}
		this.textLineCurrentSet(textLine);

	}

	TextConsole.prototype.textLineCurrentSet = function(value)
	{
		this.textLines[this.indexOfTextLineCurrent] = value;
	}

	TextConsole.prototype.textLineWrite = function(textLineToWrite)
	{
		this.textLineCurrentSet(textLineToWrite);
		this.textLineCurrentAdvance();
	}

	TextConsole.prototype.update = function()
	{
		this.draw();
	}

	// events

	TextConsole.prototype.handleEventKeyDown = function(event)
	{
		event.preventDefault();

		var keyCode = event.keyCode;
		var isShiftKeyPressed = event.shiftKey;

		if (keyCode == 8) // backspace
		{
			this.textLineCurrentBackspace();
		}
		else if (keyCode == 13) // return
		{
			var textLineEntered = this.textLineCurrent();
			this.textLineCurrentAdvance();

			var textLineEchoed = "Echo: " + textLineEntered.substr(1);
			this.textLineWrite(textLineEchoed);
		}
		else if (keyCode == 16) // shift
		{
			// do nothing
		}
		else 
		{
			var characterTable;

			if (isShiftKeyPressed == true)
			{
				characterTable = TextConsole.CharactersShifted;
			}
			else
			{
				characterTable = TextConsole.CharactersUnshifted;
			}

			var charForCode = characterTable[keyCode];
			if (charForCode != null && charForCode != "`")
			{
				this.textLineCurrentAppend(charForCode);
			}
		}

		this.update();
	}
}

// run

new TextConsoleTest().main();

</script>
</body>
</html>

Advertisements
This entry was posted in Uncategorized and tagged , , . Bookmark the permalink.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s