sbbs/load/frame-viewdata.js

258 lines
8.3 KiB
JavaScript

var FRAME_VIEWDATA = (1<<2);
var VIEWDATA_LEFT = ascii(0x08);
var VIEWDATA_RIGHT = ascii(0x09);
var VIEWDATA_DOWN = ascii(0x0a); // \n
var VIEWDATA_UP = ascii(0x0b);
var VIEWDATA_CLS = ascii(0x0c);
var VIEWDATA_CR = ascii(0x0d); // \r
var VIEWDATA_CON = ascii(0x11);
var VIEWDATA_COFF = ascii(0x14);
var VIEWDATA_HOME = ascii(0x1e);
var VIEWDATA_MOSIAC_RED = ascii(27)+ascii(0x51);
var VIEWDATA_MOSIAC_GREEN = ascii(27)+ascii(0x52);
var VIEWDATA_MOSIAC_YELLOW = ascii(27)+ascii(0x53);
var VIEWDATA_MOSIAC_BLUE = ascii(27)+ascii(0x54);
var VIEWDATA_MOSIAC_MAGENTA = ascii(27)+ascii(0x55);
var VIEWDATA_MOSIAC_CYAN = ascii(27)+ascii(0x56);
var VIEWDATA_MOSIAC_WHITE = ascii(27)+ascii(0x57);
load('ansitex/load/frame-page.js');
// Our frame object
function FrameViewdata() {
PageFrame.apply(this,arguments);
/* File Extension used for frames */
this.settings.ext = 'vtx';
/* Length of a frame */
this.settings.FRAME_LENGTH = 22;
/* Width of a frame */
this.settings.FRAME_WIDTH = 40;
/* Size of page owner (length) */
this.settings.FRAME_HEADER = 23;
/* Size of page number (length with a-z) */
this.settings.FRAME_PAGENUM = 11;
/* Size of cost (length without unit) */
this.settings.FRAME_COST = 3;
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 = VIEWDATA_MOSIAC_WHITE+'loading...';
var blp=0; // Length of data on the bottom line
/**
* Set the attribute at the current position
*/
this.attr=function(field) {
//NOOP
}
/**
* Turn off the cursor
*/
this.cursorOff=function() {
write_raw(VIEWDATA_COFF);
this.gotoxy(1,1);
}
this.cursorOn=function(x,y) {
write_raw(VIEWDATA_CON);
this.gotoxy(x,y);
}
// Field backspace, that leaves the field filler char
this.fieldbs=function(char) {
console.write(VIEWDATA_LEFT+char+VIEWDATA_LEFT);
}
this.gotoxy=function(x,y) {
// @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 && NO_HISTORY_FRAMES.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)+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 += ascii(0x35);
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)+VIEWDATA_MOSIAC_WHITE;
for (var y = 0; y < qr.size; y=y+2) {
line += ascii(0x23);
}
// Render the right column
if (y%2 === 0) {
line += ascii(0x21);
}
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');
}
/**
* Send a message to the baseline.
*
* @param text
* @param reposition
*/
this.sendBaseline=function(text,reposition) {
var msg = this.getMessage(text);
var x = this.strlen(msg);
write_raw(VIEWDATA_HOME+VIEWDATA_UP+msg+
((blp > x)
? (' '.repeat(blp-x)+(reposition ? VIEWDATA_HOME+VIEWDATA_UP+VIEWDATA_RIGHT.repeat(x) : ''))
: '')
);
blp = x;
}
this.clearBaseline=function(reposition) {
msg = '';
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;
}
}
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;
}
FrameViewdata.prototype = PageFrame.prototype;
FrameViewdata.prototype.constructor = FrameViewdata;