WIP: Using new page object, frames stored and retrieved in msgbase, code cleanup, more optimisations needed
This commit is contained in:
594
load/session/ansitex.js
Normal file
594
load/session/ansitex.js
Normal file
@@ -0,0 +1,594 @@
|
||||
const SESSION_ANSITEX = (1<<1);
|
||||
const SESSION_EXT = 'tex';
|
||||
|
||||
const ANSI_FRAME_WIDTH = 80;
|
||||
const ANSI_FRAME_HEIGHT = 22;
|
||||
const ANSI_FRAME_PROVIDER_LENGTH = 55;
|
||||
const ANSI_FRAME_PAGE_LENGTH = 13;
|
||||
const ANSI_FRAME_COST_LENGTH = 10;
|
||||
const ANSI_FRAME_ATTR_LENGTH = 0; // Space that an attribute takes
|
||||
|
||||
/**
|
||||
* This function converts ANSI text into an array of attributes
|
||||
*
|
||||
* We include the attribute for every character, so that if a window is placed on top of this window, the edges
|
||||
* render correctly.
|
||||
*
|
||||
* @param contents - Our ANSI content to convert
|
||||
* @param width - The width before wrapping to the next line
|
||||
* @param yoffset - fields offset as discovered
|
||||
* @param xoffset - fields offset as discovered
|
||||
* @param debug - Enable debug mode
|
||||
*/
|
||||
function anstoattrs(contents,width,yoffset,xoffset,debug) {
|
||||
if (debug)
|
||||
writeln('DEBUG active: '+debug);
|
||||
|
||||
lines = (''+contents).split(/\r\n/);
|
||||
|
||||
var i = 0;
|
||||
var bg = BG_BLACK;
|
||||
var fg = LIGHTGRAY;
|
||||
var attr = fg + bg + i;
|
||||
|
||||
var y = 0;
|
||||
// Saving cursor positions
|
||||
var saved = {};
|
||||
|
||||
var frame = {
|
||||
content: [],
|
||||
dynamic_fields: [],
|
||||
input_fields: [],
|
||||
};
|
||||
|
||||
// @todo temp hack, rework ansi variable - perhaps have a function that converts an attribute back into an ANSI sequence
|
||||
var ansi = { i: 0, f: 37, b: 40 };
|
||||
|
||||
while (lines.length > 0) {
|
||||
var x = 0;
|
||||
var line = lines.shift();
|
||||
|
||||
if ((debug !== undefined) && (y > debug)) {
|
||||
exit(1);
|
||||
}
|
||||
|
||||
if (debug) {
|
||||
log(LOG_DEBUG,'y:'+y);
|
||||
log(LOG_DEBUG,'line:'+line);
|
||||
}
|
||||
|
||||
while (line.length > 0) {
|
||||
/* parse an attribute sequence*/
|
||||
var m = line.match(/^\x1b\[((\d+)(;?(\d+))*)+m/);
|
||||
if (m !== null) {
|
||||
line = line.substr(m.shift().length);
|
||||
m = m.shift().split(';').sort(function(a,b) { return Number(a) < Number(b) ? -1 : 1; });
|
||||
|
||||
if ((debug !== undefined) && debug === y) {
|
||||
//writeln();
|
||||
log(LOG_DEBUG,'m:'+JSON.stringify(m));
|
||||
}
|
||||
|
||||
// Reset
|
||||
if (Number(m[0]) === 0) {
|
||||
bg = BG_BLACK;
|
||||
fg = LIGHTGRAY;
|
||||
i = 0;
|
||||
ansi = { i:0, b:37, f:40};
|
||||
m.shift();
|
||||
|
||||
if (debug)
|
||||
log(LOG_DEBUG,' - RESET');
|
||||
}
|
||||
|
||||
// High Intensity
|
||||
if (Number(m[0]) === 1) {
|
||||
i += (((i === 0) || (i === BLINK)) ? HIGH : 0);
|
||||
m.shift();
|
||||
ansi.i = 1;
|
||||
|
||||
if (debug && (debug === y))
|
||||
writeln('fg:'+fg+', bg:'+bg+' i:'+i);
|
||||
}
|
||||
|
||||
// Blink
|
||||
if (Number(m[0]) === 5) {
|
||||
i += (((i === 0) || (i === HIGH)) ? BLINK : 0);
|
||||
m.shift();
|
||||
}
|
||||
|
||||
// Foreground
|
||||
if ((Number(m[0]) >= 30) && (Number(m[0]) <= 37)) {
|
||||
ansi.f = Number(m[0]);
|
||||
|
||||
switch(Number(m.shift())) {
|
||||
case 30:
|
||||
fg = BLACK;
|
||||
break;
|
||||
|
||||
case 31:
|
||||
fg = RED;
|
||||
break;
|
||||
|
||||
case 32:
|
||||
fg = GREEN;
|
||||
break;
|
||||
|
||||
case 33:
|
||||
fg = BROWN;
|
||||
break;
|
||||
|
||||
case 34:
|
||||
fg = BLUE;
|
||||
break;
|
||||
|
||||
case 35:
|
||||
fg = MAGENTA;
|
||||
break;
|
||||
|
||||
case 36:
|
||||
fg = CYAN;
|
||||
break;
|
||||
|
||||
case 37:
|
||||
fg = LIGHTGRAY;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Background
|
||||
if ((Number(m[0]) >= 40) && (Number(m[0]) <= 47)) {
|
||||
ansi.b = Number(m[0]);
|
||||
|
||||
switch (Number(m.shift())) {
|
||||
case 40:
|
||||
bg = BG_BLACK;
|
||||
break;
|
||||
|
||||
case 41:
|
||||
bg = BG_RED;
|
||||
break;
|
||||
|
||||
case 42:
|
||||
bg = BG_GREEN;
|
||||
break;
|
||||
|
||||
case 43:
|
||||
bg = BG_BROWN;
|
||||
break;
|
||||
|
||||
case 44:
|
||||
bg = BG_BLUE;
|
||||
break;
|
||||
|
||||
case 45:
|
||||
bg = BG_MAGENTA;
|
||||
break;
|
||||
|
||||
case 46:
|
||||
bg = BG_CYAN;
|
||||
break;
|
||||
|
||||
case 47:
|
||||
bg = BG_LIGHTGRAY;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (debug) {
|
||||
log(LOG_DEBUG,'fg:'+fg+', bg:'+bg+' i:'+i);
|
||||
log(LOG_DEBUG,'ansi:'+JSON.stringify(ansi));
|
||||
}
|
||||
|
||||
attr = bg + fg + i;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (debug)
|
||||
log(LOG_DEBUG,'= Current attr:'+attr);
|
||||
|
||||
/* parse absolute character position */
|
||||
var m = line.match(/^\x1b\[(\d*);?(\d*)[Hf]/);
|
||||
if (m !== null) {
|
||||
line = line.substr(m.shift().length);
|
||||
|
||||
if (m.length === 0) {
|
||||
x = 0;
|
||||
y = 0;
|
||||
|
||||
} else {
|
||||
if(m[0])
|
||||
y = Number(m.shift())-1;
|
||||
|
||||
if(m[0])
|
||||
x = Number(m.shift())-1;
|
||||
}
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
/* ignore a bullshit sequence */
|
||||
var n = line.match(/^\x1b\[\?7h/);
|
||||
if (n !== null) {
|
||||
line = line.substr(n.shift().length);
|
||||
continue;
|
||||
}
|
||||
|
||||
/* parse an up positional sequence */
|
||||
var n = line.match(/^\x1b\[(\d*)A/);
|
||||
if (n !== null) {
|
||||
line = line.substr(n.shift().length);
|
||||
|
||||
var chars = n.shift();
|
||||
|
||||
y -= (chars < 1) ? 0 : Number(chars);
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
/* parse a down positional sequence */
|
||||
var n = line.match(/^\x1b\[(\d*)B/);
|
||||
if (n !== null) {
|
||||
line = line.substr(n.shift().length);
|
||||
|
||||
var chars = n.shift();
|
||||
|
||||
y += (chars < 1) ? 0 : Number(chars);
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
/* parse a forward positional sequence */
|
||||
var n = line.match(/^\x1b\[(\d*)C/);
|
||||
if (n !== null) {
|
||||
line = line.substr(n.shift().length);
|
||||
|
||||
var chars = n.shift();
|
||||
|
||||
x += (chars < 1) ? 0 : Number(chars);
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
/* parse a backward positional sequence */
|
||||
var n = line.match(/^\x1b\[(\d*)D/);
|
||||
if (n !== null) {
|
||||
line = line.substr(n.shift().length);
|
||||
|
||||
var chars = n.shift()
|
||||
|
||||
x -= (chars < 1) ? 0 : Number(chars);
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
/* parse a clear screen sequence */
|
||||
var n = line.match(/^\x1b\[2J/);
|
||||
if (n !== null) {
|
||||
line = line.substr(n.shift().length);
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
/* parse save cursor sequence */
|
||||
var n = line.match(/^\x1b\[s/);
|
||||
if (n !== null) {
|
||||
line = line.substr(n.shift().length);
|
||||
saved.x = x;
|
||||
saved.y = y;
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
/* parse restore cursor sequence */
|
||||
var n = line.match(/^\x1b\[u/);
|
||||
if (n !== null) {
|
||||
line = line.substr(n.shift().length);
|
||||
x = saved.x;
|
||||
y = saved.y;
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
/* parse an input field */
|
||||
// Input field 'FIELD;valueTYPE;input char'
|
||||
// @todo remove the trailing ESC \ to end the field, just use a control code ^B \x02 (Start of Text) and ^C \x03
|
||||
var m = line.match(/^\x1b_(([A-Z]+;[0-9a-z]+)([;]?.+)?)\x1b\\/);
|
||||
if (m !== null) {
|
||||
log(LOG_DEBUG,'Got input field: '+JSON.stringify(m));
|
||||
log(LOG_DEBUG,'ansi:'+JSON.stringify(ansi));
|
||||
// full string that matched
|
||||
match = m.shift();
|
||||
|
||||
// thus, the rest of the line
|
||||
line = line.substr(match.length);
|
||||
//writeln('rest of line:'+JSON.stringify(line));
|
||||
|
||||
// We are interested in our field match
|
||||
var sos = m.shift().split(';');
|
||||
//writeln('sos:'+JSON.stringify(sos));
|
||||
|
||||
for (var num in sos) {
|
||||
switch (num) {
|
||||
// First value is the field name
|
||||
case '0':
|
||||
field = sos[num];
|
||||
break;
|
||||
|
||||
// Second value is the length/type of the field, nnX nn=size in chars, T=type (lower case)
|
||||
case '1':
|
||||
var c = sos[num].match(/([0-9]+)([a-z])/);
|
||||
if (! c) {
|
||||
log(LOG_ERROR,'SOS FAILED PARSING FIELD LENGTH/TYPE. ['+r+'x'+c+'] '+sos[num]);
|
||||
break;
|
||||
}
|
||||
|
||||
//log(LOG_DEBUG,'SOS ['+r+'x'+c+'] NUM CHARS: '+x[1]+', TYPE: '+x[2]);
|
||||
fieldlen = c[1];
|
||||
fieldtype = c[2];
|
||||
break;
|
||||
|
||||
// Third field is the char to to use
|
||||
case '2':
|
||||
fieldchar = sos[num];
|
||||
break;
|
||||
|
||||
default:
|
||||
log(LOG_ERROR,'IGNORING ADDITIONAL SOS FIELDS. ['+r+'x'+c+'] '+sos[num]);
|
||||
}
|
||||
}
|
||||
|
||||
// If we are padding our field with a char, we need to add that back to line
|
||||
// @todo validate if this goes beyond our width (and if scrolling not enabled)
|
||||
if (fieldlen)
|
||||
line = fieldchar.repeat(fieldlen)+line;
|
||||
|
||||
frame.input_fields.push({
|
||||
type: fieldtype,
|
||||
length: Number(fieldlen),
|
||||
char: fieldchar,
|
||||
name: field,
|
||||
attribute: JSON.parse(JSON.stringify(ansi)),
|
||||
x: Number(x+(xoffset !== undefined ? xoffset : 0)),
|
||||
y: Number(y+(yoffset !== undefined ? yoffset : 0)),
|
||||
value: '',
|
||||
});
|
||||
|
||||
log(LOG_DEBUG,'input_field:'+JSON.stringify(frame.input_fields.last));
|
||||
}
|
||||
|
||||
/* parse dynamic value field */
|
||||
// @todo remove the trailing ESC \ to end the field, just use a control code ie: ^E \x05 (Enquiry) or ^Z \x26 (Substitute)
|
||||
var m = line.match(/^\x1bX(([a-zA-Z._:^;]+[0-9]?;-?[0-9^;]+)([;]?[^;]+)?)\x1b\\/);
|
||||
if (m !== null) {
|
||||
// full string that matched
|
||||
match = m.shift();
|
||||
|
||||
// thus, the rest of the line
|
||||
line = line.substr(match.length);
|
||||
//writeln('rest of line:'+JSON.stringify(line));
|
||||
|
||||
// We are interested in our field match
|
||||
var df = m.shift().split(';');
|
||||
|
||||
log(LOG_DEBUG,'- DF found at ['+x+'x'+y+'], Field: '+df[0]+', Length: '+df[1]+', Pad:'+df[2]);
|
||||
// If we are padding our field with a char, we need to add that back to line
|
||||
// @todo validate if this goes beyond our width (and if scrolling not enabled)
|
||||
line = (df[2] ? df[2] : '_').repeat(Math.abs(df[1]))+line;
|
||||
|
||||
frame.dynamic_fields.push({
|
||||
name: df[0],
|
||||
length: df[1],
|
||||
pad: df[2],
|
||||
x: x+(xoffset !== undefined ? xoffset : 0),
|
||||
y: y+(yoffset !== undefined ? yoffset : 0),
|
||||
value: undefined,
|
||||
});
|
||||
}
|
||||
|
||||
/* set character and attribute */
|
||||
var ch = line[0];
|
||||
line = line.substr(1);
|
||||
|
||||
if (debug && debug === y) {
|
||||
log(LOG_DEBUG,'Got char: '+ch);
|
||||
//write(ch);
|
||||
}
|
||||
|
||||
/* validate position */
|
||||
if (y < 0)
|
||||
y = 0;
|
||||
if (x < 0)
|
||||
x = 0;
|
||||
|
||||
if (x >= width) {
|
||||
x = 0;
|
||||
y++;
|
||||
}
|
||||
|
||||
/* set character and attribute */
|
||||
if (! frame.content[y+1])
|
||||
frame.content[y+1]=[];
|
||||
|
||||
if (attr === null)
|
||||
throw new Error('Attribute is null?');
|
||||
|
||||
frame.content[y+1][x+1] = new Char(ch,attr);
|
||||
|
||||
x++;
|
||||
}
|
||||
|
||||
// If we got a BG_BLACK|LIGHTGRAY ESC [0m, but not character, we include it as it resets any background that was going on
|
||||
if ((attr === BG_BLACK|LIGHTGRAY) && frame.content[y+1] && (frame.content[y+1][x].__properties__.attr !== attr))
|
||||
frame.content[y+1][x+1] = new Char(undefined,attr);
|
||||
|
||||
y++;
|
||||
}
|
||||
|
||||
return frame;
|
||||
}
|
||||
|
||||
load('ansitex/load/session.js');
|
||||
|
||||
// Our frame object
|
||||
function SessionAnsitex() {
|
||||
Session.apply(this,arguments);
|
||||
|
||||
this.settings.MSG_SENDORNOT = '\1n\1h\1GKEY 1 TO SEND, 2 NOT TO SEND';
|
||||
this.settings.MSG_LOGON = '\1n\1h\1GKEY 1 TO LOGON, 2 TO RETURN';
|
||||
this.settings.MSG_SENT = '\1n\1h\1GMESSAGE SENT - KEY # TO CONTINUE';
|
||||
this.settings.MSG_NOTSENT = '\1n\1h\1GMESSAGE NOT SENT - KEY # TO CONTINUE';
|
||||
this.settings.ERR_NO_PARENT = '\1n\1h\1RPARENT FRAME DOESNT EXIST';
|
||||
this.settings.ERR_NOT_IMPLEMENTED = '\1n\1h\1RNOT IMPLEMENTED YET?';
|
||||
this.settings.ERR_ROUTE = '\1n\1h\1WMISTAKE? \1GTRY AGAIN OR TELL US ON *08';
|
||||
this.settings.ERR_METHOD_NOT_EXIST = '\1n\1h\1WMISTAKE? \1GTRY AGAIN OR TELL US ON *08';
|
||||
this.settings.ACCESS_DENIED = '\1n\1h\1RACCESS DENIED. MISTAKE? TRY AGAIN OR TELL US *08';
|
||||
this.settings.ALREADY_MEMBER = '\1n\1h\1RALREADY MEMBER OF CUG'
|
||||
this.settings.INACTIVITY = '\1n\1h\1RINACTIVITY ALERT, DISCONNECT PENDING...';
|
||||
this.settings.INACTIVE = '\1n\1h\1RINACTIVITY DISCONNECT';
|
||||
this.settings.NOACTION = '\1n\1h\1RNO ACTION PERFORMED';
|
||||
this.settings.BASESTAR = '\1N\1G\1H*';
|
||||
this.settings.INVALID_CODE = '\1n\1h\1RINVAID CODE, PLEASE TRY AGAIN *00';
|
||||
this.settings.TOKEN_EMAIL = '\1n\1h\1RTOKEN EMAILED TO YOU...';
|
||||
this.settings.TOKEN_SENT = '\1n\1h\1RTOKEN SENT, PLEASE ENTER TOKEN';
|
||||
this.settings.INVALID_EMAIL = '\1n\1h\1RINVAID EMAIL, PLEASE TRY AGAIN *00';
|
||||
this.settings.INVALID_UID = '\1n\1h\1RINVAID USER ID, PLEASE TRY AGAIN *00';
|
||||
this.settings.CANNOT_SEND_TOKEN = '\1n\1h\1RCANNOT SEND VALIDATION CODE, PLEASE TRY AGAIN *00';
|
||||
this.settings.USER_EXISTS = '\1n\1h\1RERROR USER EXISTS, PLEASE TRY AGAIN *00';
|
||||
this.settings.USER_CREATE_ERROR = '\1n\1h\1RERROR CREATING USER, PLEASE TRY AGAIN *00';
|
||||
this.settings.LOGIN_ERROR = '\1n\1h\1RERROR LOGGING IN, PLEASE TRY AGAIN *00';
|
||||
this.settings.CANCEL_MSG = '\1n\1h\1GPRESS 2 TO CANCEL';
|
||||
this.settings.SYS_ERROR = '\1n\1h\1RSYSTEM ERROR DETECTED - TRY AGAIN OR TELL US *08';
|
||||
this.settings.LOADING = '\1n\1h\1Kloading...';
|
||||
this.settings.PROCESSING = '\1n\1h\1Kprocessing...';
|
||||
|
||||
/**
|
||||
* Set the attribute at the current position
|
||||
*/
|
||||
this.attr = function(field) {
|
||||
write('\x1b['+field.i+';'+field.f+';'+field.b+'m');
|
||||
}
|
||||
|
||||
this.baselineClear = function(reposition) {
|
||||
this.cursorSave();
|
||||
this.gotoxy(0,24);
|
||||
this.cleareol();
|
||||
|
||||
if (! reposition)
|
||||
this.cursorRestore();
|
||||
}
|
||||
|
||||
/**
|
||||
* Send a message to the baseline.
|
||||
*
|
||||
* @param text
|
||||
* @param reposition
|
||||
*/
|
||||
this.baselineSend = function(text,reposition) {
|
||||
this.cursorSave();
|
||||
this.gotoxy(0,24);
|
||||
write(this.getMessage(text));
|
||||
this.cleareol();
|
||||
|
||||
if (! reposition)
|
||||
this.cursorRestore();
|
||||
}
|
||||
|
||||
/**
|
||||
* Turn off the cursor
|
||||
*/
|
||||
this.cursorOff = function() {
|
||||
write('\x1b[?25l');
|
||||
write('\x1b[24;0H');
|
||||
}
|
||||
|
||||
/**
|
||||
* Turn on cursor
|
||||
* @param x
|
||||
* @param y
|
||||
*/
|
||||
this.cursorOn = function(x,y) {
|
||||
write('\x1b[?25h');
|
||||
|
||||
if (x && y)
|
||||
this.gotoxy(x,y);
|
||||
}
|
||||
|
||||
this.cursorRestore = function() {
|
||||
write('\x1b[u');
|
||||
}
|
||||
|
||||
this.cursorSave = function() {
|
||||
write('\x1b[s');
|
||||
}
|
||||
|
||||
this.cleareol = function() {
|
||||
write('\x1b[0K');
|
||||
}
|
||||
|
||||
// Field backspace, that leaves the field filler char
|
||||
this.fieldbs = function(char) {
|
||||
write('\x1b[D'+char+'\x1b[D');
|
||||
}
|
||||
|
||||
/**
|
||||
* Position the cursor in a specific location
|
||||
*
|
||||
* @param x
|
||||
* @param y
|
||||
*/
|
||||
this.gotoxy = function(x,y) {
|
||||
write('\x1b['+y+';'+x+'H');
|
||||
}
|
||||
|
||||
this.qrcode = function(qr,subframe) {
|
||||
// SMALL Image
|
||||
var full = ascii(0xdb);
|
||||
var top = ascii(0xdf);
|
||||
var bot = ascii(0xdc);
|
||||
var blank = ' ';
|
||||
|
||||
var qrcode = '';
|
||||
|
||||
/*
|
||||
// Render the top line
|
||||
var line = ascii(27)+'[1;37m'+bot;
|
||||
for (var y = 0; y < qr.size; y++) {
|
||||
line += bot;
|
||||
}
|
||||
qrcode += line+bot+bot+ascii(27)+'[0m'+"\r\n";
|
||||
*/
|
||||
|
||||
// Render the body
|
||||
for (var x = -1; x < qr.size; x=x+2) {
|
||||
line = ascii(27)+'[1;37m'+full;
|
||||
|
||||
for (var y = 0; y < qr.size; y++) {
|
||||
// Top is white
|
||||
if (! ((x===-1)? 0 : qr.getModule(x, y))) {
|
||||
line += (qr.getModule(x+1, y)) ? top : full;
|
||||
|
||||
// Top is black
|
||||
} else {
|
||||
line += (qr.getModule(x+1, y)) ? blank : bot;
|
||||
}
|
||||
}
|
||||
|
||||
qrcode += line+full+ascii(27)+'[0m'+"\r\n";
|
||||
}
|
||||
|
||||
// Render the bottom
|
||||
line = ascii(27)+'[1;37m'+top;
|
||||
for (var y = 0; y < qr.size; y++) {
|
||||
line += top;
|
||||
}
|
||||
qrcode += line+top+ascii(27)+'[0m'+"\r\n";
|
||||
|
||||
ans2bin(fo.parse(qrcode),subframe);
|
||||
subframe.open();
|
||||
subframe.cycle();
|
||||
};
|
||||
}
|
||||
|
||||
SessionAnsitex.prototype = Session.prototype;
|
||||
SessionAnsitex.prototype.constructor = SessionAnsitex;
|
678
load/session/viewdata.js
Normal file
678
load/session/viewdata.js
Normal file
@@ -0,0 +1,678 @@
|
||||
var SESSION_VIEWDATA = (1<<2);
|
||||
var SESSION_EXT = 'vtx';
|
||||
|
||||
var VIEWDATA_FRAME_WIDTH = 40;
|
||||
var VIEWDATA_FRAME_HEIGHT = 22;
|
||||
var VIEWDATA_FRAME_PROVIDER_LENGTH = 23;
|
||||
var VIEWDATA_FRAME_PAGE_LENGTH = 11;
|
||||
var VIEWDATA_FRAME_COST_LENGTH = 6;
|
||||
const VIEWDATA_FRAME_ATTR_LENGTH = 0; // Space that an attribute takes
|
||||
|
||||
var VIEWDATA_LEFT = '\x08';
|
||||
var VIEWDATA_RIGHT = '\x09';
|
||||
var VIEWDATA_DOWN = '\x0a'; // \n
|
||||
var VIEWDATA_UP = '\x0b';
|
||||
var VIEWDATA_CLS = '\x0c';
|
||||
var VIEWDATA_CR = '\x0d'; // \r
|
||||
var VIEWDATA_CON = '\x11';
|
||||
var VIEWDATA_COFF = '\x14';
|
||||
var VIEWDATA_HOME = '\x1e';
|
||||
|
||||
var VIEWDATA_BLINK = '\x48';
|
||||
var VIEWDATA_STEADY = '\x49';
|
||||
var VIEWDATA_NORMAL = '\x4c';
|
||||
var VIEWDATA_DOUBLE = '\x4d';
|
||||
var VIEWDATA_CONCEAL = '\x58';
|
||||
var VIEWDATA_BLOCKS = '\x59';
|
||||
var VIEWDATA_SEPARATED = '\x5a';
|
||||
var VIEWDATA_BLACKBACK = '\x5c';
|
||||
var VIEWDATA_NEWBACK = '\x5d';
|
||||
var VIEWDATA_HOLD = '\x5e';
|
||||
var VIEWDATA_REVEAL = '\x5f';
|
||||
|
||||
var VIEWDATA_RED = '\x41';
|
||||
var VIEWDATA_GREEN = '\x42';
|
||||
var VIEWDATA_YELLOW = '\x43'; // C
|
||||
var VIEWDATA_BLUE = '\x44';
|
||||
var VIEWDATA_MAGENTA = '\x45';
|
||||
var VIEWDATA_CYAN = '\x46';
|
||||
var VIEWDATA_WHITE = '\x47';
|
||||
|
||||
var VIEWDATA_MOSIAC_RED = '\x51';
|
||||
var VIEWDATA_MOSIAC_GREEN = '\x52';
|
||||
var VIEWDATA_MOSIAC_YELLOW = '\x53';
|
||||
var VIEWDATA_MOSIAC_BLUE = '\x54';
|
||||
var VIEWDATA_MOSIAC_MAGENTA = '\x55';
|
||||
var VIEWDATA_MOSIAC_CYAN = '\x56';
|
||||
var VIEWDATA_MOSIAC_WHITE = '\x57'; // W
|
||||
|
||||
/* BINARY DUMP LEVEL 1 ATTRIBUTES */
|
||||
var VIEWDATA_BIN_RED = '\x01';
|
||||
var VIEWDATA_BIN_GREEN = '\x02';
|
||||
var VIEWDATA_BIN_YELLOW = '\x03';
|
||||
var VIEWDATA_BIN_BLUE = '\x04';
|
||||
var VIEWDATA_BIN_MAGENTA = '\x05';
|
||||
var VIEWDATA_BIN_CYAN = '\x06';
|
||||
var VIEWDATA_BIN_WHITE = '\x07';
|
||||
|
||||
/**
|
||||
* ViewData characters are 7bit (0x00-0x7f)
|
||||
*
|
||||
* Chars 0x00-0x1f are control characters (display attributes) and are sent to the terminal with 0x1b
|
||||
* + 0x00-0x07 are foreground colors
|
||||
* + 0x08-0x09 flash/steady
|
||||
* + 0x0a-0x0b end/start box (?) *
|
||||
* + 0x0c-0x0d normal/double height
|
||||
* + 0x0e-0x0f double width (?) *
|
||||
* + 0x10-0x17 are foreground graphics (mosiac) colors
|
||||
* + 0x18/0x1f conceal/reveal
|
||||
* + 0x19-0x1a solid/seperated graphics
|
||||
* + 0x1b unused
|
||||
* + 0x1c-1x1d Black/New Background (new background converts color foreground to background)
|
||||
* + 0x1e-0x1f graphics hold/release (enables changing color and repeats previous graphics char)
|
||||
* Chars 0x20-0x7f are normal printed ASCII chars
|
||||
* Chars 0x20-0x3f & 0x60-0x7f when activated with a MOSIAC color sends a 2x3 pixel character
|
||||
*
|
||||
* We can map these into cga_defs with the following amendments:
|
||||
* 0x00-0x0f = foreground/background colors (4 bits) (8 foreground/8 background colors)
|
||||
* 0x10 - mosiac (bit 4)
|
||||
* 0x20 - conceal (bit 5)
|
||||
* 0x40 - seperated graphics (bit 6)
|
||||
* 0x80 - flash (bit 7)
|
||||
* 0x100 - double height (bit 8)
|
||||
* 0x200 - hold (bit 9)
|
||||
* 0x400 - new background (bits 10/11)
|
||||
* 0x800 - black background (bits 10/11)
|
||||
* 0xc00 - unused (bits 10/11)
|
||||
* bits (12-15) unused
|
||||
*
|
||||
* @type {number}
|
||||
*/
|
||||
var MOSIAC = 0x10;
|
||||
|
||||
// Toggles
|
||||
var CONCEAL = 0x20;
|
||||
var REVEAL = 0x2000; // @temp Turns off Conceal
|
||||
|
||||
var SEPARATED = 0x40;
|
||||
var BLOCKS = 0x4000; // @temp Turns off Separated
|
||||
|
||||
var STEADY = 0x8000; // @temp (turn off flash)
|
||||
|
||||
var DOUBLE = 0x100;
|
||||
var NORMAL = 0x1000; // @temp Turns off Double Height
|
||||
|
||||
var HOLD = 0x200;
|
||||
var RELEASE = 0x20000; // @temp turns off Hold
|
||||
|
||||
var NEWBACK = 0x400;
|
||||
var BLACKBACK = 0x800;
|
||||
|
||||
/**
|
||||
* This function converts ANSI text into an array of attributes
|
||||
*
|
||||
* @param contents - Our ANSI content to convert
|
||||
* @param width - The width before wrapping to the next line
|
||||
* @param yoffset - fields offset as discovered
|
||||
* @param xoffset - fields offset as discovered
|
||||
* @param debug - Enable debug mode
|
||||
*/
|
||||
function bintoattrs(contents,width,yoffset,xoffset,debug) {
|
||||
if (debug)
|
||||
writeln('DEBUG active: '+debug);
|
||||
|
||||
lines = (''+contents).split(/\r\n/);
|
||||
|
||||
var i = 0;
|
||||
var bg = BG_BLACK;
|
||||
var fg = LIGHTGRAY;
|
||||
var attr = fg + bg + i;
|
||||
|
||||
// Attribute state on a new line
|
||||
var new_line = attr;
|
||||
|
||||
var y = 0;
|
||||
|
||||
var frame = {
|
||||
content: [],
|
||||
dynamic_fields: [],
|
||||
input_fields: [],
|
||||
};
|
||||
|
||||
// @todo temp hack, rework ansi variable - perhaps have a function that converts an attribute back into an ANSI sequence
|
||||
var ansi = { i: 0, f: 37, b: 40 };
|
||||
|
||||
while (lines.length > 0) {
|
||||
var x = 0;
|
||||
var line = lines.shift();
|
||||
|
||||
if ((debug !== undefined) && (y > debug)) {
|
||||
exit(1);
|
||||
}
|
||||
|
||||
if (debug) {
|
||||
log(LOG_DEBUG,'y:'+y);
|
||||
log(LOG_DEBUG,'line:'+line);
|
||||
write('y:'+y+', line:'+line);
|
||||
}
|
||||
|
||||
while (line.length > 0) {
|
||||
if (x >= width) {
|
||||
x = 0;
|
||||
// Each new line, we reset the attrs
|
||||
attr = new_line;
|
||||
y++;
|
||||
}
|
||||
//writeln('next ch:'+line[0].charCodeAt(0));
|
||||
|
||||
/* parse control codes */
|
||||
var m = line.match(/^([\x00-\x1f])/);
|
||||
if (m !== null) {
|
||||
line = line.substr(m[0].length);
|
||||
attr = 0;
|
||||
|
||||
match = m.shift().charCodeAt(0);
|
||||
|
||||
/*
|
||||
writeln('- match:'+match);
|
||||
|
||||
writeln('- match 0x0f:'+(match & 0x0f));
|
||||
if (match & 0x10) {
|
||||
writeln(' - got mosiac');
|
||||
attr += MOSIAC;
|
||||
}
|
||||
|
||||
*/
|
||||
//if (match < 0x0f) {
|
||||
//switch(match & 0x07) {
|
||||
switch(match) {
|
||||
case 0x00:
|
||||
attr += BLACK;
|
||||
break;
|
||||
case 0x01:
|
||||
attr += RED;
|
||||
break;
|
||||
case 0x02:
|
||||
attr += GREEN;
|
||||
break;
|
||||
case 0x03:
|
||||
attr += YELLOW;
|
||||
break;
|
||||
case 0x04:
|
||||
attr += BLUE;
|
||||
break;
|
||||
case 0x05:
|
||||
attr += MAGENTA;
|
||||
break;
|
||||
case 0x06:
|
||||
attr += CYAN;
|
||||
break;
|
||||
case 0x07:
|
||||
attr += LIGHTGRAY;
|
||||
break;
|
||||
case 0x08:
|
||||
attr = BLINK;
|
||||
break;
|
||||
case 0x09:
|
||||
attr = STEADY;
|
||||
break;
|
||||
/*
|
||||
case 0x0a:
|
||||
//attr = ENDBOX; // End Box (Unused?)
|
||||
break;
|
||||
case 0x0b:
|
||||
//attr = STARTBOX; // Start Box (Unused?)
|
||||
break;
|
||||
*/
|
||||
case 0x0c:
|
||||
//attr &= ~DOUBLE;
|
||||
attr = NORMAL;
|
||||
break;
|
||||
case 0x0d:
|
||||
attr = DOUBLE;
|
||||
break;
|
||||
case 0x0e:
|
||||
attr = NORMAL; // @todo Double Width (Unused)?
|
||||
break;
|
||||
case 0x0f:
|
||||
attr = NORMAL; // @todo Double Width (Unused?)
|
||||
break;
|
||||
case 0x10:
|
||||
attr = MOSIAC|BLACK;
|
||||
break;
|
||||
case 0x11:
|
||||
attr += MOSIAC|RED;
|
||||
break;
|
||||
case 0x12:
|
||||
attr += MOSIAC|GREEN;
|
||||
break;
|
||||
case 0x13:
|
||||
attr += MOSIAC|YELLOW;
|
||||
break;
|
||||
case 0x14:
|
||||
attr += MOSIAC|BLUE;
|
||||
break;
|
||||
case 0x15:
|
||||
attr += MOSIAC|MAGENTA;
|
||||
break;
|
||||
case 0x16:
|
||||
attr += MOSIAC|CYAN;
|
||||
break;
|
||||
case 0x17:
|
||||
attr += MOSIAC|LIGHTGRAY;
|
||||
break;
|
||||
case 0x18:
|
||||
attr = CONCEAL;
|
||||
break;
|
||||
case 0x19:
|
||||
attr = BLOCKS;
|
||||
break;
|
||||
case 0x1a:
|
||||
attr = SEPARATED;
|
||||
break;
|
||||
/*
|
||||
case 0x1b:
|
||||
//attr = NORMAL; // CSI
|
||||
break;
|
||||
*/
|
||||
case 0x1c:
|
||||
attr = BLACKBACK; // Black Background
|
||||
break;
|
||||
case 0x1d:
|
||||
attr = NEWBACK; // New Background
|
||||
break;
|
||||
case 0x1e:
|
||||
attr = HOLD; // Mosiac Hold
|
||||
break;
|
||||
case 0x1f:
|
||||
attr = RELEASE; // Mosiac Release
|
||||
break;
|
||||
|
||||
// Catch all for other codes
|
||||
default:
|
||||
attr = 0xff00;
|
||||
}
|
||||
|
||||
if (debug)
|
||||
writeln(' - got control code:'+attr+'['+y+','+x+'] - length:'+attr.length);
|
||||
|
||||
store(x++,y,null,attr);
|
||||
attr = undefined;
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
/* parse an input field */
|
||||
// Input field 'FIELD;valueTYPE;input char'
|
||||
// @todo remove the trailing ESC \ to end the field, just use a control code ^B \x02 (Start of Text) and ^C \x03
|
||||
var m = line.match(/^\x1b_(([A-Z]+;[0-9a-z]+)([;]?.+)?)\x1b\\/);
|
||||
if (m !== null) {
|
||||
log(LOG_DEBUG,'Got input field: '+JSON.stringify(m));
|
||||
log(LOG_DEBUG,'ansi:'+JSON.stringify(ansi));
|
||||
// full string that matched
|
||||
match = m.shift();
|
||||
|
||||
// thus, the rest of the line
|
||||
line = line.substr(match.length);
|
||||
//writeln('rest of line:'+JSON.stringify(line));
|
||||
|
||||
// We are interested in our field match
|
||||
var sos = m.shift().split(';');
|
||||
//writeln('sos:'+JSON.stringify(sos));
|
||||
|
||||
for (var num in sos) {
|
||||
switch (num) {
|
||||
// First value is the field name
|
||||
case '0':
|
||||
field = sos[num];
|
||||
break;
|
||||
|
||||
// Second value is the length/type of the field, nnX nn=size in chars, T=type (lower case)
|
||||
case '1':
|
||||
var c = sos[num].match(/([0-9]+)([a-z])/);
|
||||
if (! c) {
|
||||
log(LOG_ERROR,'SOS FAILED PARSING FIELD LENGTH/TYPE. ['+r+'x'+c+'] '+sos[num]);
|
||||
break;
|
||||
}
|
||||
|
||||
//log(LOG_DEBUG,'SOS ['+r+'x'+c+'] NUM CHARS: '+x[1]+', TYPE: '+x[2]);
|
||||
fieldlen = c[1];
|
||||
fieldtype = c[2];
|
||||
break;
|
||||
|
||||
// Third field is the char to to use
|
||||
case '2':
|
||||
fieldchar = sos[num];
|
||||
break;
|
||||
|
||||
default:
|
||||
log(LOG_ERROR,'IGNORING ADDITIONAL SOS FIELDS. ['+r+'x'+c+'] '+sos[num]);
|
||||
}
|
||||
}
|
||||
|
||||
// If we are padding our field with a char, we need to add that back to line
|
||||
// @todo validate if this goes beyond our width (and if scrolling not enabled)
|
||||
if (fieldlen)
|
||||
line = fieldchar.repeat(fieldlen)+line;
|
||||
|
||||
frame.input_fields.push({
|
||||
type: fieldtype,
|
||||
length: Number(fieldlen),
|
||||
char: fieldchar,
|
||||
name: field,
|
||||
attribute: JSON.parse(JSON.stringify(ansi)),
|
||||
x: Number(x+(xoffset !== undefined ? xoffset : 0)),
|
||||
y: Number(y+(yoffset !== undefined ? yoffset : 0)),
|
||||
value: '',
|
||||
});
|
||||
|
||||
log(LOG_DEBUG,'input_field:'+JSON.stringify(frame.input_fields.last));
|
||||
}
|
||||
|
||||
/* parse dynamic value field */
|
||||
// @todo remove the trailing ESC \ to end the field, just use a control code ie: ^E \x05 (Enquiry) or ^Z \x26 (Substitute)
|
||||
var m = line.match(/^\x1bX(([a-zA-Z._:^;]+[0-9]?;-?[0-9^;]+)([;]?[^;]+)?)\x1b\\/);
|
||||
if (m !== null) {
|
||||
// full string that matched
|
||||
match = m.shift();
|
||||
|
||||
// thus, the rest of the line
|
||||
line = line.substr(match.length);
|
||||
//writeln('rest of line:'+JSON.stringify(line));
|
||||
|
||||
// We are interested in our field match
|
||||
var df = m.shift().split(';');
|
||||
|
||||
log(LOG_DEBUG,'- DF found at ['+x+'x'+y+'], Field: '+df[0]+', Length: '+df[1]+', Pad:'+df[2]);
|
||||
// If we are padding our field with a char, we need to add that back to line
|
||||
// @todo validate if this goes beyond our width (and if scrolling not enabled)
|
||||
line = (df[2] ? df[2] : '_').repeat(Math.abs(df[1]))+line;
|
||||
|
||||
frame.dynamic_fields.push({
|
||||
name: df[0],
|
||||
length: df[1],
|
||||
pad: df[2],
|
||||
x: x+(xoffset !== undefined ? xoffset : 0),
|
||||
y: y+(yoffset !== undefined ? yoffset : 0),
|
||||
value: undefined,
|
||||
});
|
||||
}
|
||||
|
||||
/* set character and attribute */
|
||||
var ch = line[0];
|
||||
line = line.substr(1);
|
||||
|
||||
if (debug && (debug === y)) {
|
||||
writeln('y:'+y+', x:'+x+', ch:'+ch);
|
||||
}
|
||||
|
||||
/* validate position */
|
||||
if (y < 0)
|
||||
y = 0;
|
||||
if (x < 0)
|
||||
x = 0;
|
||||
|
||||
store(x,y,ch,undefined);
|
||||
x++;
|
||||
}
|
||||
|
||||
// Each new line, we reset the attrs
|
||||
attr = undefined;
|
||||
y++;
|
||||
}
|
||||
|
||||
return frame;
|
||||
|
||||
function store(x,y,ch,attr) {
|
||||
/* set character and attribute */
|
||||
if (! frame.content[y+1])
|
||||
frame.content[y+1]=[];
|
||||
|
||||
frame.content[y+1][x+1] = new Char(ch,attr,SESSION_EXT);
|
||||
}
|
||||
}
|
||||
|
||||
load('ansitex/load/session.js');
|
||||
|
||||
// Our frame object
|
||||
function SessionViewdata() {
|
||||
Session.apply(this,arguments);
|
||||
|
||||
this.settings.MSG_SENDORNOT = ascii(27)+'BKEY 1 TO SEND, 2 NOT TO SEND';
|
||||
this.settings.MSG_LOGON = ascii(27)+'BKEY 1 TO LOGON, 2 TO RETURN';
|
||||
this.settings.MSG_SENT = ascii(27)+'BMESSAGE SENT - KEY _ TO CONTINUE';
|
||||
this.settings.MSG_NOTSENT = ascii(27)+'BMESSAGE NOT SENT - KEY _ TO CONTINUE';
|
||||
this.settings.ERR_NO_PARENT = ascii(27)+'APARENT FRAME DOESNT EXIST';
|
||||
this.settings.ERR_NOT_IMPLEMENTED = ascii(27)+'ANOT IMPLEMENTED YET?';
|
||||
this.settings.ERR_ROUTE = ascii(27)+'GMISTAKE?'+ascii(27)+'BTRY AGAIN OR TELL US ON *08';
|
||||
this.settings.ERR_METHOD_NOT_EXIST = ascii(27)+'GMISTAKE?'+ascii(27)+'BTRY AGAIN OR TELL US ON *08';
|
||||
this.settings.ACCESS_DENIED = ascii(27)+'AACCESS DENIED.';
|
||||
this.settings.ALREADY_MEMBER = ascii(27)+'AALREADY MEMBER OF CUG'
|
||||
this.settings.INACTIVITY = ascii(27)+'AINACTIVITY ALERT, DISCONNECT PENDING...';
|
||||
this.settings.INACTIVE = ascii(27)+'AINACTIVITY DISCONNECT';
|
||||
this.settings.NOACTION = ascii(27)+'ANO ACTION PERFORMED';
|
||||
this.settings.BASESTAR = ascii(27)+'B*';
|
||||
this.settings.INVALID_CODE = ascii(27)+'AINVAID CODE, PLEASE TRY AGAIN *00';
|
||||
this.settings.TOKEN_EMAIL = ascii(27)+'ATOKEN EMAILED TO YOU...';
|
||||
this.settings.TOKEN_SENT = ascii(27)+'ATOKEN SENT, PLEASE ENTER TOKEN';
|
||||
this.settings.INVALID_EMAIL = ascii(27)+'AINVAID EMAIL, PLEASE TRY AGAIN *00';
|
||||
this.settings.INVALID_UID = ascii(27)+'AINVAID USER ID, PLEASE TRY AGAIN *00';
|
||||
this.settings.CANNOT_SEND_TOKEN = ascii(27)+'ACANNOT SEND VALIDATION CODE, PLEASE TRY AGAIN *00';
|
||||
this.settings.USER_EXISTS = ascii(27)+'AERROR USER EXISTS, PLEASE TRY AGAIN *00';
|
||||
this.settings.USER_CREATE_ERROR = ascii(27)+'AERROR CREATING USER, PLEASE TRY AGAIN *00';
|
||||
this.settings.LOGIN_ERROR = ascii(27)+'AERROR LOGGING IN, PLEASE TRY AGAIN *00';
|
||||
this.settings.CANCEL_MSG = ascii(27)+'BPRESS 2 TO CANCEL';
|
||||
this.settings.SYS_ERROR = ascii(27)+'ASYS ERR, TRY AGAIN OR TELL US ON *08';
|
||||
this.settings.LOADING = ascii(27)+'Cloading...';
|
||||
this.settings.PROCESSING = ESC+VIEWDATA_YELLOW+'processing...';
|
||||
|
||||
var blp = 0; // Length of data on the bottom line
|
||||
|
||||
/**
|
||||
* Set the attribute at the current position
|
||||
*/
|
||||
this.attr = function(field) {
|
||||
//NOOP - the terminal takes care of this
|
||||
}
|
||||
|
||||
this.baselineClear = function(reposition) {
|
||||
msg = '';
|
||||
|
||||
log(LOG_DEBUG,'- Clear Bottom Line ['+blp+'] - reposition ['+reposition+']');
|
||||
|
||||
write_raw(VIEWDATA_HOME+VIEWDATA_UP+msg+
|
||||
((blp > msg.length)
|
||||
? (' '.repeat(blp-msg.length)+(reposition ? VIEWDATA_HOME+VIEWDATA_UP+VIEWDATA_RIGHT.repeat(msg.length) : ''))
|
||||
: '')
|
||||
);
|
||||
|
||||
blp = msg.length;
|
||||
}
|
||||
|
||||
/**
|
||||
* Send a message to the baseline.
|
||||
*
|
||||
* @param text
|
||||
* @param reposition
|
||||
*/
|
||||
this.baselineSend = function(text,reposition) {
|
||||
var msg = this.getMessage(text);
|
||||
var x = this.strlen(msg);
|
||||
|
||||
log(LOG_DEBUG,'- Bottom Line ['+msg+'] ('+x+') - reposition ['+reposition+'] BLP:'+blp);
|
||||
|
||||
write_raw(VIEWDATA_HOME+VIEWDATA_UP+msg+
|
||||
((blp > x)
|
||||
? (' '.repeat(blp-x)+(reposition ? VIEWDATA_HOME+VIEWDATA_UP+VIEWDATA_RIGHT.repeat(x) : ''))
|
||||
: '')
|
||||
);
|
||||
|
||||
blp = x;
|
||||
}
|
||||
|
||||
/**
|
||||
* Turn off the cursor
|
||||
*/
|
||||
this.cursorOff = function() {
|
||||
write_raw(VIEWDATA_COFF);
|
||||
}
|
||||
|
||||
/**
|
||||
* Turn on cursor
|
||||
* @param x
|
||||
* @param y
|
||||
*/
|
||||
this.cursorOn = function(x,y) {
|
||||
write_raw(VIEWDATA_CON);
|
||||
|
||||
if (x && y)
|
||||
this.gotoxy(x,y);
|
||||
}
|
||||
|
||||
// Field backspace, that leaves the field filler char
|
||||
this.fieldbs = function(char) {
|
||||
log(LOG_DEBUG,'- Field backspace with char:'+char);
|
||||
write_raw(VIEWDATA_LEFT+char+VIEWDATA_LEFT);
|
||||
}
|
||||
|
||||
this.gotoxy = function(x,y) {
|
||||
log(LOG_DEBUG,'- Moving cursor to y:'+y+', x:'+x);
|
||||
|
||||
// @todo This could be optimised to go the shortest route
|
||||
write_raw(VIEWDATA_HOME);
|
||||
|
||||
if (x > 0)
|
||||
write_raw(VIEWDATA_RIGHT.repeat(x));
|
||||
|
||||
if (y > 0)
|
||||
write_raw(VIEWDATA_DOWN.repeat(y));
|
||||
}
|
||||
|
||||
this.strlen = function(str) {
|
||||
return str.replace(/\x1b/g,'').length;
|
||||
};
|
||||
|
||||
/*
|
||||
// Render the frame to the user
|
||||
this.render=function(withHeader) {
|
||||
log(LOG_DEBUG,'- VIEWDATA FRAME');
|
||||
owner = base64_decode(this.owner);
|
||||
|
||||
header = VIEWDATA_DOWN;
|
||||
|
||||
//log(LOG_DEBUG,' - FRAME User: ['+JSON.stringify(user)+']');
|
||||
|
||||
// Dont show the page number on system login page
|
||||
if (user.number || (this.type !== FRAME_TYPE_LOGIN && FRAMES_NO_HISTORY.indexOf(this.page) === -1)) {
|
||||
log(LOG_DEBUG,' - Owner: ['+this.pageowner+'] ('+this.strlen(videotex(this.pageownerlogo))+')');
|
||||
|
||||
cost = (this.isAccessible ? this.cost+FRAME_COSTUNIT : ' -');
|
||||
|
||||
header = videotex(this.pageownerlogo)+' '.repeat(this.settings.FRAME_HEADER-this.strlen(videotex(this.pageownerlogo)))+
|
||||
(this.isAccessible ? ascii(27)+'G' : ascii(27)+'A')+this.page+' '.repeat(this.settings.FRAME_PAGENUM-this.page.length)+
|
||||
ascii(27)+'B'+' '.repeat(this.settings.FRAME_COST-cost.toString().length+1)+cost;
|
||||
}
|
||||
|
||||
//console.status |= CON_RAW_IN;
|
||||
write_raw(VIEWDATA_CLS);
|
||||
write_raw(header);
|
||||
return write_raw(videotex(base64_decode(this.content)));
|
||||
};
|
||||
*/
|
||||
|
||||
this.qrcode = function(qr) {
|
||||
// Render the body
|
||||
var qrcode = VIEWDATA_HOME+VIEWDATA_DOWN.repeat(5);
|
||||
var offset = this.settings.FRAME_WIDTH-Math.ceil(qr.size/2)-1;
|
||||
|
||||
for (var x = -1; x < qr.size; x=x+3) {
|
||||
var line = VIEWDATA_RIGHT.repeat(offset ? offset-1 : 0)+ESC+VIEWDATA_MOSIAC_WHITE;
|
||||
|
||||
for (var y = -1; y < qr.size; y=y+2) {
|
||||
var char = 0;
|
||||
|
||||
//TL
|
||||
char |= ((x===-1) || (y===-1) || ! qr.getModule(x,y)) ? (1<<0) : (0<<0);
|
||||
//TR
|
||||
char |= ((x===-1) || (y === qr.size-1) || ! qr.getModule(x,y+1)) ? (1<<1) : (0<<1);
|
||||
//ML
|
||||
char |= ((y===-1) || ! qr.getModule(x+1,y)) ? (1<<2) : (0<<2);
|
||||
//MR
|
||||
char |= ((y === qr.size-1) || ! qr.getModule(x+1,y+1)) ? (1<<3) : (0<<3);
|
||||
//BL
|
||||
char |= ((x===qr.size-2) || (y===-1) || ! qr.getModule(x+2,y)) ? (1<<4) : (0<<4);
|
||||
//BR
|
||||
char |= ((x===qr.size-2) || (y === qr.size-1) || ! qr.getModule(x+2,y+1)) ? (1<<5) : (0<<5);
|
||||
|
||||
char += 0x20;
|
||||
if (char > 0x3f)
|
||||
char += 0x20;
|
||||
|
||||
line += ascii(char);
|
||||
}
|
||||
|
||||
// Render the right column
|
||||
if (y%2)
|
||||
line += '\x35';
|
||||
|
||||
repeat_count = this.settings.FRAME_WIDTH-Math.ceil(qr.size/2)-offset-(offset ? 1 : 2)-(y%2 === 1 ? 0 : 1);
|
||||
|
||||
qrcode += line+' '.repeat(repeat_count > 0 ? repeat_count : 0);
|
||||
|
||||
// To fix some terminals where moving right from col 40 doesnt advance to col 1 on the next line
|
||||
qrcode +=VIEWDATA_LEFT+VIEWDATA_CR+VIEWDATA_DOWN;
|
||||
}
|
||||
|
||||
log(LOG_DEBUG,'WIDTH:'+this.settings.FRAME_WIDTH);
|
||||
log(LOG_DEBUG,'QR :'+(Math.ceil(qr.size/2)+1));
|
||||
log(LOG_DEBUG,'OFF :'+offset);
|
||||
log(LOG_DEBUG,'Y :'+(y%2 ? 0 : 1));
|
||||
log(LOG_DEBUG,'X :'+(x%3 ? 0 : 1));
|
||||
|
||||
// Render the bottom
|
||||
if (x%3) {
|
||||
line = VIEWDATA_RIGHT.repeat(offset ? offset-1 : 0)+ESC+VIEWDATA_MOSIAC_WHITE;
|
||||
|
||||
for (var y = 0; y < qr.size; y=y+2) {
|
||||
line += '\x23';
|
||||
}
|
||||
|
||||
// Render the right column
|
||||
if (y%2 === 0) {
|
||||
line += '\x21';
|
||||
}
|
||||
|
||||
qrcode += line+' '.repeat(repeat_count > 0 ? repeat_count : 0);
|
||||
}
|
||||
|
||||
write_raw(qrcode);
|
||||
};
|
||||
|
||||
/*
|
||||
this.save=function() {
|
||||
file = system.mods_dir+'ansitex/text/'+this.page+'.tex';
|
||||
w = new File(file);
|
||||
if (! w.open('w')) {
|
||||
log(LOG_ERROR,'! ERROR: Unable to create TEX file for '+this.page);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
w.write(JSON.stringify(this));
|
||||
w.close();
|
||||
|
||||
log(LOG_DEBUG,'Saved file: '+this.page+'.tex');
|
||||
}
|
||||
*/
|
||||
}
|
||||
|
||||
function videotex(data) {
|
||||
var output = '';
|
||||
//$output .= ($byte < 32) ? ESC.chr($byte+64) : chr($byte);
|
||||
for (var i = 0; i < data.length; i++) {
|
||||
output += (data.charCodeAt(i) < 32) ? "\x1b"+String.fromCharCode(data.charCodeAt(i)+64) : String.fromCharCode(data.charCodeAt(i));
|
||||
}
|
||||
return output;
|
||||
}
|
||||
|
||||
SessionViewdata.prototype = Session.prototype;
|
||||
SessionViewdata.prototype.constructor = SessionViewdata;
|
Reference in New Issue
Block a user