// A command-line interface emulator.
/**
* Creates a new command-line interface.
*
* @constructor
* @requires jQuery
* @param {Function} runner the function called on all the inputs. This function is passed both
* the inputs and a reference to the originating Cli.
*/
function Cli(runner) {
var that = this;
// HTML elements:
var top = $("
"),
output = $('
'),
holder = $('
'),
input = $('');
holder.append($(">"));
holder.append(input);
// Command history:
var history = [],
currentCommand = 0,
commandsShifted = false;
// The prompt that marks your input in the history:
var prompt = ">";
/**
* Input the given text to the command line. This is what happens when
* somebody enters some text. This pushes the text to the command history.
*
* @function
* @memberOf Cli
* @param {String} text the text to enter.
*/
this.input = function (text) {
history.push(text);
runner(text, that);
};
/**
* Sends the text currently in the input to the command line. This also
*
* @function
* @memberOf Cli
*/
this.send = function send() {
var value = that.getInput();
that.output(prompt + value, "in");
that.input(value);
if (commandsShifted) {
history.shift();
commandsShifted = false;
}
history.unshift(value);
currentCommand = -1;
that.setInput("");
};
/**
* Outputs the given text to the command line.
*
* @function
* @memberOf Cli
* @param {String} text the text to output. If this is falsey, nothing will happen.
* @param {String} [type] the type of output this is. This corresponds to a
* css class that determines how the line will be displayed.
*/
this.output = function (text, type) {
if (text) {
text = text.toString();
var line = $("
");
if (type) {
line.addClass(type);
}
line.addClass("line");
line.append(text.replace(/\n/gm, " "));
output.prepend(line);
}
};
/**
* Returns the current value of the input text box.
*
* @function
* @memberOf Cli
* @return {String} the text currently entered into the input text box.
*/
this.getInput = function () {
return input.val();
};
/**
* Sets the text displayed in the input text box without sending a command.
*
* @function
* @memberOf Cli
* @param {String} text the text for the input text box to display.
*/
this.setInput = function (text) {
input.val(text);
};
/**
* Returns the html element that contains the cli interface.
*
* @function
* @memberOf Cli
* @return {jQuery} the jQuery-extended div that contains everything.
*/
this.getElement = function () {
return top;
};
/**
* Tries to move the command history back one and returns the resulting
* command. If the history is empty, returns null and does not change
* anything.
*
* @function
* @return {null|String} the previous command in the history or null if the
* history is empty.
*/
function previousCommand() {
if (history.length > 0) {
if (currentCommand === -1) {
currentCommand = 1;
history.unshift(that.getInput());
} else if (currentCommand >= history.length) {
currentCommand = 0;
}
currentCommand++;
commandsShifted = true;
return(history[currentCommand]);
} else {
return null;
}
}
/**
* Tries to move the command history forward one and returns the resulting
* command. If the history is empty, returns null and changes nothing.
*
* @function
* @return {null|String} the resulting command or null if there is no
* history.
*/
function nextCommand() {
if (currentCommand > 1) {
currentCommand--;
return history[currentCommand - 1];
} else {
return null;
}
}
$("body").keydown(function (event) {
switch (event.keyCode) {
case 13 :// Enter
that.send();
break;
case 38 :// Up
input.val(previousCommand());
break;
case 40 :// Down
input.val(nextCommand());
break;
default :
// Do nothing!
break;
}
return;
});
top.append(holder);
top.append(output);
};