(function($) {
/* AnsiParse */
ansiparse = function (str) {
//
// I'm terrible at writing parsers.
//
var matchingControl = null,
matchingData = null,
matchingText = '',
ansiState = [],
result = [],
state = {},
eraseChar;
//
// General workflow for this thing is:
// \033\[33mText
// | | |
// | | matchingText
// | matchingData
// matchingControl
//
// In further steps we hope it's all going to be fine. It usually is.
//
//
// Erases a char from the output
//
eraseChar = function () {
var index, text;
if (matchingText.length) {
matchingText = matchingText.substr(0, matchingText.length - 1);
}
else if (result.length) {
index = result.length - 1;
text = result[index].text;
if (text.length === 1) {
//
// A result bit was fully deleted, pop it out to simplify the final output
//
result.pop();
}
else {
result[index].text = text.substr(0, text.length - 1);
}
}
};
for (var i = 0; i < str.length; i++) {
if (matchingControl != null) {
if (matchingControl == '\u001B' && str[i] == '\[') {
//
// We've matched full control code. Lets start matching formating data.
//
//
// "emit" matched text with correct state
//
if (matchingText) {
state.text = matchingText;
result.push(state);
state = {};
matchingText = "";
}
matchingControl = null;
matchingData = '';
}
else {
//
// We failed to match anything - most likely a bad control code. We
// go back to matching regular strings.
//
matchingText += matchingControl + str[i];
matchingControl = null;
}
continue;
}
else if (matchingData != null) {
if (str[i] == ';') {
//
// `;` separates many formatting codes, for example: `\033[33;43m`
// means that both `33` and `43` should be applied.
//
// TODO: this can be simplified by modifying state here.
//
ansiState.push(matchingData);
matchingData = '';
}
else if (str[i] == 'm') {
//
// `m` finished whole formatting code. We can proceed to matching
// formatted text.
//
ansiState.push(matchingData);
matchingData = null;
matchingText = '';
//
// Convert matched formatting data into user-friendly state object.
//
// TODO: DRY.
//
ansiState.forEach(function (ansiCode) {
if (ansiparse.foregroundColors[ansiCode]) {
state.foreground = ansiparse.foregroundColors[ansiCode];
}
else if (ansiparse.backgroundColors[ansiCode]) {
state.background = ansiparse.backgroundColors[ansiCode];
}
else if (ansiCode == 39) {
delete state.foreground;
}
else if (ansiCode == 49) {
delete state.background;
}
else if (ansiparse.styles[ansiCode]) {
state[ansiparse.styles[ansiCode]] = true;
}
else if (ansiCode == 22) {
state.bold = false;
}
else if (ansiCode == 23) {
state.italic = false;
}
else if (ansiCode == 24) {
state.underline = false;
}
});
ansiState = [];
}
else {
matchingData += str[i];
}
continue;
}
if (str[i] == '\u001B') {
matchingControl = str[i];
}
else if (str[i] == '\u0008') {
eraseChar();
}
else {
matchingText += str[i];
}
}
if (matchingText) {
state.text = matchingText + (matchingControl ? matchingControl : '');
result.push(state);
}
return result;
}
ansiparse.foregroundColors = {
'30': 'black',
'31': 'red',
'32': 'green',
'33': 'yellow',
'34': 'blue',
'35': 'magenta',
'36': 'cyan',
'37': 'white',
'90': 'grey'
};
ansiparse.backgroundColors = {
'40': 'black',
'41': 'red',
'42': 'green',
'43': 'yellow',
'44': 'blue',
'45': 'magenta',
'46': 'cyan',
'47': 'white'
};
ansiparse.styles = {
'1': 'bold',
'3': 'italic',
'4': 'underline'
};
if (typeof module == "object" && typeof window == "undefined") {
module.exports = ansiparse;
}
/* app */
var webconsole = {
history:[],
pointer:0,
query:$('#webconsole_query')
}
$('#rack-webconsole form').submit(function(e){
e.preventDefault();
});
// colors
var colors = {
'black': "#eeeeee",
'red': "#ff6c60",
'green': "#a8ff60",
'yellow': "#ffffb6",
'blue': "#96cbfe",
'magenta': "#ff73fd",
'cyan': "#c6c5fe",
'white': "#eeeeee"
}
var boldColors = {
'black': "#7c7c7c",
'red': "#ffb6b0",
'green': "#ceffac",
'yellow': "#ffffcb",
'blue': "#b5dcfe",
'magenta': "#ff9cfe",
'cyan': "#dfdffe",
'white': "#ffffff"
}
function subColor(color, elem)
{
if (color == undefined) color = 'white';
if (elem.bold && boldColors[color] != undefined) {
color = boldColors[color];
} else if (!elem.bold && colors[color] != undefined) {
color = colors[color];
}
return color;
}
function parseBashString(str, into)
{
$.each(ansiparse(str), function(idx, elem) {
if (elem.text.length == 1 && elem.text[0] == '\n') {
into.append("
");
return true;
}
var domElem = $('');
domElem.text(elem.text);
domElem.html(domElem.text().replace(/\n/g, "
"));
domElem.css('color', subColor(elem.foreground, elem));
if (elem.bold)
domElem.css('font-weight', 'bold');
if (elem.italic)
domElem.css('font-style', 'italic');
if (elem.underline)
domElem.css('text-decoration', 'underline');
if (elem.background)
domElem.css('background-color', subColor(elem.background, elem));
into.append(domElem);
});
}
$("#rack-webconsole form input").keyup(function(event) {
function escapeHTML(string) {
return(string.replace(/&/g,'&').
replace(/>/g,'>').
replace(/");
parseBashString(escapeHTML(data.prompt), result);
if (!data.multi_line) {
var mresult = $("