* Default IDs, support for some basic TextView/labels via MCI

This commit is contained in:
NuSkooler 2014-10-27 21:58:34 -06:00
parent 8119c1688a
commit 1dff6a6906
6 changed files with 88 additions and 229 deletions

View File

@ -140,11 +140,12 @@ function ANSIEscapeParser(options) {
}
function parseMCI(buffer) {
var mciRe = /\%([A-Z]{2}[0-9]{1,2})(?:\(([0-9A-Z,]+)\))*/g;
var mciRe = /\%([A-Z]{2})([0-9]{1,2})?(?:\(([0-9A-Z,]+)\))*/g;
var pos = 0;
var match;
var mciCode;
var args;
var id;
do {
pos = mciRe.lastIndex;
@ -156,15 +157,16 @@ function ANSIEscapeParser(options) {
}
mciCode = match[1];
id = match[2] || null;
if(match[2]) {
args = match[2].split(',');
if(match[3]) {
args = match[3].split(',');
} else {
args = [];
}
self.emit('mci', mciCode, args);
self.emit('mci', mciCode, id, args);
self.emit('chunk', getProcessedMCI(match[0]));
}

View File

@ -416,33 +416,37 @@ function display(art, options, cb) {
var emitter = null;
var parseComplete = false;
parser.on('mci', function onMCI(mciCode, args) {
if(mci[mciCode]) {
mci[mciCode].focusColor = {
var generatedId = 100;
parser.on('mci', function onMCI(mciCode, id, args) {
id = id || generatedId++;
var mapItem = mciCode + id;
if(mci[mapItem]) {
mci[mapItem].focusColor = {
fg : parser.fgColor,
bg : parser.bgColor,
flags : parser.flags,
};
} else {
mci[mciCode] = {
mci[mapItem] = {
args : args,
color : {
fg : parser.fgColor,
bg : parser.bgColor,
flags : parser.flags,
},
code : mciCode.substr(0, 2),
id : mciCode.substr(2, 1), // :TODO: This NEEDs to read 01-99
code : mciCode,
id : parseInt(id, 10),
};
mciPosQueue.push(mciCode);
mciPosQueue.push(mapItem);
// :TODO: Move this out of the loop
if(!emitter) {
emitter = options.client.on('onPosition', function onPosition(pos) {
if(mciPosQueue.length > 0) {
var forMciCode = mciPosQueue.shift();
mci[forMciCode].position = pos;
var forMapItem = mciPosQueue.shift();
mci[forMapItem].position = pos;
if(parseComplete && 0 === mciPosQueue.length) {
cb(null, mci);
@ -451,7 +455,7 @@ function display(art, options, cb) {
});
}
options.client.term.write(ansi.queryPos());
options.client.term.write(ansi.queryPos());
}
});
@ -468,208 +472,4 @@ function display(art, options, cb) {
});
parser.parse(art);
}
ArtDisplayer.prototype.display = function(art, options) {
var client = this.client;
var self = this;
var cancelKeys = miscUtil.valueWithDefault(options.cancelKeys, []);
var pauseKeys = miscUtil.valueWithDefault(options.pauseKeys, []);
var pauseAtTermHeight = miscUtil.valueWithDefault(options.pauseAtTermHeight, false);
var canceled = false;
if(cancelKeys.length > 0 || pauseKeys.length > 0) {
var onDataKeyCheck = function(data) {
var key = String.fromCharCode(data[0]);
if(-1 !== cancelKeys.indexOf(key)) {
canceled = true;
removeDataListener();
}
};
client.on('data', onDataKeyCheck);
}
function removeDataListener() {
client.removeListener('data', onDataKeyCheck);
}
//
// Try to split lines supporting various linebreaks we may encounter:
// - DOS \r\n
// - *nix \n
// - Old Apple \r
// - Unicode PARAGRAPH SEPARATOR (U+2029) and LINE SEPARATOR (U+2028)
//
// See also http://stackoverflow.com/questions/5034781/js-regex-to-split-by-line
//
var lines = art.split(/\r?\n|\r|[\u2028\u2029]/);
var i = 0;
var count = lines.length;
if(0 === count) {
return;
}
var termHeight = client.term.termHeight;
var aep = require('./ansi_escape_parser.js');
var p = new aep.ANSIEscapeParser();
var currentRow = 0;
var lastRow = 0;
p.on('row update', function onRowUpdated(row) {
currentRow = row;
});
//--------
var mci = {};
var mciPosQueue = [];
var parseComplete = false;
var emitter = null;
p.on('mci', function onMCI(mciCode, args) {
if(mci[mciCode]) {
mci[mciCode].fgColorAlt = p.fgColor;
mci[mciCode].bgColorAlt = p.bgColor;
mci[mciCode].flagsAlt = p.flags;
} else {
mci[mciCode] = {
args : args,
fgColor : p.fgColor,
bgColor : p.bgColor,
flags : p.flags,
};
mciPosQueue.push(mciCode);
if(!emitter) {
emitter = client.on('onPosition', function onPosition(pos) {
if(mciPosQueue.length > 0) {
var mc = mciPosQueue.shift();
console.log('position @ ' + mc + ': ' + pos);
mci[mc].pos = pos;
if(parseComplete && 0 === mciPosQueue.length) {
//console.log(mci);
var p1 = mci['LV1'].pos;
client.term.write(ansi.sgr(['red']));
var g = ansi.goto(p1);
console.log(g);
client.term.write(ansi.goto(p1[0], p1[1]));
client.term.write('Hello, World');
}
}
});
}
}
});
p.on('chunk', function onChunk(chunk) {
client.term.write(chunk);
});
p.on('complete', function onComplete() {
//console.log(mci);
parseComplete = true;
if(0 === mciPosQueue.length) {
console.log('mci from complete');
console.log(mci);
}
});
p.parse(art);
//-----------
/*
var line;
(function nextLine() {
if(i === count) {
self.emit('complete');
removeDataListener();
return;
}
if(canceled) {
self.emit('canceled');
removeDataListener();
return;
}
line = lines[i];
client.term.write(line + '\n');
p.parse(line + '\r\n');
i++;
if(pauseAtTermHeight && currentRow !== lastRow && (0 === currentRow % termHeight)) {
lastRow = currentRow;
client.getch(function onKey(k) {
nextLine();
});
} else {
setTimeout(nextLine, 20);
}
})();
*/
/*
(function nextLine() {
if(i === count) {
client.emit('complete', true);
removeDataListener();
return;
}
if(canceled) {
console.log('canceled');
client.emit('canceled');
removeDataListener();
return;
}
client.term.write(lines[i] + '\n');
//
// :TODO: support pauseAtTermHeight:
//
// - All cursor movement should be recorded for pauseAtTermHeight support &
// handling > termWidth scenarios
// - MCI codes should be processed
// - All other ANSI/CSI ignored
// - Count normal chars
//
//setTimeout(nextLine, 20);
//i++;
if(pauseAtTermHeight && i > 0 && (0 === i % termHeight)) {
console.log('pausing @ ' + i);
client.getch(function onKey() {
i++;
nextLine();
});
} else {
i++;
// :TODO: If local, use setTimeout(nextLine, 20) or so -- allow to pause/cancel
//process.nextTick(nextLine);
setTimeout(nextLine, 20);
}
})();
*/
};
//
// ANSI parser for quick scanning & handling
// of basic ANSI sequences that can be used for output to clients:
//
function ANSIOutputParser(ansi) {
//
// cb's
// - onMCI
// - onTermHeight
// -
}

View File

@ -4,6 +4,8 @@
var TextView = require('./text_view.js').TextView;
var EditTextView = require('./edit_text_view.js').EditTextView;
var ButtonView = require('./button_view.js').ButtonView;
var Config = require('./config.js').config;
var packageJson = require('../package.json');
var assert = require('assert');
exports.MCIViewFactory = MCIViewFactory;
@ -12,6 +14,16 @@ function MCIViewFactory(client) {
this.client = client;
}
MCIViewFactory.prototype.getPredefinedViewLabel = function(name) {
var label;
switch(name) {
case 'BN' : label = Config.bbsName; break;
case 'VL' : label = 'ENiGMA½ v' + packageJson.version; break;
}
return label;
};
MCIViewFactory.prototype.createFromMCI = function(mci) {
assert(mci.code);
assert(mci.id > 0);
@ -26,7 +38,24 @@ MCIViewFactory.prototype.createFromMCI = function(mci) {
};
switch(mci.code) {
case 'EV' :
case 'TL' :
if(mci.args.length > 0) {
options.textStyle = mci.args[0];
}
if(mci.args.length > 1) {
options.justify = mci.args[1];
}
if(mci.args.length > 2) {
options.maxLength = mci.args[2];
options.dimens = { width : options.maxLength };
}
view = new TextView(this.client, options);
break;
case 'ET' :
if(mci.args.length > 0) {
options.maxLength = mci.args[0];
options.dimens = { width : options.maxLength };
@ -39,6 +68,28 @@ MCIViewFactory.prototype.createFromMCI = function(mci) {
view = new EditTextView(this.client, options);
break;
case 'PL' :
if(mci.args.length > 0) {
options.text = this.getPredefinedViewLabel(mci.args[0]);
if(options.text) {
if(mci.args.length > 1) {
options.textStyle = mci.args[1];
}
if(mci.args.length > 2) {
options.justify = mci.args[2];
}
if(mci.args.length > 3) {
options.maxLength = mci.args[3];
options.dimens = { width : options.maxLength };
}
view = new TextView(this.client, options);
}
}
break;
case 'BV' :
if(mci.args.length > 0) {
options.text = mci.args[0];

View File

@ -19,8 +19,9 @@ function TextView(client, options) {
this.maxLength = this.options.maxLength;
}
this.textStyle = this.options.textStyle || 'normal';
this.multiLine = this.options.multiLine || false;
this.textStyle = this.options.textStyle || 'normal';
this.multiLine = this.options.multiLine || false;
this.fillChar = miscUtil.valueWithDefault(this.options.fillChar, ' ').substr(0, 1);
assert(!this.multiLine); // :TODO: not yet supported
@ -43,21 +44,20 @@ TextView.prototype.redraw = function() {
TextView.super_.prototype.redraw.call(this);
var color = this.hasFocus ? this.getFocusColor() : this.getColor();
//this.client.term.write(ansi.sgr(color.flags, color.fg, color.bg));
this.client.term.write(this.getANSIColor(color));
// :TODO: If using fillChar, don't just pad. switch to non-focus color & fill with |fillChar|
if(this.isPasswordTextStyle) {
this.client.term.write(strUtil.pad(new Array(this.text.length + 1).join(this.textMaskChar), this.dimens.width));
} else {
this.client.term.write(strUtil.pad(this.text, this.dimens.width));
this.client.term.write(strUtil.pad(this.text, this.dimens.width));
}
};
TextView.prototype.setFocus = function(focused) {
TextView.super_.prototype.setFocus.call(this, focused);
this.client.term.write(ansi.goto(this.position.x, this.position.y));
this.redraw();
this.client.term.write(ansi.goto(this.position.x, this.position.y + this.text.length));
};

View File

@ -116,10 +116,14 @@ ViewController.prototype.setViewOrder = function(order) {
if(0 === viewIdOrder.length) {
for(var id in this.views) {
viewIdOrder.push(id);
if(this.views[id].acceptsFocus) {
viewIdOrder.push(id);
}
}
viewIdOrder.sort();
viewIdOrder.sort(function intSort(a, b) {
return a - b;
});
}
var view;
@ -130,8 +134,7 @@ ViewController.prototype.setViewOrder = function(order) {
this.firstId = viewIdOrder[0];
var lastId = viewIdOrder[viewIdOrder.length - 1];
this.views[lastId].nextId = this.firstId;
this.views[lastId].nextId = this.firstId;
};
ViewController.prototype.loadFromMCIMap = function(mciMap) {
@ -145,6 +148,7 @@ ViewController.prototype.loadFromMCIMap = function(mciMap) {
if(view) {
view.on('action', self.onViewAction);
self.addView(view);
view.redraw();
}
});
};

View File

@ -39,6 +39,8 @@ function entryPoint(client) {
return;
}
console.log(mci);
user.authenticate('NuSkooler', 'password', client, function onAuth(isValid) {
console.log(isValid);
});