Mercurial > hg > rlgwebd
comparison termemu.js @ 4:ee22eb9ab009
Client: don't assume the terminal is 24x80.
author | John "Elwin" Edwards <elwin@sdf.org> |
---|---|
date | Mon, 07 May 2012 11:09:14 -0700 |
parents | bd412f63ce0d |
children | 826a7ced69f8 |
comparison
equal
deleted
inserted
replaced
3:bfdc775a574f | 4:ee22eb9ab009 |
---|---|
59 view: null, // The div holding the terminal screen | 59 view: null, // The div holding the terminal screen |
60 screen: null, // The div representing the active screen area | 60 screen: null, // The div representing the active screen area |
61 normbuf: null, // The normal screen buffer | 61 normbuf: null, // The normal screen buffer |
62 altbuf: null, // The alternate screen buffer | 62 altbuf: null, // The alternate screen buffer |
63 histbuf: null, // The screen history buffer | 63 histbuf: null, // The screen history buffer |
64 /* Attributes */ | |
65 w: 0, // Screen width | |
66 h: 0, // Screen height | |
64 fgColor: "#b2b2b2", // Default color for text | 67 fgColor: "#b2b2b2", // Default color for text |
65 bgColor: "black", // Default background color | 68 bgColor: "black", // Default background color |
69 scrT: 0, // top and bottom of scrolling region | |
70 scrB: 0, // init() will set this properly | |
66 c: null, // Contains cursor position and text attributes | 71 c: null, // Contains cursor position and text attributes |
67 offedge: false, // Going off the edge doesn't mean adding a new line | 72 offedge: false, // Going off the edge doesn't mean adding a new line |
68 clearAttrs: function () { | 73 clearAttrs: function () { |
69 /* Make sure to reset ALL attribute properties and NOTHING else. */ | 74 /* Make sure to reset ALL attribute properties and NOTHING else. */ |
70 this.c.bold = false; | 75 this.c.bold = false; |
121 return "#" + colstr + colstr + colstr; | 126 return "#" + colstr + colstr + colstr; |
122 } | 127 } |
123 else | 128 else |
124 return fallback; | 129 return fallback; |
125 }, | 130 }, |
126 scrT: 0, // top and bottom of scrolling region | |
127 scrB: 23, | |
128 // These keyboard-related things don't really belong here. | 131 // These keyboard-related things don't really belong here. |
129 shift: false, | 132 shift: false, |
130 shiftp: function () { | 133 shiftp: function () { |
131 return this.shift; | 134 return this.shift; |
132 }, | 135 }, |
138 return this.ctrl; | 141 return this.ctrl; |
139 }, | 142 }, |
140 togglectrl: function () { | 143 togglectrl: function () { |
141 this.ctrl = !this.ctrl; | 144 this.ctrl = !this.ctrl; |
142 }, | 145 }, |
143 init: function (divID) { | 146 init: function (divID, h, w) { |
144 /* Makes a div full of character cells. */ | 147 /* Makes a div full of character cells. */ |
145 if (this.screen != null) | 148 if (this.screen != null) |
146 return; | 149 return; |
147 var owrap = document.getElementById(divID); | 150 var owrap = document.getElementById(divID); |
148 if (!owrap) | 151 if (!owrap) |
149 return; | 152 return; |
150 while (owrap.firstChild != null) | 153 while (owrap.firstChild != null) |
151 owrap.removeChild(owrap.firstChild); | 154 owrap.removeChild(owrap.firstChild); |
152 this.c = new Cursor(null); | 155 this.c = new Cursor(null); |
156 /* Set up the sizes. */ | |
157 var tn; | |
158 tn = Number(h); | |
159 if (tn > 0 && tn < 256) | |
160 this.h = tn; | |
161 else | |
162 this.h = 24; | |
163 tn = Number(w); | |
164 if (tn > 0 && tn < 256) | |
165 this.w = tn; | |
166 else | |
167 this.w = 80; | |
168 this.scrB = this.h - 1; | |
153 /* Create the contents of the terminal div */ | 169 /* Create the contents of the terminal div */ |
154 this.inwrap = document.createElement("div"); | 170 this.inwrap = document.createElement("div"); |
155 this.inwrap.id = "inwrap"; | 171 this.inwrap.id = "inwrap"; |
156 owrap.appendChild(this.inwrap); | 172 owrap.appendChild(this.inwrap); |
157 var termdiv = document.createElement("div"); | 173 var termdiv = document.createElement("div"); |
163 this.histbuf.id = "histbuf"; | 179 this.histbuf.id = "histbuf"; |
164 termdiv.appendChild(this.histbuf); | 180 termdiv.appendChild(this.histbuf); |
165 this.normbuf = document.createElement("div"); | 181 this.normbuf = document.createElement("div"); |
166 this.normbuf.id = "normbuf"; | 182 this.normbuf.id = "normbuf"; |
167 termdiv.appendChild(this.normbuf); | 183 termdiv.appendChild(this.normbuf); |
168 for (var row = 0; row < 24; row++) { | 184 for (var row = 0; row < this.h; row++) { |
169 this.normbuf.appendChild(this.makeRow()); | 185 this.normbuf.appendChild(this.makeRow()); |
170 } | 186 } |
171 this.altbuf = document.createElement("div"); | 187 this.altbuf = document.createElement("div"); |
172 this.altbuf.id = "altbuf"; | 188 this.altbuf.id = "altbuf"; |
173 termdiv.appendChild(this.altbuf); | 189 termdiv.appendChild(this.altbuf); |
225 toAltBuf: function () { | 241 toAltBuf: function () { |
226 if (this.screen == this.altbuf) | 242 if (this.screen == this.altbuf) |
227 return; | 243 return; |
228 while (this.altbuf.firstChild != null) | 244 while (this.altbuf.firstChild != null) |
229 this.altbuf.removeChild(this.altbuf.firstChild); | 245 this.altbuf.removeChild(this.altbuf.firstChild); |
230 for (var i = 0; i < 24; i++) { | 246 for (var i = 0; i < this.h; i++) { |
231 this.altbuf.appendChild(this.makeRow()); | 247 this.altbuf.appendChild(this.makeRow()); |
232 } | 248 } |
233 this.normc = new Cursor(this.c); | 249 this.normc = new Cursor(this.c); |
234 this.altbuf.style.display = "table-row-group"; | 250 this.altbuf.style.display = "table-row-group"; |
235 this.normbuf.style.display = "none"; | 251 this.normbuf.style.display = "none"; |
264 } | 280 } |
265 else { | 281 else { |
266 this.offedge = false; | 282 this.offedge = false; |
267 if (x < 0) | 283 if (x < 0) |
268 x = 0; | 284 x = 0; |
269 else if (x > 79) | 285 else if (x >= this.w) |
270 x = 79; | 286 x = this.w - 1; |
271 } | 287 } |
272 if (y == null) { | 288 if (y == null) { |
273 if (this.c.y != null) | 289 if (this.c.y != null) |
274 y = this.c.y; | 290 y = this.c.y; |
275 else | 291 else |
276 return; | 292 return; |
277 } | 293 } |
278 else if (y < 0) | 294 else if (y < 0) |
279 y = 0; | 295 y = 0; |
280 else if (y > 23) | 296 else if (y >= this.h) |
281 y = 23; | 297 y = this.h - 1; |
282 /* Un-reverse video the current location. */ | 298 /* Un-reverse video the current location. */ |
283 this.flipCursor(); | 299 this.flipCursor(); |
284 this.c.x = x; | 300 this.c.x = x; |
285 this.c.y = y; | 301 this.c.y = y; |
286 /* Reverse-video the new location. */ | 302 /* Reverse-video the new location. */ |
312 this.flipCursor(); | 328 this.flipCursor(); |
313 while (count > 0) { | 329 while (count > 0) { |
314 var blankrow = this.makeRow(); | 330 var blankrow = this.makeRow(); |
315 /* Careful with the order */ | 331 /* Careful with the order */ |
316 if (lines > 0) { | 332 if (lines > 0) { |
317 if (this.scrB == 23) | 333 if (this.scrB == this.h - 1) |
318 this.screen.appendChild(blankrow); | 334 this.screen.appendChild(blankrow); |
319 else | 335 else |
320 this.screen.insertBefore(blankrow, this.screen.childNodes[this.scrB | 336 this.screen.insertBefore(blankrow, this.screen.childNodes[this.scrB |
321 + 1]); | 337 + 1]); |
322 this.historize(this.scrT); | 338 this.historize(this.scrT); |
332 this.flipCursor(); | 348 this.flipCursor(); |
333 return; | 349 return; |
334 }, | 350 }, |
335 newline: function (doReturn) { | 351 newline: function (doReturn) { |
336 if (this.c.y == this.scrB) | 352 if (this.c.y == this.scrB) |
337 this.scroll(1) | 353 this.scroll(1); |
338 else if (this.c.y < 23) | 354 else if (this.c.y < this.h - 1) |
339 this.cmove(this.c.y + 1, null); | 355 this.cmove(this.c.y + 1, null); |
340 /* If the cursor is at the bottom but outside the scrolling region, | 356 /* If the cursor is at the bottom but outside the scrolling region, |
341 * nothing can be done. */ | 357 * nothing can be done. */ |
342 if (doReturn) { | 358 if (doReturn) { |
343 this.cmove(null, 0); | 359 this.cmove(null, 0); |
348 this.scroll(-1); | 364 this.scroll(-1); |
349 else if (this.c.y > 0) | 365 else if (this.c.y > 0) |
350 this.cmove(this.c.y - 1, null); | 366 this.cmove(this.c.y - 1, null); |
351 }, | 367 }, |
352 advance: function () { | 368 advance: function () { |
353 if (this.c.x < 79) | 369 if (this.c.x < this.w - 1) |
354 this.cmove(null, this.c.x + 1); | 370 this.cmove(null, this.c.x + 1); |
355 else { | 371 else { |
356 this.offedge = true; | 372 this.offedge = true; |
357 } | 373 } |
358 }, | 374 }, |
376 this.c.cset = 'B'; | 392 this.c.cset = 'B'; |
377 this.cmove(0, 0); | 393 this.cmove(0, 0); |
378 this.saved = null; | 394 this.saved = null; |
379 this.normc = null; | 395 this.normc = null; |
380 this.scrT = 0; | 396 this.scrT = 0; |
381 this.scrB = 23; | 397 this.scrB = this.h - 1; |
382 while (this.histbuf.firstChild != null) { | 398 while (this.histbuf.firstChild != null) { |
383 this.histbuf.removeChild(this.histbuf.firstChild); | 399 this.histbuf.removeChild(this.histbuf.firstChild); |
384 } | 400 } |
385 for (var i = 0; i < 24; i++) { | 401 for (var i = 0; i < this.h; i++) { |
386 this.screen.replaceChild(this.makeRow(), this.screen.childNodes[i]); | 402 this.screen.replaceChild(this.makeRow(), this.screen.childNodes[i]); |
387 } | 403 } |
388 this.flipCursor(); // make it appear in the new row | 404 this.flipCursor(); // make it appear in the new row |
389 return; | 405 return; |
390 }, | 406 }, |
555 this.cmove(null, this.c.x - 1); | 571 this.cmove(null, this.c.x - 1); |
556 } | 572 } |
557 else if (codes[i] == 9) { | 573 else if (codes[i] == 9) { |
558 /* tab */ | 574 /* tab */ |
559 var xnew; | 575 var xnew; |
560 if (this.c.x < 79) { | 576 if (this.c.x < this.w - 1) { |
561 xnew = 8 * (Math.floor(this.c.x / 8) + 1); | 577 xnew = 8 * (Math.floor(this.c.x / 8) + 1); |
562 if (xnew > 79) | 578 if (xnew >= this.w) |
563 xnew = 79; | 579 xnew = this.w - 1; |
564 this.cmove(null, xnew); | 580 this.cmove(null, xnew); |
565 } | 581 } |
566 else { | 582 else { |
567 this.offedge = true; | 583 this.offedge = true; |
568 } | 584 } |
699 } | 715 } |
700 if (params[0]) | 716 if (params[0]) |
701 y = params[0] - 1; | 717 y = params[0] - 1; |
702 if (params[1]) | 718 if (params[1]) |
703 x = params[1] - 1; | 719 x = params[1] - 1; |
704 if (y > 23) | 720 if (y >= this.h) |
705 y = 23; | 721 y = this.h - 1; |
706 if (x > 79) | 722 if (x >= this.w) |
707 x = 79; | 723 x = this.w - 1; |
708 debug(0, "Moving to row " + y + ", col " + x); | 724 debug(0, "Moving to row " + y + ", col " + x); |
709 this.cmove(y, x); | 725 this.cmove(y, x); |
710 } | 726 } |
711 else if (c == 73) { | 727 else if (c == 73) { |
712 /* I - move forward by tabs */ | 728 /* I - move forward by tabs */ |
715 debug(1, "Invalid CSI I sequence: " + comstr); | 731 debug(1, "Invalid CSI I sequence: " + comstr); |
716 return; | 732 return; |
717 } | 733 } |
718 while (count > 0) { | 734 while (count > 0) { |
719 x = 8 * (Math.floor(x / 8) + 1); | 735 x = 8 * (Math.floor(x / 8) + 1); |
720 if (x > 79) { | 736 if (x >= this.w) { |
721 x = 79; | 737 x = this.w - 1; |
722 break; | 738 break; |
723 } | 739 } |
724 count--; | 740 count--; |
725 } | 741 } |
726 this.cmove(null, x); | 742 this.cmove(null, x); |
737 return; | 753 return; |
738 } | 754 } |
739 if (!params[0]) { | 755 if (!params[0]) { |
740 /* Either 0 or not given */ | 756 /* Either 0 or not given */ |
741 start = this.c.y + 1; | 757 start = this.c.y + 1; |
742 end = 23; | 758 end = this.h - 1; |
743 cols = 1; | 759 cols = 1; |
744 } | 760 } |
745 else if (params[0] == 1) { | 761 else if (params[0] == 1) { |
746 start = 0; | 762 start = 0; |
747 end = this.c.y - 1; | 763 end = this.c.y - 1; |
748 cols = -1; | 764 cols = -1; |
749 } | 765 } |
750 else if (params[0] == 2) { | 766 else if (params[0] == 2) { |
751 start = 0; | 767 start = 0; |
752 end = 23; | 768 end = this.h - 1; |
753 cols = 0; | 769 cols = 0; |
754 } | 770 } |
755 else { | 771 else { |
756 debug(1, "Unimplemented parameter in CSI J sequence: " + comstr); | 772 debug(1, "Unimplemented parameter in CSI J sequence: " + comstr); |
757 return; | 773 return; |
761 } | 777 } |
762 if (cols != 0) { | 778 if (cols != 0) { |
763 /* Otherwise, the whole screen was erased and the active row doesn't | 779 /* Otherwise, the whole screen was erased and the active row doesn't |
764 * need special treatment. */ | 780 * need special treatment. */ |
765 var cursrow = this.screen.childNodes[this.c.y]; | 781 var cursrow = this.screen.childNodes[this.c.y]; |
766 for (var ncol = this.c.x; ncol >= 0 && ncol < 80; ncol += cols) { | 782 for (var ncol = this.c.x; ncol >= 0 && ncol < this.w; ncol += cols) { |
767 cursrow.replaceChild(this.makeCell(' '), cursrow.childNodes[ncol]); | 783 cursrow.replaceChild(this.makeCell(' '), cursrow.childNodes[ncol]); |
768 } | 784 } |
769 } | 785 } |
770 this.offedge = false; | 786 this.offedge = false; |
771 /* Always flip after replacing the active position. */ | 787 /* Always flip after replacing the active position. */ |
788 start = 0; | 804 start = 0; |
789 end = this.c.x; | 805 end = this.c.x; |
790 } | 806 } |
791 else if (params[0] == 2) { | 807 else if (params[0] == 2) { |
792 start = 0; | 808 start = 0; |
793 end = 79; | 809 end = this.w - 1; |
794 } | 810 } |
795 else { | 811 else { |
796 start = this.c.x; | 812 start = this.c.x; |
797 end = 79; | 813 end = this.w - 1; |
798 } | 814 } |
799 var rowdiv = this.screen.childNodes[this.c.y]; | 815 var rowdiv = this.screen.childNodes[this.c.y]; |
800 for (var i = start; i <= end; i++) { | 816 for (var i = start; i <= end; i++) { |
801 rowdiv.replaceChild(this.makeCell(' '), rowdiv.childNodes[i]); | 817 rowdiv.replaceChild(this.makeCell(' '), rowdiv.childNodes[i]); |
802 } | 818 } |
822 if (c == 76) { | 838 if (c == 76) { |
823 this.historize(this.scrB); | 839 this.historize(this.scrB); |
824 this.screen.insertBefore(blankrow, this.screen.childNodes[this.c.y]); | 840 this.screen.insertBefore(blankrow, this.screen.childNodes[this.c.y]); |
825 } | 841 } |
826 else { | 842 else { |
827 if (this.scrB == 23) | 843 if (this.scrB == this.h - 1) |
828 this.screen.appendChild(blankrow); | 844 this.screen.appendChild(blankrow); |
829 else | 845 else |
830 this.screen.insertBefore(blankrow, this.screen.childNodes[this.scrB | 846 this.screen.insertBefore(blankrow, this.screen.childNodes[this.scrB |
831 + 1]); | 847 + 1]); |
832 this.historize(this.c.y); | 848 this.historize(this.c.y); |
868 if (prefix || postfix) { | 884 if (prefix || postfix) { |
869 debug(1, "Invalid CSI sequence: " + comstr); | 885 debug(1, "Invalid CSI sequence: " + comstr); |
870 return; | 886 return; |
871 } | 887 } |
872 var row = this.screen.childNodes[this.c.y]; | 888 var row = this.screen.childNodes[this.c.y]; |
873 for (var i = 0; i < count && this.c.x + i < 80; i++) { | 889 for (var i = 0; i < count && this.c.x + i < this.w; i++) { |
874 row.replaceChild(this.makeCell(' '), row.childNodes[this.c.x + i]); | 890 row.replaceChild(this.makeCell(' '), row.childNodes[this.c.x + i]); |
875 } | 891 } |
876 this.flipCursor(); | 892 this.flipCursor(); |
877 } | 893 } |
878 else if (c == 90) { | 894 else if (c == 90) { |
1010 } | 1026 } |
1011 } | 1027 } |
1012 else if (c == 114) { | 1028 else if (c == 114) { |
1013 /* r - set scrolling region */ | 1029 /* r - set scrolling region */ |
1014 var t = 0; | 1030 var t = 0; |
1015 var b = 23; | 1031 var b = this.h - 1; |
1016 if (params[0] && params[0] <= 23) | 1032 if (params[0] && params[0] <= this.h - 1) |
1017 t = params[0] - 1; | 1033 t = params[0] - 1; |
1018 if (params[1] && params[1] <= 24) | 1034 if (params[1] && params[1] <= this.h) |
1019 b = params[1] - 1; | 1035 b = params[1] - 1; |
1020 if (b <= t) | 1036 if (b <= t) |
1021 return; | 1037 return; |
1022 this.scrT = t; | 1038 this.scrT = t; |
1023 this.scrB = b; | 1039 this.scrB = b; |
1074 return cell; | 1090 return cell; |
1075 }, | 1091 }, |
1076 makeRow: function() { | 1092 makeRow: function() { |
1077 var blankrow = document.createElement("div"); | 1093 var blankrow = document.createElement("div"); |
1078 blankrow.className = "termrow"; | 1094 blankrow.className = "termrow"; |
1079 for (var i = 0; i < 80; i++) | 1095 for (var i = 0; i < this.w; i++) |
1080 blankrow.appendChild(this.makeCell(' ')); | 1096 blankrow.appendChild(this.makeCell(' ')); |
1081 return blankrow; | 1097 return blankrow; |
1082 } | 1098 } |
1083 }; | 1099 }; |
1084 | 1100 |