sbbs/themes/hueman/source/js/viewdata/vdata.js

464 lines
8.5 KiB
JavaScript
Raw Normal View History

2019-01-16 03:07:59 +00:00
// VD.js -- a viewdata terminal emulator
// constructor
2020-08-16 04:49:03 +00:00
function VD(wd, ht, scr_id, initscr)
2019-01-16 03:07:59 +00:00
{
var r;
var c;
var scr = document.getElementById(scr_id);
2019-01-16 03:07:59 +00:00
this.wd_ = wd;
this.ht_ = ht;
this.text_ = new Array(ht);
for (r=0; r<ht; ++r) {
2019-01-16 03:07:59 +00:00
this.text_[r] = new Array(wd);
}
2019-01-16 03:07:59 +00:00
this.scr_ = scr;
this.cursor_vis_ = true;
2020-08-16 04:49:03 +00:00
this.reveal_ = 0;
2019-01-16 03:07:59 +00:00
this.getch_isr_ = undefined;
this.grab_events_ = false;
this.key_buf_ = [];
this.esc_state_ = 0;
this.col_ = 0;
this.row_ = 0;
// Initial Screen
if (typeof initscr !== 'undefined') {
2020-08-16 04:49:03 +00:00
this.write("\x0c" + this.txthash(initscr) + "\x14\x1e");
} else {
this.write("\x0c\x11\x1e");
}
2019-01-16 03:07:59 +00:00
}
VD.A_REVERSE = 2;
VD.A_BLINK = 4;
// class variables
VD.the_vt_ = undefined;
// object methods
VD.prototype.html_colours_ = function(at_fg, at_bg, at_mode) {
2019-01-16 03:07:59 +00:00
var co0, co1;
if (at_mode & VD.A_REVERSE) {
co0 = 'ff';
co1 = '00';
} else {
co0 = '00';
co1 = 'ff';
}
return {
f: '#' + (at_fg & 1 ? co1 : co0) +
(at_fg & 2 ? co1 : co0) +
(at_fg & 4 ? co1 : co0),
b: '#' + (at_bg & 1 ? co1 : co0) +
(at_bg & 2 ? co1 : co0) +
(at_bg & 4 ? co1 : co0)
};
}
VD.prototype.txthash = function(hashstring) {
var currentcode = 0, stuff = '';
2019-01-16 03:07:59 +00:00
if (hashstring.indexOf(':') > -1)
var hashstring = hashstring.split(':')[1];
hashstring = hashstring.substring(0,this.wd_*this.ht_);
for (var p=0; p<hashstring.length; p++) {
var pc = hashstring.charAt(p);
var pc_dec = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_"
.indexOf(hashstring.charAt(p));
// b is the bit in the 6-bit base-64 character.
for (var b=0; b<6; b++) {
// The current bit position in the character being
// written to.
var charbit = (6*p+b) % 7;
// The bit value (set or unset) of the bit we're
// reading from.
var b64bit = pc_dec & (1 << (5-b));
if ( b64bit > 0 ) {
b64bit = 1;
}
// Update the current code.
currentcode |= b64bit << (6-charbit);
// If we've reached the end of this character cell
// and it's the last bit in the character we're
// writing to, set the character code or place the
// code.
if (charbit === 6) {
if (currentcode < 32) {
stuff += '\x1b';
currentcode += 64;
2020-08-16 04:49:03 +00:00
}
stuff += String.fromCharCode(currentcode);
currentcode = 0;
2020-08-16 04:49:03 +00:00
}
}
}
2020-08-16 04:49:03 +00:00
return stuff;
}
VD.prototype.clear = function() {
2019-01-16 03:07:59 +00:00
this.row_ = this.col_ = 0;
for (r=0; r<this.ht_; ++r) {
2019-01-16 03:07:59 +00:00
for (c = 0; c < this.wd_; ++c) {
this.text_[r][c] = ' ';
}
}
}
VD.prototype.curs_set = function(vis) {
2019-01-16 03:07:59 +00:00
if (vis !== undefined)
this.cursor_vis_ = (vis > 0);
}
VD.prototype.getch = function(isr) {
2019-01-16 03:07:59 +00:00
this.getch_isr_ = isr;
2019-01-16 03:07:59 +00:00
setTimeout(VD.go_getch_, 0);
}
VD.go_getch_ = function VD_go_getch() {
2019-01-16 03:07:59 +00:00
var vt = VD.the_vt_;
if (vt === undefined)
return;
2019-01-16 03:07:59 +00:00
var isr = vt.getch_isr_;
vt.getch_isr_ = undefined;
if (isr === undefined)
return;
2019-01-16 03:07:59 +00:00
var ch = vt.key_buf_.shift();
if (ch === undefined) {
vt.getch_isr_ = isr;
return;
}
isr(ch,vt);
2019-01-16 03:07:59 +00:00
}
VD.prototype.move = function(r, c) {
2019-01-16 03:07:59 +00:00
if (r < 0)
r = 0;
2019-01-16 03:07:59 +00:00
else if (r >= this.ht_)
r = this.ht_ - 1;
2019-01-16 03:07:59 +00:00
if (c < 0)
c = 0;
2019-01-16 03:07:59 +00:00
else if (c >= this.wd_)
c = this.wd_ - 1;
this.row_ = r;
this.col_ = c;
}
VD.prototype.refresh = function() {
2020-08-16 04:49:03 +00:00
var r, c, stuff = "", start_tag = "", end_tag = "", ch, chtype,
pair, cr, cc, ht, wd, cv, n_fg, n_bg, n_mode, n_type, a_fg=-1, a_bg=-1, a_mode=-1, n_dblnextline=-2, n_heldchar, n_heldtype;
2019-01-16 03:07:59 +00:00
ht = this.ht_;
wd = this.wd_;
cr = this.row_;
cc = this.col_;
cv = this.cursor_vis_;
2019-01-16 03:07:59 +00:00
if (cc >= wd)
cc = wd - 1;
2019-01-16 03:07:59 +00:00
for (r = 0; r < ht; ++r) {
if (r > 0) {
stuff += '\n';
}
2019-01-16 03:07:59 +00:00
n_fg = 7;
n_bg = 0;
n_mode = 0;
n_type = 0;
2020-08-16 04:49:03 +00:00
n_heldchar = 32;
n_heldtype = 0;
2020-08-16 04:49:03 +00:00
if (n_dblnextline+1 < r)
n_dblnextline = -2;
2019-01-16 03:07:59 +00:00
for (c = 0; c < wd; ++c) {
if (cv && r == cr && c == cc) {
// Draw the cursor here.
n_mode |= VD.A_REVERSE;
} else {
n_mode &= ~VD.A_REVERSE;
}
2020-08-16 04:49:03 +00:00
if (r == n_dblnextline+1) {
ch = this.text_[r-1][c].charCodeAt(0);
} else {
ch = this.text_[r][c].charCodeAt(0);
2019-01-16 03:07:59 +00:00
}
2020-08-16 04:49:03 +00:00
ctrlch = ch;
// set-at
if (ctrlch == 0x89) // steady
2019-01-16 03:07:59 +00:00
n_mode &= ~VD.A_BLINK;
2020-08-16 04:49:03 +00:00
if (ctrlch == 0x8c) { // normal
if (n_type & 8) {
n_heldchar = 32;
n_heldtype = 0;
}
2019-01-16 03:07:59 +00:00
n_type &= ~8;
2020-08-16 04:49:03 +00:00
}
2020-08-16 04:49:03 +00:00
if (ctrlch == 0x98 && this.reveal_ == false) // conceal
2019-01-16 03:07:59 +00:00
n_type |= 16;
2020-08-16 04:49:03 +00:00
if (ctrlch == 0x99) // contig
2019-01-16 03:07:59 +00:00
n_type &= ~1;
2020-08-16 04:49:03 +00:00
if (ctrlch == 0x9a) // sep
2019-01-16 03:07:59 +00:00
n_type |= 1;
2020-08-16 04:49:03 +00:00
if (ctrlch == 0x9c) // black
2019-01-16 03:07:59 +00:00
n_bg = 0;
2020-08-16 04:49:03 +00:00
if (ctrlch == 0x9d) // newback
2019-01-16 03:07:59 +00:00
n_bg = n_fg;
2020-08-16 04:49:03 +00:00
if (ctrlch == 0x9e) // hold
2019-01-16 03:07:59 +00:00
n_type |= 32;
// If the attributes changed, make a new span.
if (n_mode != a_mode || n_fg != a_fg || n_bg != a_bg) {
stuff += end_tag;
pair = this.html_colours_(n_fg, n_bg, n_mode);
2020-08-16 04:49:03 +00:00
stuff += '<span style="color:' + pair.f + ';background-color:' + pair.b + ";" +'">'
2019-01-16 03:07:59 +00:00
end_tag = "</span>";
2020-08-16 04:49:03 +00:00
if (n_mode & VD.A_BLINK) {
stuff += '<span class="flashing";>';
2020-08-16 04:49:03 +00:00
end_tag += "</span>";
}
2019-01-16 03:07:59 +00:00
a_fg = n_fg;
a_bg = n_bg;
a_mode = n_mode;
}
2020-08-16 04:49:03 +00:00
chtype = n_type;
if (ch >= 128) {
if (n_type & 32) {
ch = n_heldchar;
chtype = n_heldtype;
} else {
2020-08-16 04:49:03 +00:00
ch = 32;
}
}
2020-08-16 04:49:03 +00:00
if (ch == 127) {
if (n_type & 2) {
ch = 0xe23f+((chtype & 1)*0xc0);
n_heldchar = 127;
} else {
ch = 0xb6;
}
}
2019-01-16 03:07:59 +00:00
if (n_type & 2) {
2020-08-16 04:49:03 +00:00
if ( ch >= 0x20 && ch <= 0x3f) {
n_heldchar = ch;
ch = ch+0xe1e0+((chtype & 1)*0xc0);
} else if ( ch >= 0x60 && ch <= 0x7e) {
n_heldchar = ch;
ch = ch+0xe1c0+((chtype & 1)*0xc0);
2019-01-16 03:07:59 +00:00
}
}
2020-08-16 04:49:03 +00:00
if (n_type & 16)
ch = 32;
n_heldtype = chtype;
2019-01-16 03:07:59 +00:00
switch (ch) {
2020-08-16 04:49:03 +00:00
case 32:
ch = 0xa0; break;
case 0x7e:
ch = 0xf7; break;
case 0x5f: // _
ch = 0x23; break // #
case 123: // {
ch = 0xbc; break
case 92: // \
ch = 0xbd; break
case 125: // }
ch = 0xbe; break
case 0x23: // #
ch = 0xa3; break
}
2020-08-16 04:49:03 +00:00
if (n_type & 8) {
if (ch < 0x100) {
ch = ch+0xe000+((r==n_dblnextline+1)*0x100);
} else {
ch = ch+0x40+((r==n_dblnextline+1)*0x40)
}
2020-08-16 04:49:03 +00:00
} else if (r==n_dblnextline+1) {
ch = 0xa0;
2019-01-16 03:07:59 +00:00
}
2020-08-16 04:49:03 +00:00
stuff += "&#x" + ch.toString(16) + ";"
// set-after
if (ctrlch >= 129 && ctrlch <= 135) {
if (n_type & 2) {
n_heldchar=32;
n_heldtype=0;
}
n_fg = ctrlch-128;
n_type &= ~2;
n_type &= ~16;
}
2020-08-16 04:49:03 +00:00
if (ctrlch >= 145 && ctrlch <= 151) {
if (n_type & 2 == 0) {
n_heldchar=32;
n_heldtype=0;
}
n_fg = ctrlch-144;
n_type |= 2;
n_type &= ~16;
}
2020-08-16 04:49:03 +00:00
if (ctrlch == 0x88) // flash
n_mode |= VD.A_BLINK;
2020-08-16 04:49:03 +00:00
if (ctrlch == 0x8d) { // double
if (n_type & 8 == 0) {
n_heldchar = 32;
n_heldtype = 0;
}
n_type |= 8;
if (n_dblnextline < 0)
n_dblnextline = r;
}
2020-08-16 04:49:03 +00:00
if (ctrlch == 0x9f) // release
n_type &= ~32;
2019-01-16 03:07:59 +00:00
}
}
2019-01-16 03:07:59 +00:00
stuff += end_tag
2020-08-16 04:49:03 +00:00
this.scr_.innerHTML = "<b>" + stuff + "</b>\n";
2019-01-16 03:07:59 +00:00
}
VD.prototype.write = function(stuff) {
2019-01-16 03:07:59 +00:00
var ch, i;
2019-01-16 03:07:59 +00:00
for (i = 0; i < stuff.length; ++i) {
ch = stuff.charCodeAt(i);
2019-01-16 03:07:59 +00:00
if (this.esc_state_ && ch > 31)
ch = (ch % 32) + 128;
2019-01-16 03:07:59 +00:00
this.esc_state_ = 0;
2019-01-16 03:07:59 +00:00
switch (ch) {
case 8:
if (this.col_ != 0) {
--this.col_;
2019-01-16 03:07:59 +00:00
} else {
this.col_ = this.wd_-1;
if (this.row_ == 0) {
this.row_ = this.ht_-1;
} else {
--this.row_;
}
2019-01-16 03:07:59 +00:00
}
break;
case 9:
if (this.col_ >= this.wd_) {
2019-01-16 03:07:59 +00:00
this.col_ = 0;
if (this.row_ == this.ht_-1) {
2019-01-16 03:07:59 +00:00
this.row_ = 0;
} else {
++this.row_;
}
} else {
++this.col_;
}
break;
case 10:
if (this.row_ >= this.ht_-1) {
this.row_ = 0;
} else {
++this.row_;
}
break;
case 11:
if (this.row_ == 0) {
this.row_ = this.ht_-1;
} else {
--this.row_;
}
break;
case 12:
this.clear();
this.move(0, 0);
this.reveal_ = false;
break;
case 13:
this.col_ = 0;
break;
case 17:
this.curs_set(1);
break;
case 20:
this.curs_set(0);
break;
case 27:
this.esc_state_ = 1;
break;
case 30:
this.move(0, 0);
break;
default:
if (ch > 31) {
this.text_[this.row_][this.col_] = String.fromCharCode(ch);
if (this.col_ >= this.wd_-1) {
this.col_ = 0;
if (this.row_ >= this.ht_-1) {
this.row_ = 0;
} else {
++this.row_;
}
} else {
++this.col_;
}
}
2019-01-16 03:07:59 +00:00
}
}
2019-01-16 03:07:59 +00:00
this.refresh();
}