321 lines
6.4 KiB
JavaScript
321 lines
6.4 KiB
JavaScript
// VD.js -- a viewdata terminal emulator
|
|
|
|
// constructor
|
|
function VD(wd, ht, scr_id)
|
|
{
|
|
var r;
|
|
var c;
|
|
var scr = document.getElementById(scr_id);
|
|
this.wd_ = wd;
|
|
this.ht_ = ht;
|
|
this.text_ = new Array(ht);
|
|
for (r = 0; r < ht; ++r) {
|
|
this.text_[r] = new Array(wd);
|
|
}
|
|
this.scr_ = scr;
|
|
this.cursor_vis_ = true;
|
|
this.getch_isr_ = undefined;
|
|
this.grab_events_ = false;
|
|
this.key_buf_ = [];
|
|
this.esc_state_ = 0;
|
|
this.col_ = 0;
|
|
this.row_ = 0;
|
|
// Internal debug setting.
|
|
this.clear();
|
|
//this.refresh();
|
|
}
|
|
|
|
VD.A_REVERSE = 2;
|
|
VD.A_BLINK = 4;
|
|
|
|
VD.browser_ie_ = (navigator.appName.indexOf("Microsoft") != -1);
|
|
VD.browser_opera_ = (navigator.appName.indexOf("Opera") != -1);
|
|
// class variables
|
|
VD.the_vt_ = undefined;
|
|
|
|
// object methods
|
|
|
|
VD.prototype.html_colours_ = function(at_fg, at_bg, at_mode)
|
|
{
|
|
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.clear = function()
|
|
{
|
|
this.row_ = this.col_ = 0;
|
|
for (r = 0; r < this.ht_; ++r) {
|
|
for (c = 0; c < this.wd_; ++c) {
|
|
this.text_[r][c] = ' ';
|
|
}
|
|
}
|
|
}
|
|
|
|
VD.prototype.curs_set = function(vis, grab, eventist)
|
|
{
|
|
if (vis !== undefined)
|
|
this.cursor_vis_ = (vis > 0);
|
|
}
|
|
|
|
VD.prototype.getch = function(isr)
|
|
{
|
|
// this.refresh();
|
|
this.getch_isr_ = isr;
|
|
setTimeout(VD.go_getch_, 0);
|
|
}
|
|
|
|
VD.go_getch_ = function VD_go_getch()
|
|
{
|
|
var vt = VD.the_vt_;
|
|
if (vt === undefined)
|
|
return;
|
|
var isr = vt.getch_isr_;
|
|
vt.getch_isr_ = undefined;
|
|
if (isr === undefined)
|
|
return;
|
|
var ch = vt.key_buf_.shift();
|
|
if (ch === undefined) {
|
|
vt.getch_isr_ = isr;
|
|
return;
|
|
}
|
|
isr(ch, vt);
|
|
}
|
|
|
|
VD.prototype.move = function(r, c)
|
|
{
|
|
if (r < 0)
|
|
r = 0;
|
|
else if (r >= this.ht_)
|
|
r = this.ht_ - 1;
|
|
if (c < 0)
|
|
c = 0;
|
|
else if (c >= this.wd_)
|
|
c = this.wd_ - 1;
|
|
this.row_ = r;
|
|
this.col_ = c;
|
|
}
|
|
|
|
|
|
VD.prototype.refresh = function()
|
|
{
|
|
var r, c, stuff = "", start_tag = "", end_tag = "", ch,
|
|
pair, cr, cc, ht, wd, cv, n_fg, n_bg, n_mode, n_type, a_fg=-1, a_bg=-1, a_mode=-1;
|
|
ht = this.ht_;
|
|
wd = this.wd_;
|
|
cr = this.row_;
|
|
cc = this.col_;
|
|
cv = this.cursor_vis_;
|
|
// var innerHTML = this.scr_.innerHTML;
|
|
if (cc >= wd)
|
|
cc = wd - 1;
|
|
for (r = 0; r < ht; ++r) {
|
|
if (r > 0) {
|
|
stuff += '\n';
|
|
}
|
|
n_fg = 7;
|
|
n_bg = 0;
|
|
n_mode = 0;
|
|
n_type = 0;
|
|
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;
|
|
}
|
|
|
|
ch = this.text_[r][c];
|
|
//console.log('CH: %i (%s) [%i,%i]',ch.charCodeAt(0),ch,r,c);
|
|
if (ch.charCodeAt(0) >= 129 && ch.charCodeAt(0) <= 135) {
|
|
n_fg = ch.charCodeAt(0)-128;
|
|
n_type &= ~2;
|
|
n_type &= ~16;
|
|
}
|
|
if (ch.charCodeAt(0) >= 145 && ch.charCodeAt(0) <= 151) {
|
|
n_fg = ch.charCodeAt(0)-144;
|
|
n_type |= 2;
|
|
n_type &= ~16;
|
|
}
|
|
if (ch == '\x88')
|
|
n_mode |= VD.A_BLINK;
|
|
if (ch == '\x89')
|
|
n_mode &= ~VD.A_BLINK;
|
|
if (ch == '\x8c')
|
|
n_type &= ~8;
|
|
if (ch == '\x8d')
|
|
n_type |= 8;
|
|
if (ch == '\x98')
|
|
n_type |= 16;
|
|
if (ch == '\x99')
|
|
n_type &= ~1;
|
|
if (ch == '\x9a')
|
|
n_type |= 1;
|
|
if (ch == '\x9c')
|
|
n_bg = 0;
|
|
if (ch == '\x9d')
|
|
n_bg = n_fg;
|
|
if (ch == '\x9e')
|
|
n_type |= 32;
|
|
if (ch == '\x9f')
|
|
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);
|
|
stuff += '<span style="color:' + pair.f + ';background-color:' + pair.b + ';">';
|
|
// + (n_mode & VD.A_BLINK ? ' class="blink"' : '') + '>';
|
|
end_tag = "</span>";
|
|
a_fg = n_fg;
|
|
a_bg = n_bg;
|
|
a_mode = n_mode;
|
|
}
|
|
|
|
if (ch.charCodeAt(0) >= 128)
|
|
ch = ' ';
|
|
|
|
if (n_type & 2) {
|
|
if ( ch.charCodeAt(0) >= 0x20 && ch.charCodeAt(0) <= 0x3f) {
|
|
ch = '&#x' + (ch.charCodeAt(0)+0xe1e0+((n_type & 1)*0xc0)).toString(16) +";";
|
|
} else if ( ch.charCodeAt(0) >= 0x60 && ch.charCodeAt(0) <= 0x7f) {
|
|
ch = '&#x' + (ch.charCodeAt(0)+0xe1c0+((n_type & 1)*0xc0)).toString(16) +";";
|
|
}
|
|
}
|
|
|
|
switch (ch) {
|
|
case '&':
|
|
stuff += '&'; break;
|
|
case '<':
|
|
stuff += '<'; break;
|
|
case '>':
|
|
stuff += '>'; break;
|
|
case ' ':
|
|
// stuff += ' '; break;
|
|
stuff += '\xa0'; break;
|
|
case '\x7e':
|
|
case '~':
|
|
stuff += '\xf7'; break;
|
|
case '\x7f':
|
|
stuff += ""; break
|
|
case '_':
|
|
stuff += '#'; break
|
|
case '{':
|
|
stuff += '\xbc'; break
|
|
case '\\':
|
|
stuff += '\xbd'; break
|
|
case '}':
|
|
stuff += '\xbe'; break
|
|
case '#':
|
|
stuff += '\xa3'; break
|
|
default:
|
|
stuff += ch;
|
|
}
|
|
}
|
|
}
|
|
stuff += end_tag
|
|
//this.scr_.innerHTML = "<b>" + stuff + "</b>\n";
|
|
this.scr_.innerHTML = stuff + "\n";
|
|
}
|
|
|
|
|
|
VD.prototype.write = function(stuff)
|
|
{
|
|
var ch, i;
|
|
for (i = 0; i < stuff.length; ++i) {
|
|
ch = stuff.charCodeAt(i);
|
|
if (this.esc_state_ && ch > 31)
|
|
ch = (ch % 32) + 128;
|
|
this.esc_state_ = 0;
|
|
switch (ch) {
|
|
case 8:
|
|
if (this.col_ != 0) {
|
|
--this.col_;
|
|
} else {
|
|
this.col_ = this.wd_-1;
|
|
if (this.row_ == 0) {
|
|
this.row_ = this.ht_-1;
|
|
} else {
|
|
--this.row_;
|
|
}
|
|
}
|
|
break;
|
|
case 9:
|
|
if (this.col_ >= this.wd_) {
|
|
this.col_ = 0;
|
|
if (this.row_ == this.ht_-1) {
|
|
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);
|
|
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_;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
this.refresh();
|
|
}
|