Changed TexFrame to ANSIFrame(), setup edit.js to edit properties
This commit is contained in:
parent
a52bda670d
commit
1387a79672
407
load/ansiframe.js
Normal file
407
load/ansiframe.js
Normal file
@ -0,0 +1,407 @@
|
|||||||
|
var FRAME_ANSI=(1<<1);
|
||||||
|
|
||||||
|
// Our frame object
|
||||||
|
function ANSIFrame() {
|
||||||
|
this.version=1; // The version of this frame - in case we update functionality and we need to be
|
||||||
|
// backwards compatible
|
||||||
|
this.frame=null; // Frame Number [0-9]+
|
||||||
|
this.index=null; // Frame Index [a-z]
|
||||||
|
this.owner=0; // The Service Provider owning the frame.
|
||||||
|
this.cost=0; // The cost to view the frame @TODO
|
||||||
|
this.content=''; // The frame content, base64 encoded
|
||||||
|
|
||||||
|
// Frame's owned by the system where:
|
||||||
|
// isPublic is FALSE - the user must be logged in to view it
|
||||||
|
// isPublic is TRUE - can be viewed by non-logged in users
|
||||||
|
|
||||||
|
// Frame's owned by Service Providers where:
|
||||||
|
// isPublic is FALSE - can only be viewed if a user is
|
||||||
|
// a member of the Service Providers CUG
|
||||||
|
// isPublic is TRUE - can be viewed by users (if logged in)
|
||||||
|
|
||||||
|
this.isPublic=false; // Is this frame accessible to non CUG users
|
||||||
|
// If FALSE user must be a member of the CUG to view the frame
|
||||||
|
// All users, including unauthenticated, are members of 'system' (owner = 0)
|
||||||
|
this.isAccessible=false; // Is this frame available to be accessed
|
||||||
|
// If FALSE, only the SP can view/edit the frame
|
||||||
|
|
||||||
|
this.type = FRAME_TYPE_INFO; // The frame type - see FRAME_TYPES above
|
||||||
|
this.key=[ null,null,null,null,null,null,null,null,null,null ]; // Key actions [0-9]
|
||||||
|
|
||||||
|
// Render the frame to the user
|
||||||
|
this.render=function(withHeader) {
|
||||||
|
owner = base64_decode(this.owner);
|
||||||
|
|
||||||
|
header = '\n\r';
|
||||||
|
|
||||||
|
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+']');
|
||||||
|
|
||||||
|
cost = (this.isAccessible ? this.cost+FRAME_COSTUNIT : ' -')
|
||||||
|
|
||||||
|
header = '\1n'+this.pageownerlogo+' '.repeat(FRAME_HEADER-console.strlen(this.pageownerlogo))+'\1n '+
|
||||||
|
(this.isAccessible ? '\1W' : '\1R')+'\1H'+this.page+' '.repeat(FRAME_PAGENUM-this.page.length)+' '+
|
||||||
|
'\1G\1H'+' '.repeat(FRAME_COST-cost.toString().length+1)+cost+'\1n'+
|
||||||
|
(console.screen_columns > 80 ? '\n\r' : '');
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((this.type == FRAME_TYPE_LOGIN) || (this.type == FRAME_TYPE_RESPONSE)) {
|
||||||
|
return header+this.parse(base64_decode(this.content));
|
||||||
|
} else {
|
||||||
|
return header+base64_decode(this.content);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
this.fieldValue=function(key) {
|
||||||
|
for each (var k in this.frame_fields) {
|
||||||
|
log(LOG_DEBUG,' - k:'+JSON.stringify(k));
|
||||||
|
|
||||||
|
if (k.fname == key) {
|
||||||
|
return k.fvalue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Load a frame from disk (.tex file)
|
||||||
|
this.load = function(filename) {
|
||||||
|
log(LOG_DEBUG,'Loading frame from: '+filename);
|
||||||
|
|
||||||
|
f = new File(system.mods_dir+'ansitex/text/'+filename+'.tex');
|
||||||
|
if (! f.exists || ! f.open('r')) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
var load = JSON.parse(f.read());
|
||||||
|
|
||||||
|
for (property in load) {
|
||||||
|
this[property] = load[property];
|
||||||
|
}
|
||||||
|
|
||||||
|
} catch (error) {
|
||||||
|
log(LOG_ERROR,'Frame error: '+error);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
log(LOG_DEBUG,'Loaded frame: ['+this.frame+']['+this.index+'] ('+this.page+')');
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Parse the page text, and return the frame as 2 arrays:
|
||||||
|
* + First array is all the characters and the position on the frame
|
||||||
|
* + Second array is the array of the control codes that changes the color of the character
|
||||||
|
*
|
||||||
|
* The purpose of this function is to convert any special char sequences there are interpreted directly by Ansitex
|
||||||
|
* Currently they are:
|
||||||
|
* + ESC _ <value>[;value] ESC \
|
||||||
|
*
|
||||||
|
* Additionally, for response frames, if the cursor is moved to a field, its to determine what attributes (eg: color)
|
||||||
|
* should apply for that field.
|
||||||
|
*
|
||||||
|
* @param text
|
||||||
|
*/
|
||||||
|
this.parse = function(text) {
|
||||||
|
var c = 1; // column
|
||||||
|
var r = 2; // row (row 1 is the header)
|
||||||
|
var output = '';
|
||||||
|
this.frame_fields = [];
|
||||||
|
|
||||||
|
// Default Attributes
|
||||||
|
f = 39;
|
||||||
|
b = 49;
|
||||||
|
i = 0;
|
||||||
|
|
||||||
|
for(p=0;p<text.length;p++) {
|
||||||
|
// Look for a special character until the end of the frame width
|
||||||
|
cte = (r*FRAME_WIDTH - ((r-1)*FRAME_WIDTH+c));
|
||||||
|
match = text.substr(p,cte).match(/[\r\n\x1b]/);
|
||||||
|
//log(LOG_DEBUG,'SPECIAL CHAR ['+r+'x'+c+'] ['+p+'-'+cte+'] for: '+match);
|
||||||
|
|
||||||
|
if (match == null || match.index) {
|
||||||
|
advance = match ? match.index : cte;
|
||||||
|
//log(LOG_DEBUG,'INCLUDE: '+text.substr(p,advance));
|
||||||
|
|
||||||
|
output += text.substr(p,advance);
|
||||||
|
p += advance;
|
||||||
|
c += advance;
|
||||||
|
advance = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// If the frame is not big enough, fill it with spaces.
|
||||||
|
byte = text.charAt(p);
|
||||||
|
advance = 0;
|
||||||
|
|
||||||
|
switch (byte) {
|
||||||
|
// Carriage Return
|
||||||
|
case '\r':
|
||||||
|
// log(LOG_DEBUG,'CR');
|
||||||
|
c=1;
|
||||||
|
break;
|
||||||
|
|
||||||
|
// New line
|
||||||
|
case '\n':
|
||||||
|
// log(LOG_DEBUG,'LF');
|
||||||
|
r++;
|
||||||
|
break;
|
||||||
|
|
||||||
|
// ESC
|
||||||
|
case KEY_ESC:
|
||||||
|
advance = 1;
|
||||||
|
// Is the next byte something we know about
|
||||||
|
nextbyte = text.charAt(p+advance);
|
||||||
|
//log(LOG_DEBUG,'ESC ['+r+'x'+c+'] NEXT: '+nextbyte);
|
||||||
|
|
||||||
|
switch (nextbyte) {
|
||||||
|
// CSI
|
||||||
|
case '[':
|
||||||
|
advance++;
|
||||||
|
chars = '';
|
||||||
|
|
||||||
|
// Find our end CSI param in the next 50 chars
|
||||||
|
matches = text.substr(p+advance,50).match(/([0-9]+[;]?)+([a-zA-Z])/);
|
||||||
|
//log(LOG_DEBUG,'CSI ['+r+'x'+c+'] ADVANCE: '+advance+', MATCHES: '+matches+', STRING: '+text.substr(p+advance,50));
|
||||||
|
|
||||||
|
if (! matches) {
|
||||||
|
chars += nextbyte;
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
advance += matches[0].length-1;
|
||||||
|
chars += nextbyte+matches[0];
|
||||||
|
//log(LOG_DEBUG,'CSI ['+r+'x'+c+'] ADVANCE: '+advance+', CHARS: '+chars+', CHARSLEN: '+chars.length);
|
||||||
|
|
||||||
|
switch (matches[2]) {
|
||||||
|
// Color CSIs
|
||||||
|
case 'm':
|
||||||
|
//log(LOG_DEBUG,'CSI m ['+r+'x'+c+'] MATCHES: '+matches[0]+', LENGTH : '+matches[0].length);
|
||||||
|
|
||||||
|
csi = matches[0].substr(0,matches[0].length-1).split(';');
|
||||||
|
var num = null;
|
||||||
|
for (num in csi) {
|
||||||
|
//log(LOG_DEBUG,'CSI m ['+r+'x'+c+'] NUM: '+num+', CSI: '+csi[num]);
|
||||||
|
// Intensity
|
||||||
|
if (csi[num] >= 0 && csi[num] <= 8) {
|
||||||
|
i = csi[num];
|
||||||
|
f = 39;
|
||||||
|
b = 49;
|
||||||
|
|
||||||
|
// Forground Color
|
||||||
|
} else if (csi[num] >= 30 && csi[num] <= 39) {
|
||||||
|
f = csi[num];
|
||||||
|
|
||||||
|
// Background Color
|
||||||
|
} else if (csi[num] >= 40 && csi[num] <= 49) {
|
||||||
|
b = num;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
// Advance characters
|
||||||
|
case 'C':
|
||||||
|
//log(LOG_DEBUG,'CSI C ['+r+'x'+c+'] CHARS: '+matches[1]);
|
||||||
|
c += parseInt(matches[1]); // Advance our position
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
log(LOG_DEBUG,'? CSI: '.matches[2]);
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
|
||||||
|
case ' ':
|
||||||
|
log(LOG_DEBUG,'LOOSE ESC? ['+r+'x'+c+'] '+advance);
|
||||||
|
|
||||||
|
break;
|
||||||
|
|
||||||
|
// SOS
|
||||||
|
case '_':
|
||||||
|
//log(LOG_DEBUG,'SOS ['+r+'x'+c+'] '+advance);
|
||||||
|
advance++;
|
||||||
|
|
||||||
|
// Find our end ST param in the next 50 chars
|
||||||
|
matches = text.substr(p+advance,50).match(/(([A-Z]+;[0-9a-z]+)([;]?.+)?)\x1b\\/);
|
||||||
|
//log(LOG_DEBUG,'SOS ['+r+'x'+c+'] ADVANCE: '+advance+', MATCHES: '+matches+', LENGTH: '+matches[0].length+', STRING: '+text.substr(p+advance,50));
|
||||||
|
|
||||||
|
if (! matches) {
|
||||||
|
chars += nextbyte;
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
advance += matches[0].length-1;
|
||||||
|
|
||||||
|
// The last 2 chars of matches[0] are the ESC \
|
||||||
|
sos = matches[0].substr(0,matches[0].length-2).split(';');
|
||||||
|
//log(LOG_DEBUG,'SOS ['+r+'x'+c+'] ADVANCE: '+advance+', SOS: '+sos);
|
||||||
|
|
||||||
|
var num = null;
|
||||||
|
var fieldlen = null;
|
||||||
|
for (num in sos) {
|
||||||
|
//log(LOG_DEBUG,'SOS ['+r+'x'+c+'] NUM: '+num+', SOS: '+sos[num]);
|
||||||
|
|
||||||
|
switch (num) {
|
||||||
|
// First value is the field name
|
||||||
|
case '0':
|
||||||
|
field = sos[num];
|
||||||
|
break;
|
||||||
|
|
||||||
|
// Second value is the length/type of the field
|
||||||
|
case '1':
|
||||||
|
x = sos[num].match(/([0-9]+)([a-z])/);
|
||||||
|
if (! x) {
|
||||||
|
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 = x[1];
|
||||||
|
fieldtype = x[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 (fieldlen) {
|
||||||
|
chars = fieldchar.repeat(fieldlen);
|
||||||
|
}
|
||||||
|
|
||||||
|
byte = '';
|
||||||
|
|
||||||
|
this.frame_fields.push({
|
||||||
|
ftype: fieldtype,
|
||||||
|
flength: fieldlen,
|
||||||
|
fchar: fieldchar,
|
||||||
|
fname: field,
|
||||||
|
r: r,
|
||||||
|
c: c,
|
||||||
|
attribute: {i:i,f:f,b:b},
|
||||||
|
fvalue: '',
|
||||||
|
});
|
||||||
|
|
||||||
|
log(LOG_DEBUG,'SOS Field found at ['+r+'x'+(c-1)+'], Type: '+fieldtype+', Length: '+fieldlen+', Attrs: '+JSON.stringify({i:i,f:f,b:b}));
|
||||||
|
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
log(LOG_DEBUG,'DEFAULT ['+r+'x'+c+'] '+advance);
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
c++;
|
||||||
|
}
|
||||||
|
|
||||||
|
output += byte;
|
||||||
|
|
||||||
|
if (advance) {
|
||||||
|
//log(LOG_DEBUG,'ADVANCE P ['+r+'x'+c+'] '+advance+', NEXT CHAR: '+text.charAt(p+advance)+' ('+text.charCodeAt(p+advance)+')');
|
||||||
|
output += chars;
|
||||||
|
p += advance;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (c>FRAME_WIDTH) {
|
||||||
|
c = 1;
|
||||||
|
r++;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
// @todo - If we are longer than FRAME_LENGTH, move the output into the next frame.
|
||||||
|
if (r>FRAME_LENGTH) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
}
|
||||||
|
|
||||||
|
return output;
|
||||||
|
};
|
||||||
|
|
||||||
|
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');
|
||||||
|
}
|
||||||
|
|
||||||
|
Object.defineProperty(this,'accessible',{
|
||||||
|
get: function() {
|
||||||
|
log(LOG_DEBUG,'- Checking if user can access frame: '+this.page);
|
||||||
|
log(LOG_DEBUG,' - User: '+JSON.stringify(user.number));
|
||||||
|
log(LOG_DEBUG,' - Frame Owner: '+JSON.stringify(this.owner)+', System Frame: '+(this.pageowner == SYSTEM_OWNER));
|
||||||
|
|
||||||
|
// user.number 0 is unidentified user.
|
||||||
|
if (user.number) {
|
||||||
|
return (
|
||||||
|
(this.isAccessible && this.pageowner == SYSTEM_OWNER && ! this.isPublic) ||
|
||||||
|
(this.isAccessible && this.isPublic) ||
|
||||||
|
(this.isAccessible && ! this.isPublic && this.isMember) ||
|
||||||
|
(pageEditor(this.frame))
|
||||||
|
);
|
||||||
|
|
||||||
|
} else {
|
||||||
|
return (this.isAccessible && this.pageowner == SYSTEM_OWNER && this.isPublic);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
Object.defineProperty(this,'fields', {
|
||||||
|
get: function() {
|
||||||
|
return this.frame_fields;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// Check if the user is already a member of the CUG
|
||||||
|
Object.defineProperty(this,'isMember',{
|
||||||
|
get: function() {
|
||||||
|
log(LOG_DEBUG,'- Checking if user is a member of frame: '+this.page);
|
||||||
|
|
||||||
|
if (user.number) {
|
||||||
|
return (
|
||||||
|
(this.pageowner == SYSTEM_OWNER)
|
||||||
|
);
|
||||||
|
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
Object.defineProperty(this,'page', {
|
||||||
|
get: function() {
|
||||||
|
if (this.frame == null || this.index == null) return null;
|
||||||
|
return this.frame.toString()+this.index;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
Object.defineProperty(this,'pageowner', {
|
||||||
|
get: function() {
|
||||||
|
return pageOwner(this.frame).prefix;
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
Object.defineProperty(this,'pageownerlogo', {
|
||||||
|
get: function() {
|
||||||
|
return base64_decode(pageOwner(this.frame).logo);
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
406
load/defs.js
406
load/defs.js
@ -53,410 +53,4 @@ var INKEY_TIMEOUT =10000;
|
|||||||
var INACTIVE_NOLOGIN =1000;
|
var INACTIVE_NOLOGIN =1000;
|
||||||
var INACTIVE_LOGIN =5*60000;
|
var INACTIVE_LOGIN =5*60000;
|
||||||
|
|
||||||
// Our frame object
|
|
||||||
function TexFrame() {
|
|
||||||
this.version=1; // The version of this frame - in case we update functionality and we need to be
|
|
||||||
// backwards compatible
|
|
||||||
this.frame=null; // Frame Number [0-9]+
|
|
||||||
this.index=null; // Frame Index [a-z]
|
|
||||||
this.owner=0; // The Service Provider owning the frame.
|
|
||||||
this.cost=0; // The cost to view the frame @TODO
|
|
||||||
this.content=''; // The frame content, base64 encoded
|
|
||||||
|
|
||||||
// Frame's owned by the system where:
|
|
||||||
// isPublic is FALSE - the user must be logged in to view it
|
|
||||||
// isPublic is TRUE - can be viewed by non-logged in users
|
|
||||||
|
|
||||||
// Frame's owned by Service Providers where:
|
|
||||||
// isPublic is FALSE - can only be viewed if a user is
|
|
||||||
// a member of the Service Providers CUG
|
|
||||||
// isPublic is TRUE - can be viewed by users (if logged in)
|
|
||||||
|
|
||||||
this.isPublic=false; // Is this frame accessible to non CUG users
|
|
||||||
// If FALSE user must be a member of the CUG to view the frame
|
|
||||||
// All users, including unauthenticated, are members of 'system' (owner = 0)
|
|
||||||
this.isAccessible=false; // Is this frame available to be accessed
|
|
||||||
// If FALSE, only the SP can view/edit the frame
|
|
||||||
|
|
||||||
this.type = FRAME_TYPE_INFO; // The frame type - see FRAME_TYPES above
|
|
||||||
this.key=[ null,null,null,null,null,null,null,null,null,null ]; // Key actions [0-9]
|
|
||||||
|
|
||||||
// Render the frame to the user
|
|
||||||
this.render=function(withHeader) {
|
|
||||||
owner = base64_decode(this.owner);
|
|
||||||
|
|
||||||
header = '\n\r';
|
|
||||||
|
|
||||||
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+']');
|
|
||||||
|
|
||||||
cost = (this.isAccessible ? this.cost+FRAME_COSTUNIT : ' -')
|
|
||||||
|
|
||||||
header = '\1n'+this.pageownerlogo+' '.repeat(FRAME_HEADER-console.strlen(this.pageownerlogo))+'\1n '+
|
|
||||||
(this.isAccessible ? '\1W' : '\1R')+'\1H'+this.page+' '.repeat(FRAME_PAGENUM-this.page.length)+' '+
|
|
||||||
'\1G\1H'+' '.repeat(FRAME_COST-cost.toString().length+1)+cost+'\1n'+
|
|
||||||
(console.screen_columns > 80 ? '\n\r' : '');
|
|
||||||
}
|
|
||||||
|
|
||||||
if ((this.type == FRAME_TYPE_LOGIN) || (this.type == FRAME_TYPE_RESPONSE)) {
|
|
||||||
return header+this.parse(base64_decode(this.content));
|
|
||||||
} else {
|
|
||||||
return header+base64_decode(this.content);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
this.fieldValue=function(key) {
|
|
||||||
for each (var k in this.frame_fields) {
|
|
||||||
log(LOG_DEBUG,' - k:'+JSON.stringify(k));
|
|
||||||
|
|
||||||
if (k.fname == key) {
|
|
||||||
return k.fvalue;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Load a frame from disk (.tex file)
|
|
||||||
this.load = function(filename) {
|
|
||||||
log(LOG_DEBUG,'Loading frame from: '+filename);
|
|
||||||
|
|
||||||
f = new File(system.mods_dir+'ansitex/text/'+filename+'.tex');
|
|
||||||
if (! f.exists || ! f.open('r')) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
|
||||||
var load = JSON.parse(f.read());
|
|
||||||
|
|
||||||
for (property in load) {
|
|
||||||
this[property] = load[property];
|
|
||||||
}
|
|
||||||
|
|
||||||
} catch (error) {
|
|
||||||
log(LOG_ERROR,'Frame error: '+error);
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
log(LOG_DEBUG,'Loaded frame: ['+this.frame+']['+this.index+'] ('+this.page+')');
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Parse the page text, and return the frame as 2 arrays:
|
|
||||||
* + First array is all the characters and the position on the frame
|
|
||||||
* + Second array is the array of the control codes that changes the color of the character
|
|
||||||
*
|
|
||||||
* The purpose of this function is to convert any special char sequences there are interpreted directly by Ansitex
|
|
||||||
* Currently they are:
|
|
||||||
* + ESC _ <value>[;value] ESC \
|
|
||||||
*
|
|
||||||
* Additionally, for response frames, if the cursor is moved to a field, its to determine what attributes (eg: color)
|
|
||||||
* should apply for that field.
|
|
||||||
*
|
|
||||||
* @param text
|
|
||||||
*/
|
|
||||||
this.parse = function(text) {
|
|
||||||
var c = 1; // column
|
|
||||||
var r = 2; // row (row 1 is the header)
|
|
||||||
var output = '';
|
|
||||||
this.frame_fields = [];
|
|
||||||
|
|
||||||
// Default Attributes
|
|
||||||
f = 39;
|
|
||||||
b = 49;
|
|
||||||
i = 0;
|
|
||||||
|
|
||||||
for(p=0;p<text.length;p++) {
|
|
||||||
// Look for a special character until the end of the frame width
|
|
||||||
cte = (r*FRAME_WIDTH - ((r-1)*FRAME_WIDTH+c));
|
|
||||||
match = text.substr(p,cte).match(/[\r\n\x1b]/);
|
|
||||||
//log(LOG_DEBUG,'SPECIAL CHAR ['+r+'x'+c+'] ['+p+'-'+cte+'] for: '+match);
|
|
||||||
|
|
||||||
if (match == null || match.index) {
|
|
||||||
advance = match ? match.index : cte;
|
|
||||||
//log(LOG_DEBUG,'INCLUDE: '+text.substr(p,advance));
|
|
||||||
|
|
||||||
output += text.substr(p,advance);
|
|
||||||
p += advance;
|
|
||||||
c += advance;
|
|
||||||
advance = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
// If the frame is not big enough, fill it with spaces.
|
|
||||||
byte = text.charAt(p);
|
|
||||||
advance = 0;
|
|
||||||
|
|
||||||
switch (byte) {
|
|
||||||
// Carriage Return
|
|
||||||
case '\r':
|
|
||||||
// log(LOG_DEBUG,'CR');
|
|
||||||
c=1;
|
|
||||||
break;
|
|
||||||
|
|
||||||
// New line
|
|
||||||
case '\n':
|
|
||||||
// log(LOG_DEBUG,'LF');
|
|
||||||
r++;
|
|
||||||
break;
|
|
||||||
|
|
||||||
// ESC
|
|
||||||
case KEY_ESC:
|
|
||||||
advance = 1;
|
|
||||||
// Is the next byte something we know about
|
|
||||||
nextbyte = text.charAt(p+advance);
|
|
||||||
//log(LOG_DEBUG,'ESC ['+r+'x'+c+'] NEXT: '+nextbyte);
|
|
||||||
|
|
||||||
switch (nextbyte) {
|
|
||||||
// CSI
|
|
||||||
case '[':
|
|
||||||
advance++;
|
|
||||||
chars = '';
|
|
||||||
|
|
||||||
// Find our end CSI param in the next 50 chars
|
|
||||||
matches = text.substr(p+advance,50).match(/([0-9]+[;]?)+([a-zA-Z])/);
|
|
||||||
//log(LOG_DEBUG,'CSI ['+r+'x'+c+'] ADVANCE: '+advance+', MATCHES: '+matches+', STRING: '+text.substr(p+advance,50));
|
|
||||||
|
|
||||||
if (! matches) {
|
|
||||||
chars += nextbyte;
|
|
||||||
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
advance += matches[0].length-1;
|
|
||||||
chars += nextbyte+matches[0];
|
|
||||||
//log(LOG_DEBUG,'CSI ['+r+'x'+c+'] ADVANCE: '+advance+', CHARS: '+chars+', CHARSLEN: '+chars.length);
|
|
||||||
|
|
||||||
switch (matches[2]) {
|
|
||||||
// Color CSIs
|
|
||||||
case 'm':
|
|
||||||
//log(LOG_DEBUG,'CSI m ['+r+'x'+c+'] MATCHES: '+matches[0]+', LENGTH : '+matches[0].length);
|
|
||||||
|
|
||||||
csi = matches[0].substr(0,matches[0].length-1).split(';');
|
|
||||||
var num = null;
|
|
||||||
for (num in csi) {
|
|
||||||
//log(LOG_DEBUG,'CSI m ['+r+'x'+c+'] NUM: '+num+', CSI: '+csi[num]);
|
|
||||||
// Intensity
|
|
||||||
if (csi[num] >= 0 && csi[num] <= 8) {
|
|
||||||
i = csi[num];
|
|
||||||
f = 39;
|
|
||||||
b = 49;
|
|
||||||
|
|
||||||
// Forground Color
|
|
||||||
} else if (csi[num] >= 30 && csi[num] <= 39) {
|
|
||||||
f = csi[num];
|
|
||||||
|
|
||||||
// Background Color
|
|
||||||
} else if (csi[num] >= 40 && csi[num] <= 49) {
|
|
||||||
b = num;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
// Advance characters
|
|
||||||
case 'C':
|
|
||||||
//log(LOG_DEBUG,'CSI C ['+r+'x'+c+'] CHARS: '+matches[1]);
|
|
||||||
c += parseInt(matches[1]); // Advance our position
|
|
||||||
break;
|
|
||||||
|
|
||||||
default:
|
|
||||||
log(LOG_DEBUG,'? CSI: '.matches[2]);
|
|
||||||
}
|
|
||||||
|
|
||||||
break;
|
|
||||||
|
|
||||||
case ' ':
|
|
||||||
log(LOG_DEBUG,'LOOSE ESC? ['+r+'x'+c+'] '+advance);
|
|
||||||
|
|
||||||
break;
|
|
||||||
|
|
||||||
// SOS
|
|
||||||
case '_':
|
|
||||||
//log(LOG_DEBUG,'SOS ['+r+'x'+c+'] '+advance);
|
|
||||||
advance++;
|
|
||||||
|
|
||||||
// Find our end ST param in the next 50 chars
|
|
||||||
matches = text.substr(p+advance,50).match(/(([A-Z]+;[0-9a-z]+)([;]?.+)?)\x1b\\/);
|
|
||||||
//log(LOG_DEBUG,'SOS ['+r+'x'+c+'] ADVANCE: '+advance+', MATCHES: '+matches+', LENGTH: '+matches[0].length+', STRING: '+text.substr(p+advance,50));
|
|
||||||
|
|
||||||
if (! matches) {
|
|
||||||
chars += nextbyte;
|
|
||||||
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
advance += matches[0].length-1;
|
|
||||||
|
|
||||||
// The last 2 chars of matches[0] are the ESC \
|
|
||||||
sos = matches[0].substr(0,matches[0].length-2).split(';');
|
|
||||||
//log(LOG_DEBUG,'SOS ['+r+'x'+c+'] ADVANCE: '+advance+', SOS: '+sos);
|
|
||||||
|
|
||||||
var num = null;
|
|
||||||
var fieldlen = null;
|
|
||||||
for (num in sos) {
|
|
||||||
//log(LOG_DEBUG,'SOS ['+r+'x'+c+'] NUM: '+num+', SOS: '+sos[num]);
|
|
||||||
|
|
||||||
switch (num) {
|
|
||||||
// First value is the field name
|
|
||||||
case '0':
|
|
||||||
field = sos[num];
|
|
||||||
break;
|
|
||||||
|
|
||||||
// Second value is the length/type of the field
|
|
||||||
case '1':
|
|
||||||
x = sos[num].match(/([0-9]+)([a-z])/);
|
|
||||||
if (! x) {
|
|
||||||
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 = x[1];
|
|
||||||
fieldtype = x[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 (fieldlen) {
|
|
||||||
chars = fieldchar.repeat(fieldlen);
|
|
||||||
}
|
|
||||||
|
|
||||||
byte = '';
|
|
||||||
|
|
||||||
this.frame_fields.push({
|
|
||||||
ftype: fieldtype,
|
|
||||||
flength: fieldlen,
|
|
||||||
fchar: fieldchar,
|
|
||||||
fname: field,
|
|
||||||
r: r,
|
|
||||||
c: c,
|
|
||||||
attribute: {i:i,f:f,b:b},
|
|
||||||
fvalue: '',
|
|
||||||
});
|
|
||||||
|
|
||||||
log(LOG_DEBUG,'SOS Field found at ['+r+'x'+(c-1)+'], Type: '+fieldtype+', Length: '+fieldlen+', Attrs: '+JSON.stringify({i:i,f:f,b:b}));
|
|
||||||
|
|
||||||
break;
|
|
||||||
|
|
||||||
default:
|
|
||||||
log(LOG_DEBUG,'DEFAULT ['+r+'x'+c+'] '+advance);
|
|
||||||
}
|
|
||||||
|
|
||||||
break;
|
|
||||||
|
|
||||||
default:
|
|
||||||
c++;
|
|
||||||
}
|
|
||||||
|
|
||||||
output += byte;
|
|
||||||
|
|
||||||
if (advance) {
|
|
||||||
//log(LOG_DEBUG,'ADVANCE P ['+r+'x'+c+'] '+advance+', NEXT CHAR: '+text.charAt(p+advance)+' ('+text.charCodeAt(p+advance)+')');
|
|
||||||
output += chars;
|
|
||||||
p += advance;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (c>FRAME_WIDTH) {
|
|
||||||
c = 1;
|
|
||||||
r++;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
// @todo - If we are longer than FRAME_LENGTH, move the output into the next frame.
|
|
||||||
if (r>FRAME_LENGTH) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
}
|
|
||||||
|
|
||||||
return output;
|
|
||||||
};
|
|
||||||
|
|
||||||
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');
|
|
||||||
}
|
|
||||||
|
|
||||||
Object.defineProperty(this,'accessible',{
|
|
||||||
get: function() {
|
|
||||||
log(LOG_DEBUG,'- Checking if user can access frame: '+this.page);
|
|
||||||
log(LOG_DEBUG,' - User: '+JSON.stringify(user.number));
|
|
||||||
log(LOG_DEBUG,' - Frame Owner: '+JSON.stringify(this.owner)+', System Frame: '+(this.pageowner == SYSTEM_OWNER));
|
|
||||||
|
|
||||||
// user.number 0 is unidentified user.
|
|
||||||
if (user.number) {
|
|
||||||
return (
|
|
||||||
(this.isAccessible && this.pageowner == SYSTEM_OWNER && ! this.isPublic) ||
|
|
||||||
(this.isAccessible && this.isPublic) ||
|
|
||||||
(this.isAccessible && ! this.isPublic && this.isMember) ||
|
|
||||||
(pageEditor(this.frame))
|
|
||||||
);
|
|
||||||
|
|
||||||
} else {
|
|
||||||
return (this.isAccessible && this.pageowner == SYSTEM_OWNER && this.isPublic);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
Object.defineProperty(this,'fields', {
|
|
||||||
get: function() {
|
|
||||||
return this.frame_fields;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
// Check if the user is already a member of the CUG
|
|
||||||
Object.defineProperty(this,'isMember',{
|
|
||||||
get: function() {
|
|
||||||
log(LOG_DEBUG,'- Checking if user is a member of frame: '+this.page);
|
|
||||||
|
|
||||||
if (user.number) {
|
|
||||||
return (
|
|
||||||
(this.pageowner == SYSTEM_OWNER)
|
|
||||||
);
|
|
||||||
|
|
||||||
} else {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
Object.defineProperty(this,'page', {
|
|
||||||
get: function() {
|
|
||||||
if (this.frame == null || this.index == null) return null;
|
|
||||||
return this.frame.toString()+this.index;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
Object.defineProperty(this,'pageowner', {
|
|
||||||
get: function() {
|
|
||||||
return pageOwner(this.frame).prefix;
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
Object.defineProperty(this,'pageownerlogo', {
|
|
||||||
get: function() {
|
|
||||||
return base64_decode(pageOwner(this.frame).logo);
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
this;
|
this;
|
23
load/edit.js
23
load/edit.js
@ -11,6 +11,7 @@ var CONTROL_EDIT = '1';
|
|||||||
function edit(fo) {
|
function edit(fo) {
|
||||||
log(LOG_DEBUG,'+ Control EDIT loaded');
|
log(LOG_DEBUG,'+ Control EDIT loaded');
|
||||||
var complete = false;
|
var complete = false;
|
||||||
|
var inProperty = false;
|
||||||
|
|
||||||
Object.defineProperty(this,'getName', {
|
Object.defineProperty(this,'getName', {
|
||||||
get: function() {
|
get: function() {
|
||||||
@ -75,15 +76,30 @@ function edit(fo) {
|
|||||||
this.handle=function(read) {
|
this.handle=function(read) {
|
||||||
if (! js.terminated && ascii(read) != 27) {
|
if (! js.terminated && ascii(read) != 27) {
|
||||||
|
|
||||||
|
if (inProperty) {
|
||||||
|
log(LOG_DEBUG, ' + FrameEdit properties(): read');
|
||||||
|
propFrame.putmsg(read);
|
||||||
|
propFrame.cycle();
|
||||||
|
|
||||||
|
} else {
|
||||||
editor.getcmd(read);
|
editor.getcmd(read);
|
||||||
editor.cycle();
|
editor.cycle();
|
||||||
frame.cycle();
|
frame.cycle();
|
||||||
|
}
|
||||||
|
|
||||||
if (! complete)
|
if (! complete)
|
||||||
return '';
|
return '';
|
||||||
|
|
||||||
// Ignore esc
|
// Ignore esc
|
||||||
} else if (ascii(read) == 27) {
|
} else if (ascii(read) == 27) {
|
||||||
|
if (inProperty) {
|
||||||
|
log(LOG_DEBUG, ' + FrameEdit properties(): ESC');
|
||||||
|
propFrame.close();
|
||||||
|
frame.top();
|
||||||
|
frame.cycle();
|
||||||
|
inProperty = false;
|
||||||
|
}
|
||||||
|
|
||||||
return '';
|
return '';
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -97,7 +113,14 @@ function edit(fo) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function properties() {
|
function properties() {
|
||||||
|
inProperty = true;
|
||||||
log(LOG_DEBUG, '+ FrameEdit properties()');
|
log(LOG_DEBUG, '+ FrameEdit properties()');
|
||||||
|
frame.bottom();
|
||||||
|
propFrame = new Frame(1,2,40,14,BG_BLUE|WHITE,frame);
|
||||||
|
propFrame.gotoxy(1,1);
|
||||||
|
propFrame.putmsg('Properties!');
|
||||||
|
propFrame.open();
|
||||||
|
propFrame.cycle();
|
||||||
}
|
}
|
||||||
|
|
||||||
function save() {
|
function save() {
|
||||||
|
12
main.js
12
main.js
@ -12,13 +12,15 @@ load('ansitex/load/funcs.js');
|
|||||||
|
|
||||||
// Ansitex specific includes
|
// Ansitex specific includes
|
||||||
require('ansitex/load/defs.js','ACTION_EXIT');
|
require('ansitex/load/defs.js','ACTION_EXIT');
|
||||||
|
require('ansitex/load/ansiframe.js','FRAME_ANSI');
|
||||||
|
require('ansitex/load/viewdataframe.js','FRAME_VIEWDATA');
|
||||||
|
|
||||||
// @TODO LIST
|
// @TODO LIST
|
||||||
// login screen - backspace not working
|
// login screen - backspace not working
|
||||||
// login screen ** to clear the current field not working
|
// login screen ** to clear the current field not working
|
||||||
// Returning from chat should refresh the frame
|
// Returning from chat should refresh the frame
|
||||||
// Supress displays of telegrams
|
// Supress displays of telegrams
|
||||||
|
log(LOG_DEBUG,'Socket:'+JSON.stringify(client.socket.local_port));
|
||||||
while(bbs.online) {
|
while(bbs.online) {
|
||||||
var mode = false; // Initial mode
|
var mode = false; // Initial mode
|
||||||
|
|
||||||
@ -740,7 +742,7 @@ while(bbs.online) {
|
|||||||
// If we are editing a specific frame, attempt to load it
|
// If we are editing a specific frame, attempt to load it
|
||||||
if (fe) {
|
if (fe) {
|
||||||
current = fo;
|
current = fo;
|
||||||
fo = new TexFrame();
|
fo = (client.socket.local_port !== 516) ? new ANSIFrame() : new VIEWDATAFrame();
|
||||||
fo.load(pageStr(fe));
|
fo.load(pageStr(fe));
|
||||||
|
|
||||||
// If the frame doesnt exist, check that the parent frame exists in case we are creating a new one
|
// If the frame doesnt exist, check that the parent frame exists in case we are creating a new one
|
||||||
@ -749,7 +751,7 @@ while(bbs.online) {
|
|||||||
|
|
||||||
// We can always create an 'a' frame
|
// We can always create an 'a' frame
|
||||||
if (fe.index !== 'a') {
|
if (fe.index !== 'a') {
|
||||||
fo = new TexFrame();
|
fo = (client.socket.local_port !== 516) ? new ANSIFrame() : new VIEWDATAFrame();
|
||||||
fo.load(pageStr({frame: fe.frame, index: String.fromCharCode(fe.index.charCodeAt(0)-1)}));
|
fo.load(pageStr({frame: fe.frame, index: String.fromCharCode(fe.index.charCodeAt(0)-1)}));
|
||||||
|
|
||||||
log(LOG_DEBUG,'- ACTION_EDIT: check index: '+JSON.stringify(fo)+' ('+String.fromCharCode(fe.index.charCodeAt(0)-1)+')');
|
log(LOG_DEBUG,'- ACTION_EDIT: check index: '+JSON.stringify(fo)+' ('+String.fromCharCode(fe.index.charCodeAt(0)-1)+')');
|
||||||
@ -763,7 +765,7 @@ while(bbs.online) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// New frame
|
// New frame
|
||||||
fo = new TexFrame();
|
fo = (client.socket.local_port !== 516) ? new ANSIFrame() : new VIEWDATAFrame();
|
||||||
fo.frame = fe.frame;
|
fo.frame = fe.frame;
|
||||||
fo.index = fe.index;
|
fo.index = fe.index;
|
||||||
fo.cost = 0;
|
fo.cost = 0;
|
||||||
@ -784,7 +786,7 @@ while(bbs.online) {
|
|||||||
|
|
||||||
if (next_page !== null) {
|
if (next_page !== null) {
|
||||||
current = fo;
|
current = fo;
|
||||||
fo = new TexFrame();
|
fo = (client.socket.local_port !== 516) ? new ANSIFrame() : new VIEWDATAFrame();
|
||||||
fo.load(pageStr(next_page));
|
fo.load(pageStr(next_page));
|
||||||
|
|
||||||
if (fo.page == null) {
|
if (fo.page == null) {
|
||||||
|
Loading…
Reference in New Issue
Block a user