* Default IDs, support for some basic TextView/labels via MCI
This commit is contained in:
parent
8119c1688a
commit
1dff6a6906
|
@ -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]));
|
||||
}
|
||||
|
|
228
core/art.js
228
core/art.js
|
@ -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
|
||||
// -
|
||||
}
|
|
@ -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];
|
||||
|
|
|
@ -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));
|
||||
};
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
});
|
||||
};
|
||||
|
|
|
@ -39,6 +39,8 @@ function entryPoint(client) {
|
|||
return;
|
||||
}
|
||||
|
||||
console.log(mci);
|
||||
|
||||
user.authenticate('NuSkooler', 'password', client, function onAuth(isValid) {
|
||||
console.log(isValid);
|
||||
});
|
||||
|
|
Loading…
Reference in New Issue