// 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 += ''; // + (n_mode & VD.A_BLINK ? ' class="blink"' : '') + '>'; end_tag = ""; 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 = "" + stuff + "\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(); }