Included example style sheets that allow switching to white-on-black or to

monochrome mode from the right click context menu. This required a couple of
architectural changes to the JavaScript code.


git-svn-id: https://shellinabox.googlecode.com/svn/trunk@167 0da03de8-d603-11dd-86c2-0f8696b7b6f9
This commit is contained in:
zodiac 2009-08-12 02:32:26 +00:00
parent 71ba8641c1
commit 341eb1982c
26 changed files with 753 additions and 429 deletions

View file

@ -1,3 +1,11 @@
2009-08-11 Markus Gutschke <markus@shellinabox.com>
* Added support for user selectable style sheets. Included example
style sheets that allow switching to white-on-black or to monochrome
mode from the right click context menu.
* Fixed the "|" key on Swedish keyboards.
2009-07-30 Markus Gutschke <markus@shellinabox.com>
* Added the --css command line option to make incremental changes

View file

@ -16,15 +16,23 @@ dist_doc_DATA = AUTHORS \
NEWS \
README \
TODO \
shellinabox/white-on-black.css
shellinabox/white-on-black.css \
shellinabox/black-on-white.css \
shellinabox/monochrome.css \
shellinabox/color.css
EXTRA_DIST = demo/beep.wav \
demo/favicon.ico \
demo/demo.html \
demo/demo.js \
demo/demo.jspp \
demo/demo.xml \
demo/enabled.gif \
demo/styles.css \
demo/vt100.js \
demo/usercss-0.css \
demo/usercss-1.css \
demo/usercss-2.css \
demo/usercss-3.css \
shellinabox/shellinaboxd.man.in \
shellinabox/shell_in_a_box.js \
shellinabox/vt100.js \
@ -83,6 +91,7 @@ shellinaboxd_SOURCES = shellinabox/shellinaboxd.c \
shellinabox/vt100.jspp \
shellinabox/shell_in_a_box.jspp \
shellinabox/styles.css \
shellinabox/enabled.gif \
shellinabox/favicon.ico \
shellinabox/beep.wav \
config.h
@ -122,12 +131,20 @@ ${top_srcdir}/demo/demo.js: ${top_srcdir}/demo/beep.wav \
${top_srcdir}/demo/demo.jspp \
${top_srcdir}/demo/favicon.ico \
${top_srcdir}/demo/styles.css \
${top_srcdir}/demo/vt100.js
${top_srcdir}/demo/vt100.js \
${top_srcdir}/demo/usercss-0.css \
${top_srcdir}/demo/usercss-1.css \
${top_srcdir}/demo/usercss-2.css \
${top_srcdir}/demo/usercss-3.css
${top_srcdir}/demo/beep.wav: ${top_srcdir}/shellinabox/beep.wav
@rm -f "$@"
ln "$<" "$@"
${top_srcdir}/demo/enabled.gif: ${top_srcdir}/shellinabox/enabled.gif
@rm -f "$@"
ln "$<" "$@"
${top_srcdir}/demo/favicon.ico: ${top_srcdir}/shellinabox/favicon.ico
@rm -f "$@"
ln "$<" "$@"
@ -136,6 +153,22 @@ ${top_srcdir}/demo/styles.css: ${top_srcdir}/shellinabox/styles.css
@rm -f "$@"
ln "$<" "$@"
${top_srcdir}/demo/usercss-0.css: ${top_srcdir}/shellinabox/white-on-black.css
@rm -f "$@"
ln "$<" "$@"
${top_srcdir}/demo/usercss-1.css: ${top_srcdir}/shellinabox/black-on-white.css
@rm -f "$@"
ln "$<" "$@"
${top_srcdir}/demo/usercss-2.css: ${top_srcdir}/shellinabox/monochrome.css
@rm -f "$@"
ln "$<" "$@"
${top_srcdir}/demo/usercss-3.css: ${top_srcdir}/shellinabox/color.css
@rm -f "$@"
ln "$<" "$@"
${top_srcdir}/demo/vt100.js: ${top_srcdir}/shellinabox/vt100.js
@rm -f "$@"
ln "$<" "$@"
@ -178,6 +211,11 @@ clean-local:
@objcopy -I binary `$(objcopyflags)` `echo "$<" | $(renamesymbols)` \
"$<" "$@"
.gif.o:
@echo objcopy "$<" "$@"
@objcopy -I binary `$(objcopyflags)` `echo "$<" | $(renamesymbols)` \
"$<" "$@"
.html.o:
@echo objcopy "$<" "$@"
@objcopy -I binary `$(objcopyflags)` `echo "$<" | $(renamesymbols)` \

View file

@ -77,8 +77,8 @@ am_shellinaboxd_OBJECTS = shellinaboxd.$(OBJEXT) \
shellinabox/cgi_root.$(OBJEXT) shellinabox/root_page.$(OBJEXT) \
shellinabox/vt100.$(OBJEXT) \
shellinabox/shell_in_a_box.$(OBJEXT) \
shellinabox/styles.$(OBJEXT) shellinabox/favicon.$(OBJEXT) \
shellinabox/beep.$(OBJEXT)
shellinabox/styles.$(OBJEXT) shellinabox/enabled.$(OBJEXT) \
shellinabox/favicon.$(OBJEXT) shellinabox/beep.$(OBJEXT)
shellinaboxd_OBJECTS = $(am_shellinaboxd_OBJECTS)
shellinaboxd_DEPENDENCIES = liblogging.la libhttp.la
shellinaboxd_LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) \
@ -255,7 +255,10 @@ dist_doc_DATA = AUTHORS \
NEWS \
README \
TODO \
shellinabox/white-on-black.css
shellinabox/white-on-black.css \
shellinabox/black-on-white.css \
shellinabox/monochrome.css \
shellinabox/color.css
EXTRA_DIST = demo/beep.wav \
demo/favicon.ico \
@ -263,8 +266,13 @@ EXTRA_DIST = demo/beep.wav \
demo/demo.js \
demo/demo.jspp \
demo/demo.xml \
demo/enabled.gif \
demo/styles.css \
demo/vt100.js \
demo/usercss-0.css \
demo/usercss-1.css \
demo/usercss-2.css \
demo/usercss-3.css \
shellinabox/shellinaboxd.man.in \
shellinabox/shell_in_a_box.js \
shellinabox/vt100.js \
@ -327,6 +335,7 @@ shellinaboxd_SOURCES = shellinabox/shellinaboxd.c \
shellinabox/vt100.jspp \
shellinabox/shell_in_a_box.jspp \
shellinabox/styles.css \
shellinabox/enabled.gif \
shellinabox/favicon.ico \
shellinabox/beep.wav \
config.h
@ -363,7 +372,7 @@ all: config.h
$(MAKE) $(AM_MAKEFLAGS) all-am
.SUFFIXES:
.SUFFIXES: .c .css .html .ico .js .jspp .lo .o .obj .wav
.SUFFIXES: .c .css .gif .html .ico .js .jspp .lo .o .obj .wav
am--refresh:
@:
$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps)
@ -471,6 +480,8 @@ shellinabox/shell_in_a_box.$(OBJEXT): shellinabox/$(am__dirstamp) \
shellinabox/$(DEPDIR)/$(am__dirstamp)
shellinabox/styles.$(OBJEXT): shellinabox/$(am__dirstamp) \
shellinabox/$(DEPDIR)/$(am__dirstamp)
shellinabox/enabled.$(OBJEXT): shellinabox/$(am__dirstamp) \
shellinabox/$(DEPDIR)/$(am__dirstamp)
shellinabox/favicon.$(OBJEXT): shellinabox/$(am__dirstamp) \
shellinabox/$(DEPDIR)/$(am__dirstamp)
shellinabox/beep.$(OBJEXT): shellinabox/$(am__dirstamp) \
@ -483,6 +494,7 @@ mostlyclean-compile:
-rm -f *.$(OBJEXT)
-rm -f shellinabox/beep.$(OBJEXT)
-rm -f shellinabox/cgi_root.$(OBJEXT)
-rm -f shellinabox/enabled.$(OBJEXT)
-rm -f shellinabox/favicon.$(OBJEXT)
-rm -f shellinabox/root_page.$(OBJEXT)
-rm -f shellinabox/shell_in_a_box.$(OBJEXT)
@ -1052,12 +1064,20 @@ ${top_srcdir}/demo/demo.js: ${top_srcdir}/demo/beep.wav \
${top_srcdir}/demo/demo.jspp \
${top_srcdir}/demo/favicon.ico \
${top_srcdir}/demo/styles.css \
${top_srcdir}/demo/vt100.js
${top_srcdir}/demo/vt100.js \
${top_srcdir}/demo/usercss-0.css \
${top_srcdir}/demo/usercss-1.css \
${top_srcdir}/demo/usercss-2.css \
${top_srcdir}/demo/usercss-3.css
${top_srcdir}/demo/beep.wav: ${top_srcdir}/shellinabox/beep.wav
@rm -f "$@"
ln "$<" "$@"
${top_srcdir}/demo/enabled.gif: ${top_srcdir}/shellinabox/enabled.gif
@rm -f "$@"
ln "$<" "$@"
${top_srcdir}/demo/favicon.ico: ${top_srcdir}/shellinabox/favicon.ico
@rm -f "$@"
ln "$<" "$@"
@ -1066,6 +1086,22 @@ ${top_srcdir}/demo/styles.css: ${top_srcdir}/shellinabox/styles.css
@rm -f "$@"
ln "$<" "$@"
${top_srcdir}/demo/usercss-0.css: ${top_srcdir}/shellinabox/white-on-black.css
@rm -f "$@"
ln "$<" "$@"
${top_srcdir}/demo/usercss-1.css: ${top_srcdir}/shellinabox/black-on-white.css
@rm -f "$@"
ln "$<" "$@"
${top_srcdir}/demo/usercss-2.css: ${top_srcdir}/shellinabox/monochrome.css
@rm -f "$@"
ln "$<" "$@"
${top_srcdir}/demo/usercss-3.css: ${top_srcdir}/shellinabox/color.css
@rm -f "$@"
ln "$<" "$@"
${top_srcdir}/demo/vt100.js: ${top_srcdir}/shellinabox/vt100.js
@rm -f "$@"
ln "$<" "$@"
@ -1108,6 +1144,11 @@ clean-local:
@objcopy -I binary `$(objcopyflags)` `echo "$<" | $(renamesymbols)` \
"$<" "$@"
.gif.o:
@echo objcopy "$<" "$@"
@objcopy -I binary `$(objcopyflags)` `echo "$<" | $(renamesymbols)` \
"$<" "$@"
.html.o:
@echo objcopy "$<" "$@"
@objcopy -I binary `$(objcopyflags)` `echo "$<" | $(renamesymbols)` \

View file

@ -138,7 +138,7 @@
#define STDC_HEADERS 1
/* Most recent revision number in the version control system */
#define VCS_REVISION "166"
#define VCS_REVISION "167"
/* Version number of package */
#define VERSION "2.9"

2
configure vendored
View file

@ -2317,7 +2317,7 @@ ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $
ac_compiler_gnu=$ac_cv_c_compiler_gnu
VCS_REVISION=166
VCS_REVISION=167
cat >>confdefs.h <<_ACEOF

View file

@ -2,7 +2,7 @@ AC_PREREQ(2.57)
dnl This is the one location where the authoritative version number is stored
AC_INIT(shellinabox, 2.9, markus@shellinabox.com)
VCS_REVISION=166
VCS_REVISION=167
AC_SUBST(VCS_REVISION)
AC_DEFINE_UNQUOTED(VCS_REVISION, "${VCS_REVISION}",
[Most recent revision number in the version control system])

3
debian/docs vendored
View file

@ -6,3 +6,6 @@ NEWS
README
TODO
shellinabox/white-on-black.css
shellinabox/black-on-white.css
shellinabox/monochrome.css
shellinabox/color.css

View file

@ -64,6 +64,13 @@
'}' +
'</style>');
}
suppressAllAudio = true;
linkifyURLs = 1;
userCSSList = [ [ 'White on Black', true, false ],
[ 'Black on White', false, true ],
[ 'Monochrome', true, false ],
[ 'Color Terminal', false, true ] ];
--></script>
<link rel="shortcut icon" href="favicon.ico" type="image/x-icon">
<script type="text/javascript" src="vt100.js"></script>

BIN
demo/enabled.gif Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 847 B

View file

@ -127,22 +127,47 @@
margin: 0.5ex 0px 0.5ex 0px;
}
#vt100 #ansi0 { background-color: #000000; }
#vt100 #ansi1 { background-color: #cd0000; }
#vt100 #ansi2 { background-color: #00cd00; }
#vt100 #ansi3 { background-color: #cdcd00; }
#vt100 #ansi4 { background-color: #0000ee; }
#vt100 #ansi5 { background-color: #cd00cd; }
#vt100 #ansi6 { background-color: #00cdcd; }
#vt100 #ansi7 { background-color: #e5e5e5; }
#vt100 #ansi8 { background-color: #7f7f7f; }
#vt100 #ansi9 { background-color: #ff0000; }
#vt100 #ansi10 { background-color: #00ff00; }
#vt100 #ansi11 { background-color: #e8e800; }
#vt100 #ansi12 { background-color: #5c5cff; }
#vt100 #ansi13 { background-color: #ff00ff; }
#vt100 #ansi14 { background-color: #00ffff; }
#vt100 #ansi15 { background-color: #ffffff; }
#vt100 #menu img {
margin-right: 0.5ex;
width: 1ex;
height: 1ex;
}
#vt100 #scrollable.inverted { color: #ffffff;
background-color: #000000; }
#vt100 .ansi0 { }
#vt100 .ansi1 { color: #cd0000; }
#vt100 .ansi2 { color: #00cd00; }
#vt100 .ansi3 { color: #cdcd00; }
#vt100 .ansi4 { color: #0000ee; }
#vt100 .ansi5 { color: #cd00cd; }
#vt100 .ansi6 { color: #00cdcd; }
#vt100 .ansi7 { color: #e5e5e5; }
#vt100 .ansi8 { color: #7f7f7f; }
#vt100 .ansi9 { color: #ff0000; }
#vt100 .ansi10 { color: #00ff00; }
#vt100 .ansi11 { color: #e8e800; }
#vt100 .ansi12 { color: #5c5cff; }
#vt100 .ansi13 { color: #ff00ff; }
#vt100 .ansi14 { color: #00ffff; }
#vt100 .ansi15 { color: #ffffff; }
#vt100 .bgAnsi0 { background-color: #000000; }
#vt100 .bgAnsi1 { background-color: #cd0000; }
#vt100 .bgAnsi2 { background-color: #00cd00; }
#vt100 .bgAnsi3 { background-color: #cdcd00; }
#vt100 .bgAnsi4 { background-color: #0000ee; }
#vt100 .bgAnsi5 { background-color: #cd00cd; }
#vt100 .bgAnsi6 { background-color: #00cdcd; }
#vt100 .bgAnsi7 { background-color: #e5e5e5; }
#vt100 .bgAnsi8 { background-color: #7f7f7f; }
#vt100 .bgAnsi9 { background-color: #ff0000; }
#vt100 .bgAnsi10 { background-color: #00ff00; }
#vt100 .bgAnsi11 { background-color: #e8e800; }
#vt100 .bgAnsi12 { background-color: #5c5cff; }
#vt100 .bgAnsi13 { background-color: #ff00ff; }
#vt100 .bgAnsi14 { background-color: #00ffff; }
#vt100 .bgAnsi15 { }
@media print {
#vt100 .scrollback {

6
demo/usercss-0.css Normal file
View file

@ -0,0 +1,6 @@
#vt100 #scrollable { color: #ffffff;
background-color: #000000; }
#vt100 #scrollable.inverted { color: #000000;
background-color: #ffffff; }
#vt100 .ansi15 { color: #000000; }
#vt100 .bgAnsi0 { background-color: #ffffff; }

0
demo/usercss-1.css Normal file
View file

29
demo/usercss-2.css Normal file
View file

@ -0,0 +1,29 @@
#vt100 .ansi1 { color: inherit; }
#vt100 .ansi2 { color: inherit; }
#vt100 .ansi3 { color: inherit; }
#vt100 .ansi4 { color: inherit; }
#vt100 .ansi5 { color: inherit; }
#vt100 .ansi6 { color: inherit; }
#vt100 .ansi7 { color: inherit; }
#vt100 .ansi8 { color: inherit; }
#vt100 .ansi9 { color: inherit; }
#vt100 .ansi10 { color: inherit; }
#vt100 .ansi11 { color: inherit; }
#vt100 .ansi12 { color: inherit; }
#vt100 .ansi13 { color: inherit; }
#vt100 .ansi14 { color: inherit; }
#vt100 .bgAnsi1 { background-color: inherit; }
#vt100 .bgAnsi2 { background-color: inherit; }
#vt100 .bgAnsi3 { background-color: inherit; }
#vt100 .bgAnsi4 { background-color: inherit; }
#vt100 .bgAnsi5 { background-color: inherit; }
#vt100 .bgAnsi6 { background-color: inherit; }
#vt100 .bgAnsi7 { background-color: inherit; }
#vt100 .bgAnsi8 { background-color: inherit; }
#vt100 .bgAnsi9 { background-color: inherit; }
#vt100 .bgAnsi10 { background-color: inherit; }
#vt100 .bgAnsi11 { background-color: inherit; }
#vt100 .bgAnsi12 { background-color: inherit; }
#vt100 .bgAnsi13 { background-color: inherit; }
#vt100 .bgAnsi14 { background-color: inherit; }

0
demo/usercss-3.css Normal file
View file

View file

@ -174,7 +174,6 @@ function VT100(container) {
'(?:[?](?:(?![ \u00A0]|[,.)}"\u0027!]+[ \u00A0]|[,.)}"\u0027!]+$).)*)?');
}
this.initializeElements(container);
this.initializeAnsiColors();
this.maxScrollbackLines = 500;
this.npar = 0;
this.par = [ ];
@ -210,6 +209,7 @@ VT100.prototype.reset = function(clearHistory) {
suppressAllAudio;
this.utfCount = 0;
this.utfChar = 0;
this.color = 'ansi0 bgAnsi15';
this.style = '';
this.attr = 0x00F0 /* ATTR_DEFAULT */;
this.useGMap = 0;
@ -236,19 +236,8 @@ VT100.prototype.reset = function(clearHistory) {
this.showCursor();
this.isInverted = false;
this.refreshInvertedState();
this.clearRegion(0, 0, this.terminalWidth, this.terminalHeight, this.style);
};
VT100.prototype.initializeAnsiColors = function() {
var elem = document.createElement('pre');
this.container.appendChild(elem);
this.setTextContent(elem, ' ');
this.ansi = [ ];
for (var i = 0; i < 16; i++) {
elem.id = 'ansi' + i;
this.ansi[i] = this.getCurrentComputedStyle(elem, 'backgroundColor');
}
this.container.removeChild(elem);
this.clearRegion(0, 0, this.terminalWidth, this.terminalHeight,
this.color, this.style);
};
VT100.prototype.addListener = function(elem, event, listener) {
@ -319,8 +308,17 @@ VT100.prototype.initializeUserCSSStyles = function() {
if (++i >= begin) {
--c;
var label = vt100.usercss.childNodes[j];
label.innerHTML =
label.innerHTML.replace(/^\u2714 /, '');
// Restore label to just the text content
if (typeof label.textContent == 'undefined') {
var s = label.innerText;
label.innerHTML = '';
label.appendChild(document.createTextNode(s));
} else {
label.textContent= label.textContent;
}
// User style sheets are number sequentially
var sheet = document.getElementById(
'usercss-' + i);
if (i == current) {
@ -330,7 +328,8 @@ VT100.prototype.initializeUserCSSStyles = function() {
sheet.disabled = false;
}
if (!sheet.disabled) {
label.innerHTML= '&#10004; ' + label.innerHTML;
label.innerHTML= '<img src="enabled.gif" />' +
label.innerHTML;
}
} else {
sheet.disabled = true;
@ -355,7 +354,9 @@ VT100.prototype.initializeUserCSSStyles = function() {
// both ends), or whether this is a on/off toggle, which can be grouped
// together with other on/off options.
group +=
'<li>' + (enabled ? '&#10004; ' : '') + label + '</li>';
'<li>' + (enabled ? '<img src="enabled.gif" />' : '') +
label +
'</li>';
}
this.usercss.innerHTML = menu;
}
@ -384,8 +385,7 @@ VT100.prototype.initializeElements = function(container) {
!this.getChildById(this.container, 'usercss') ||
!this.getChildById(this.container, 'space') ||
!this.getChildById(this.container, 'input') ||
!this.getChildById(this.container, 'cliphelper') ||
!this.getChildById(this.container, 'attrib')) {
!this.getChildById(this.container, 'cliphelper')) {
// Only enable the "embed" object, if we have a suitable plugin. Otherwise,
// we might get a pointless warning that a suitable plugin is not yet
// installed. If in doubt, we'd rather just stay silent.
@ -432,7 +432,6 @@ VT100.prototype.initializeElements = function(container) {
'<pre><div><span id="space"></span></div></pre>' +
'<input type="textfield" id="input" />' +
'<input type="textfield" id="cliphelper" />' +
'<span id="attrib">&nbsp;</span>' +
(typeof suppressAllAudio != 'undefined' &&
suppressAllAudio ? "" :
embed + '<bgsound id="beep_bgsound" loop=1 />') +
@ -474,7 +473,6 @@ VT100.prototype.initializeElements = function(container) {
this.input = this.getChildById(this.container, 'input');
this.cliphelper = this.getChildById(this.container,
'cliphelper');
this.attributeHelper = this.getChildById(this.container, 'attrib');
// Add any user selectable style sheets to the menu
this.initializeUserCSSStyles();
@ -642,6 +640,7 @@ VT100.prototype.repairElements = function(console) {
for (var span = line.firstChild; span; span = span.nextSibling) {
var newSpan = document.createElement(span.tagName);
newSpan.style.cssText = span.style.cssText;
newSpan.style.className = span.style.className;
this.setTextContent(newSpan, this.getTextContent(span));
newLine.appendChild(newSpan);
}
@ -1015,7 +1014,7 @@ VT100.prototype.setTextContent = function(elem, s) {
}
};
VT100.prototype.insertBlankLine = function(y, style) {
VT100.prototype.insertBlankLine = function(y, color, style) {
// Insert a blank line a position y. This method ignores the scrollback
// buffer. The caller has to add the length of the scrollback buffer to
// the position, if necessary.
@ -1023,17 +1022,21 @@ VT100.prototype.insertBlankLine = function(y, style) {
// method just adds a new line right after the last existing one. It does
// not add any missing lines in between. It is the caller's responsibility
// to do so.
if (style == undefined) {
if (!color) {
color = 'ansi0 bgAnsi15';
}
if (!style) {
style = '';
}
var line;
if (!style) {
if (color != 'ansi0 bgAnsi15' && !style) {
line = document.createElement('pre');
this.setTextContent(line, '\n');
} else {
line = document.createElement('div');
var span = document.createElement('span');
span.style.cssText = style;
span.style.className = color;
this.setTextContent(span, this.spaces(this.terminalWidth));
line.appendChild(span);
}
@ -1104,7 +1107,9 @@ VT100.prototype.truncateLines = function(width) {
}
// Prune white space from the end of the current line
var span = line.lastChild;
while (span && !span.style.cssText.length) {
while (span &&
span.className == 'ansi0 bgAnsi15' &&
!span.style.cssText.length) {
// Scan backwards looking for first non-space character
var s = this.getTextContent(span);
for (var i = s.length; i--; ) {
@ -1135,7 +1140,10 @@ VT100.prototype.truncateLines = function(width) {
}
};
VT100.prototype.putString = function(x, y, text, style) {
VT100.prototype.putString = function(x, y, text, color, style) {
if (!color) {
color = 'ansi0 bgAnsi15';
}
if (!style) {
style = '';
}
@ -1192,12 +1200,15 @@ VT100.prototype.putString = function(x, y, text, style) {
// If current <span> is not long enough, pad with spaces or add new
// span
s = this.getTextContent(span);
var oldColor = span.className;
var oldStyle = span.style.cssText;
if (xPos + s.length < x) {
if (oldStyle != '') {
if (oldColor != 'ansi0 bgAnsi15' || oldStyle != '') {
span = document.createElement('span');
line.appendChild(span);
span.className = 'ansi0 bgAnsi15';
span.style.cssText = '';
oldColor = 'ansi0 bgAnsi15';
oldStyle = '';
xPos += s.length;
s = '';
@ -1209,7 +1220,8 @@ VT100.prototype.putString = function(x, y, text, style) {
// If styles do not match, create a new <span>
var del = text.length - s.length + x - xPos;
if (oldStyle != style && (oldStyle || style)) {
if (oldColor != color ||
(oldStyle != style && (oldStyle || style))) {
if (xPos == x) {
// Replacing text at beginning of existing <span>
if (text.length >= s.length) {
@ -1236,6 +1248,7 @@ VT100.prototype.putString = function(x, y, text, style) {
span = sibling;
if (remainder.length) {
sibling = document.createElement('span');
sibling.className = oldColor;
sibling.style.cssText = oldStyle;
this.setTextContent(sibling, remainder);
line.insertBefore(sibling, span.nextSibling);
@ -1245,6 +1258,7 @@ VT100.prototype.putString = function(x, y, text, style) {
span = sibling;
if (remainder.length) {
sibling = document.createElement('span');
sibling.className = oldColor;
sibling.style.cssText = oldStyle;
this.setTextContent(sibling, remainder);
line.appendChild(sibling);
@ -1252,6 +1266,7 @@ VT100.prototype.putString = function(x, y, text, style) {
}
s = text;
}
span.className = color;
span.style.cssText = style;
} else {
// Overwrite (partial) <span> with new text
@ -1278,7 +1293,8 @@ VT100.prototype.putString = function(x, y, text, style) {
}
// Merge <span> with next sibling, if styles are identical
if (sibling && span.style.cssText == sibling.style.cssText) {
if (sibling && span.className == sibling.className &&
span.style.cssText == sibling.style.cssText) {
this.setTextContent(span,
this.getTextContent(span) +
this.getTextContent(sibling));
@ -1348,6 +1364,7 @@ VT100.prototype.putString = function(x, y, text, style) {
if (text.length) {
// Merge <span> with previous sibling, if styles are identical
if ((sibling = span.previousSibling) &&
span.className == sibling.className &&
span.style.cssText == sibling.style.cssText) {
this.setTextContent(span,
this.getTextContent(sibling) +
@ -1357,7 +1374,9 @@ VT100.prototype.putString = function(x, y, text, style) {
// Prune white space from the end of the current line
span = line.lastChild;
while (span && !span.style.cssText.length) {
while (span &&
span.className == 'ansi0 bgAnsi15' &&
!span.style.cssText.length) {
// Scan backwards looking for first non-space character
s = this.getTextContent(span);
for (var i = s.length; i--; ) {
@ -1418,11 +1437,10 @@ VT100.prototype.gotoXaY = function(x, y) {
VT100.prototype.refreshInvertedState = function() {
if (this.isInverted) {
this.scrollable.style.color = this.ansi[15];
this.scrollable.style.backgroundColor = this.ansi[0];
this.scrollable.className += ' inverted';
} else {
this.scrollable.style.color = '';
this.scrollable.style.backgroundColor = '';
this.scrollable.className = this.scrollable.className.
replace(/ *inverted/, '');
}
};
@ -1502,7 +1520,7 @@ VT100.prototype.spaces = function(i) {
return s;
};
VT100.prototype.clearRegion = function(x, y, w, h, style) {
VT100.prototype.clearRegion = function(x, y, w, h, color, style) {
w += x;
if (x < 0) {
x = 0;
@ -1529,7 +1547,7 @@ VT100.prototype.clearRegion = function(x, y, w, h, style) {
// child nodes.
if (!this.numScrollbackLines &&
w == this.terminalWidth && h == this.terminalHeight &&
!style) {
(color == undefined || color == 'ansi0 bgAnsi15') && !style) {
var console = this.console[this.currentScreen];
while (console.lastChild) {
console.removeChild(console.lastChild);
@ -1541,7 +1559,7 @@ VT100.prototype.clearRegion = function(x, y, w, h, style) {
var cy = this.cursorY;
var s = this.spaces(w);
for (var i = y+h; i-- > y; ) {
this.putString(x, i, s, style);
this.putString(x, i, s, color, style);
}
hidden ? this.showCursor(cx, cy) : this.putString(cx, cy, '', undefined);
}
@ -1549,16 +1567,19 @@ VT100.prototype.clearRegion = function(x, y, w, h, style) {
VT100.prototype.copyLineSegment = function(dX, dY, sX, sY, w) {
var text = [ ];
var className = [ ];
var style = [ ];
var console = this.console[this.currentScreen];
if (sY >= console.childNodes.length) {
text[0] = this.spaces(w);
style[0] = null;
className[0] = undefined;
style[0] = undefined;
} else {
var line = console.childNodes[sY];
if (line.tagName != 'DIV' || !line.childNodes.length) {
text[0] = this.spaces(w);
style[0] = null;
className[0] = undefined;
style[0] = undefined;
} else {
var x = 0;
for (var span = line.firstChild; span && w > 0; span = span.nextSibling){
@ -1567,6 +1588,7 @@ VT100.prototype.copyLineSegment = function(dX, dY, sX, sY, w) {
if (x + len > sX) {
var o = sX > x ? sX - x : 0;
text[text.length] = s.substr(o, w);
className[className.length] = span.className;
style[style.length] = span.style.cssText;
w -= len - o;
}
@ -1574,7 +1596,8 @@ VT100.prototype.copyLineSegment = function(dX, dY, sX, sY, w) {
}
if (w > 0) {
text[text.length] = this.spaces(w);
style[style.length] = null;
className[className.length] = undefined;
style[style.length] = undefined;
}
}
}
@ -1582,13 +1605,20 @@ VT100.prototype.copyLineSegment = function(dX, dY, sX, sY, w) {
var cx = this.cursorX;
var cy = this.cursorY;
for (var i = 0; i < text.length; i++) {
this.putString(dX, dY - this.numScrollbackLines, text[i], style[i]);
var color;
if (className[i]) {
color = className[i];
} else {
color = 'ansi0 bgAnsi15';
}
this.putString(dX, dY - this.numScrollbackLines, text[i], color, style[i]);
dX += text[i].length;
}
hidden ? this.showCursor(cx, cy) : this.putString(cx, cy, '', undefined);
};
VT100.prototype.scrollRegion = function(x, y, w, h, incX, incY, style) {
VT100.prototype.scrollRegion = function(x, y, w, h, incX, incY,
color, style) {
var left = incX < 0 ? -incX : 0;
var right = incX > 0 ? incX : 0;
var up = incY < 0 ? -incY : 0;
@ -1623,9 +1653,7 @@ VT100.prototype.scrollRegion = function(x, y, w, h, incX, incY, style) {
// fill with underlined spaces. N.B. this is different from the
// cases when the user blanks a region. User-initiated blanking
// always fills with all of the current attributes.
this.attributeHelper.cssText
= style.replace(/text-decoration:underline;/, "");
style = this.attributeHelper.cssText;
style = style.replace(/text-decoration:underline;/, '');
}
// Compute current scroll position
@ -1654,7 +1682,7 @@ VT100.prototype.scrollRegion = function(x, y, w, h, incX, incY, style) {
// Add new lines at bottom in order to force scrolling
for (var i = 0; i < y; i++) {
this.insertBlankLine(console.childNodes.length, style);
this.insertBlankLine(console.childNodes.length, color, style);
}
// Adjust the number of lines in the scrollback buffer by
@ -1691,7 +1719,7 @@ VT100.prototype.scrollRegion = function(x, y, w, h, incX, incY, style) {
console.childNodes.length > this.numScrollbackLines+y+h+incY) {
for (var i = -incY; i-- > 0; ) {
this.insertBlankLine(this.numScrollbackLines + y + h + incY,
style);
color, style);
}
}
}
@ -1703,7 +1731,7 @@ VT100.prototype.scrollRegion = function(x, y, w, h, incX, incY, style) {
console.removeChild(console.childNodes[this.numScrollbackLines+y+h]);
}
for (var i = incY; i--; ) {
this.insertBlankLine(this.numScrollbackLines + y, style);
this.insertBlankLine(this.numScrollbackLines + y, color, style);
}
}
} else {
@ -1725,14 +1753,14 @@ VT100.prototype.scrollRegion = function(x, y, w, h, incX, incY, style) {
// Clear blank regions
if (incX > 0) {
this.clearRegion(x, y, incX, h, style);
this.clearRegion(x, y, incX, h, color, style);
} else if (incX < 0) {
this.clearRegion(x + w + incX, y, -incX, h, style);
this.clearRegion(x + w + incX, y, -incX, h, color, style);
}
if (incY > 0) {
this.clearRegion(x, y, w, incY, style);
this.clearRegion(x, y, w, incY, color, style);
} else if (incY < 0) {
this.clearRegion(x, y + h + incY, w, -incY, style);
this.clearRegion(x, y + h + incY, w, -incY, color, style);
}
}
@ -1801,7 +1829,7 @@ VT100.prototype.toggleBell = function() {
};
VT100.prototype.about = function() {
alert("VT100 Terminal Emulator " + "2.9 (revision 166)" +
alert("VT100 Terminal Emulator " + "2.9 (revision 167)" +
"\nCopyright 2008-2009 by Markus Gutschke\n" +
"For more information check http://shellinabox.com");
};
@ -1829,9 +1857,11 @@ VT100.prototype.showContextMenu = function(x, y) {
'<li id="reset">Reset</li>' +
'<hr />' +
'<li id="beginconfig">' +
(this.utfEnabled ? '&#10004; ' : '') + 'Unicode</li>' +
(this.utfEnabled ? '<img src="enabled.gif" />' : '') +
'Unicode</li>' +
'<li id="endconfig">' +
(this.visualBell ? '&#10004; ' : '') + 'Visual Bell</li>'+
(this.visualBell ? '<img src="enabled.gif" />' : '') +
'Visual Bell</li>'+
(this.usercss.firstChild ?
'<hr id="beginusercss" />' +
this.usercss.innerHTML +
@ -2576,7 +2606,7 @@ VT100.prototype.lf = function(count) {
if (this.cursorY == this.bottom - 1) {
this.scrollRegion(0, this.top + 1,
this.terminalWidth, this.bottom - this.top - 1,
0, -1, this.style);
0, -1, this.color, this.style);
offset = undefined;
} else if (this.cursorY < this.terminalHeight - 1) {
this.gotoXY(this.cursorX, this.cursorY + 1);
@ -2599,7 +2629,7 @@ VT100.prototype.ri = function(count) {
if (this.cursorY == this.top) {
this.scrollRegion(0, this.top,
this.terminalWidth, this.bottom - this.top - 1,
0, 1, this.style);
0, 1, this.color, this.style);
} else if (this.cursorY > 0) {
this.gotoXY(this.cursorX, this.cursorY - 1);
}
@ -2615,10 +2645,11 @@ VT100.prototype.respondSecondaryDA = function() {
this.respondString += '\u001B[>0;0;0c';
};
VT100.prototype.updateStyle = function() {
var style = '';
this.style = '';
if (this.attr & 0x0200 /* ATTR_UNDERLINE */) {
style += 'text-decoration:underline;';
this.style = 'text-decoration:underline;';
}
var bg = (this.attr >> 4) & 0xF;
var fg = this.attr & 0xF;
@ -2649,14 +2680,7 @@ VT100.prototype.updateStyle = function() {
}
}
if (fg != 0) {
style += 'color:' + this.ansi[fg] + ';';
}
if (bg != 15) {
style += 'background-color:' + this.ansi[bg] + ';';
}
this.attributeHelper.cssText = style;
this.style = this.attributeHelper.cssText;
this.color = 'ansi' + fg + ' bgAnsi' + bg;
};
VT100.prototype.setAttrColors = function(attr) {
@ -2750,7 +2774,7 @@ VT100.prototype.csiAt = function(number) {
}
this.scrollRegion(this.cursorX, this.cursorY,
this.terminalWidth - this.cursorX - number, 1,
number, 0, this.style);
number, 0, this.color, this.style);
this.needWrap = false;
};
@ -2758,22 +2782,26 @@ VT100.prototype.csiJ = function(number) {
switch (number) {
case 0: // Erase from cursor to end of display
this.clearRegion(this.cursorX, this.cursorY,
this.terminalWidth - this.cursorX, 1, this.style);
this.terminalWidth - this.cursorX, 1,
this.color, this.style);
if (this.cursorY < this.terminalHeight-2) {
this.clearRegion(0, this.cursorY+1,
this.terminalWidth, this.terminalHeight-this.cursorY-1,
this.style);
this.color, this.style);
}
break;
case 1: // Erase from start to cursor
if (this.cursorY > 0) {
this.clearRegion(0, 0,
this.terminalWidth, this.cursorY, this.style);
this.terminalWidth, this.cursorY,
this.color, this.style);
}
this.clearRegion(0, this.cursorY, this.cursorX + 1, 1, this.style);
this.clearRegion(0, this.cursorY, this.cursorX + 1, 1,
this.color, this.style);
break;
case 2: // Erase whole display
this.clearRegion(0, 0, this.terminalWidth, this.terminalHeight,this.style);
this.clearRegion(0, 0, this.terminalWidth, this.terminalHeight,
this.color, this.style);
break;
default:
return;
@ -2785,13 +2813,16 @@ VT100.prototype.csiK = function(number) {
switch (number) {
case 0: // Erase from cursor to end of line
this.clearRegion(this.cursorX, this.cursorY,
this.terminalWidth - this.cursorX, 1, this.style);
this.terminalWidth - this.cursorX, 1,
this.color, this.style);
break;
case 1: // Erase from start of line to cursor
this.clearRegion(0, this.cursorY, this.cursorX + 1, 1, this.style);
this.clearRegion(0, this.cursorY, this.cursorX + 1, 1,
this.color, this.style);
break;
case 2: // Erase whole line
this.clearRegion(0, this.cursorY, this.terminalWidth, 1, this.style);
this.clearRegion(0, this.cursorY, this.terminalWidth, 1,
this.color, this.style);
break;
default:
return;
@ -2812,7 +2843,7 @@ VT100.prototype.csiL = function(number) {
}
this.scrollRegion(0, this.cursorY,
this.terminalWidth, this.bottom - this.cursorY - number,
0, number, this.style);
0, number, this.color, this.style);
needWrap = false;
};
@ -2829,7 +2860,7 @@ VT100.prototype.csiM = function(number) {
}
this.scrollRegion(0, this.cursorY + number,
this.terminalWidth, this.bottom - this.cursorY - number,
0, -number, this.style);
0, -number, this.color, this.style);
needWrap = false;
};
@ -2890,7 +2921,7 @@ VT100.prototype.csiP = function(number) {
}
this.scrollRegion(this.cursorX + number, this.cursorY,
this.terminalWidth - this.cursorX - number, 1,
-number, 0, this.style);
-number, 0, this.color, this.style);
needWrap = false;
};
@ -2902,7 +2933,8 @@ VT100.prototype.csiX = function(number) {
if (number > this.terminalWidth - this.cursorX) {
number = this.terminalWidth - this.cursorX;
}
this.clearRegion(this.cursorX, this.cursorY, number, 1, this.style);
this.clearRegion(this.cursorX, this.cursorY, number, 1,
this.color, this.style);
needWrap = false;
};
@ -3224,7 +3256,7 @@ VT100.prototype.renderString = function(s, showCursor) {
// call to this.showCursor()
this.cursor.style.visibility = '';
}
this.putString(this.cursorX, this.cursorY, s, this.style);
this.putString(this.cursorX, this.cursorY, s, this.color, this.style);
};
VT100.prototype.vt100 = function(s) {
@ -3299,7 +3331,7 @@ VT100.prototype.vt100 = function(s) {
if (this.insertMode) {
this.scrollRegion(this.cursorX, this.cursorY,
this.terminalWidth - this.cursorX - 1, 1,
1, 0, this.style);
1, 0, this.color, this.style);
}
this.lastCharacter = String.fromCharCode(ch);
lineBuf += this.lastCharacter;

View file

0
shellinabox/color.css Normal file
View file

BIN
shellinabox/enabled.gif Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 847 B

View file

@ -1195,13 +1195,25 @@ static void execService(int width, int height, struct Service *service,
void setWindowSize(int pty, int width, int height) {
if (width > 0 && height > 0) {
#ifdef TIOCSSIZE
{
struct ttysize win;
ioctl(pty, TIOCGSIZE, &win);
win.ts_lines = height;
win.ts_cols = width;
ioctl(pty, TIOCSSIZE, &win);
}
#endif
#ifdef TIOCGWINSZ
{
struct winsize win;
ioctl(pty, TIOCGWINSZ, &win);
win.ws_row = height;
win.ws_col = width;
win.ws_xpixel = 0;
win.ws_ypixel = 0;
ioctl(pty, TIOCSWINSZ, &win);
}
#endif
}
}
static void childProcess(struct Service *service, int width, int height,

View file

@ -0,0 +1,29 @@
#vt100 .ansi1 { color: inherit; }
#vt100 .ansi2 { color: inherit; }
#vt100 .ansi3 { color: inherit; }
#vt100 .ansi4 { color: inherit; }
#vt100 .ansi5 { color: inherit; }
#vt100 .ansi6 { color: inherit; }
#vt100 .ansi7 { color: inherit; }
#vt100 .ansi8 { color: inherit; }
#vt100 .ansi9 { color: inherit; }
#vt100 .ansi10 { color: inherit; }
#vt100 .ansi11 { color: inherit; }
#vt100 .ansi12 { color: inherit; }
#vt100 .ansi13 { color: inherit; }
#vt100 .ansi14 { color: inherit; }
#vt100 .bgAnsi1 { background-color: inherit; }
#vt100 .bgAnsi2 { background-color: inherit; }
#vt100 .bgAnsi3 { background-color: inherit; }
#vt100 .bgAnsi4 { background-color: inherit; }
#vt100 .bgAnsi5 { background-color: inherit; }
#vt100 .bgAnsi6 { background-color: inherit; }
#vt100 .bgAnsi7 { background-color: inherit; }
#vt100 .bgAnsi8 { background-color: inherit; }
#vt100 .bgAnsi9 { background-color: inherit; }
#vt100 .bgAnsi10 { background-color: inherit; }
#vt100 .bgAnsi11 { background-color: inherit; }
#vt100 .bgAnsi12 { background-color: inherit; }
#vt100 .bgAnsi13 { background-color: inherit; }
#vt100 .bgAnsi14 { background-color: inherit; }

View file

@ -355,7 +355,7 @@ ShellInABox.prototype.extendContextMenu = function(entries, actions) {
};
ShellInABox.prototype.about = function() {
alert("Shell In A Box version " + "2.9 (revision 166)" +
alert("Shell In A Box version " + "2.9 (revision 167)" +
"\nCopyright 2008-2009 by Markus Gutschke\n" +
"For more information check http://shellinabox.com" +
(typeof serverSupportsSSL != 'undefined' && serverSupportsSSL ?

View file

@ -507,6 +507,11 @@ static int shellInABoxHttpHandler(HttpConnection *http, void *arg,
extern char beepStart[];
extern char beepEnd[];
serveStaticFile(http, "audio/x-wav", beepStart, beepEnd);
} else if (pathInfoLength == 11 && !memcmp(pathInfo, "enabled.gif", 11)) {
// Serve the checkmark icon used in the context menu
extern char enabledStart[];
extern char enabledEnd[];
serveStaticFile(http, "image/gif", enabledStart, enabledEnd);
} else if (pathInfoLength == 11 && !memcmp(pathInfo, "favicon.ico", 11)) {
// Serve the favicon
extern char faviconStart[];

View file

@ -127,22 +127,47 @@
margin: 0.5ex 0px 0.5ex 0px;
}
#vt100 #ansi0 { background-color: #000000; }
#vt100 #ansi1 { background-color: #cd0000; }
#vt100 #ansi2 { background-color: #00cd00; }
#vt100 #ansi3 { background-color: #cdcd00; }
#vt100 #ansi4 { background-color: #0000ee; }
#vt100 #ansi5 { background-color: #cd00cd; }
#vt100 #ansi6 { background-color: #00cdcd; }
#vt100 #ansi7 { background-color: #e5e5e5; }
#vt100 #ansi8 { background-color: #7f7f7f; }
#vt100 #ansi9 { background-color: #ff0000; }
#vt100 #ansi10 { background-color: #00ff00; }
#vt100 #ansi11 { background-color: #e8e800; }
#vt100 #ansi12 { background-color: #5c5cff; }
#vt100 #ansi13 { background-color: #ff00ff; }
#vt100 #ansi14 { background-color: #00ffff; }
#vt100 #ansi15 { background-color: #ffffff; }
#vt100 #menu img {
margin-right: 0.5ex;
width: 1ex;
height: 1ex;
}
#vt100 #scrollable.inverted { color: #ffffff;
background-color: #000000; }
#vt100 .ansi0 { }
#vt100 .ansi1 { color: #cd0000; }
#vt100 .ansi2 { color: #00cd00; }
#vt100 .ansi3 { color: #cdcd00; }
#vt100 .ansi4 { color: #0000ee; }
#vt100 .ansi5 { color: #cd00cd; }
#vt100 .ansi6 { color: #00cdcd; }
#vt100 .ansi7 { color: #e5e5e5; }
#vt100 .ansi8 { color: #7f7f7f; }
#vt100 .ansi9 { color: #ff0000; }
#vt100 .ansi10 { color: #00ff00; }
#vt100 .ansi11 { color: #e8e800; }
#vt100 .ansi12 { color: #5c5cff; }
#vt100 .ansi13 { color: #ff00ff; }
#vt100 .ansi14 { color: #00ffff; }
#vt100 .ansi15 { color: #ffffff; }
#vt100 .bgAnsi0 { background-color: #000000; }
#vt100 .bgAnsi1 { background-color: #cd0000; }
#vt100 .bgAnsi2 { background-color: #00cd00; }
#vt100 .bgAnsi3 { background-color: #cdcd00; }
#vt100 .bgAnsi4 { background-color: #0000ee; }
#vt100 .bgAnsi5 { background-color: #cd00cd; }
#vt100 .bgAnsi6 { background-color: #00cdcd; }
#vt100 .bgAnsi7 { background-color: #e5e5e5; }
#vt100 .bgAnsi8 { background-color: #7f7f7f; }
#vt100 .bgAnsi9 { background-color: #ff0000; }
#vt100 .bgAnsi10 { background-color: #00ff00; }
#vt100 .bgAnsi11 { background-color: #e8e800; }
#vt100 .bgAnsi12 { background-color: #5c5cff; }
#vt100 .bgAnsi13 { background-color: #ff00ff; }
#vt100 .bgAnsi14 { background-color: #00ffff; }
#vt100 .bgAnsi15 { }
@media print {
#vt100 .scrollback {

View file

@ -174,7 +174,6 @@ function VT100(container) {
'(?:[?](?:(?![ \u00A0]|[,.)}"\u0027!]+[ \u00A0]|[,.)}"\u0027!]+$).)*)?');
}
this.initializeElements(container);
this.initializeAnsiColors();
this.maxScrollbackLines = 500;
this.npar = 0;
this.par = [ ];
@ -210,6 +209,7 @@ VT100.prototype.reset = function(clearHistory) {
suppressAllAudio;
this.utfCount = 0;
this.utfChar = 0;
this.color = 'ansi0 bgAnsi15';
this.style = '';
this.attr = 0x00F0 /* ATTR_DEFAULT */;
this.useGMap = 0;
@ -236,19 +236,8 @@ VT100.prototype.reset = function(clearHistory) {
this.showCursor();
this.isInverted = false;
this.refreshInvertedState();
this.clearRegion(0, 0, this.terminalWidth, this.terminalHeight, this.style);
};
VT100.prototype.initializeAnsiColors = function() {
var elem = document.createElement('pre');
this.container.appendChild(elem);
this.setTextContent(elem, ' ');
this.ansi = [ ];
for (var i = 0; i < 16; i++) {
elem.id = 'ansi' + i;
this.ansi[i] = this.getCurrentComputedStyle(elem, 'backgroundColor');
}
this.container.removeChild(elem);
this.clearRegion(0, 0, this.terminalWidth, this.terminalHeight,
this.color, this.style);
};
VT100.prototype.addListener = function(elem, event, listener) {
@ -319,8 +308,17 @@ VT100.prototype.initializeUserCSSStyles = function() {
if (++i >= begin) {
--c;
var label = vt100.usercss.childNodes[j];
label.innerHTML =
label.innerHTML.replace(/^\u2714 /, '');
// Restore label to just the text content
if (typeof label.textContent == 'undefined') {
var s = label.innerText;
label.innerHTML = '';
label.appendChild(document.createTextNode(s));
} else {
label.textContent= label.textContent;
}
// User style sheets are number sequentially
var sheet = document.getElementById(
'usercss-' + i);
if (i == current) {
@ -330,7 +328,8 @@ VT100.prototype.initializeUserCSSStyles = function() {
sheet.disabled = false;
}
if (!sheet.disabled) {
label.innerHTML= '&#10004; ' + label.innerHTML;
label.innerHTML= '<img src="enabled.gif" />' +
label.innerHTML;
}
} else {
sheet.disabled = true;
@ -355,7 +354,9 @@ VT100.prototype.initializeUserCSSStyles = function() {
// both ends), or whether this is a on/off toggle, which can be grouped
// together with other on/off options.
group +=
'<li>' + (enabled ? '&#10004; ' : '') + label + '</li>';
'<li>' + (enabled ? '<img src="enabled.gif" />' : '') +
label +
'</li>';
}
this.usercss.innerHTML = menu;
}
@ -384,8 +385,7 @@ VT100.prototype.initializeElements = function(container) {
!this.getChildById(this.container, 'usercss') ||
!this.getChildById(this.container, 'space') ||
!this.getChildById(this.container, 'input') ||
!this.getChildById(this.container, 'cliphelper') ||
!this.getChildById(this.container, 'attrib')) {
!this.getChildById(this.container, 'cliphelper')) {
// Only enable the "embed" object, if we have a suitable plugin. Otherwise,
// we might get a pointless warning that a suitable plugin is not yet
// installed. If in doubt, we'd rather just stay silent.
@ -432,7 +432,6 @@ VT100.prototype.initializeElements = function(container) {
'<pre><div><span id="space"></span></div></pre>' +
'<input type="textfield" id="input" />' +
'<input type="textfield" id="cliphelper" />' +
'<span id="attrib">&nbsp;</span>' +
(typeof suppressAllAudio != 'undefined' &&
suppressAllAudio ? "" :
embed + '<bgsound id="beep_bgsound" loop=1 />') +
@ -474,7 +473,6 @@ VT100.prototype.initializeElements = function(container) {
this.input = this.getChildById(this.container, 'input');
this.cliphelper = this.getChildById(this.container,
'cliphelper');
this.attributeHelper = this.getChildById(this.container, 'attrib');
// Add any user selectable style sheets to the menu
this.initializeUserCSSStyles();
@ -642,6 +640,7 @@ VT100.prototype.repairElements = function(console) {
for (var span = line.firstChild; span; span = span.nextSibling) {
var newSpan = document.createElement(span.tagName);
newSpan.style.cssText = span.style.cssText;
newSpan.style.className = span.style.className;
this.setTextContent(newSpan, this.getTextContent(span));
newLine.appendChild(newSpan);
}
@ -1015,7 +1014,7 @@ VT100.prototype.setTextContent = function(elem, s) {
}
};
VT100.prototype.insertBlankLine = function(y, style) {
VT100.prototype.insertBlankLine = function(y, color, style) {
// Insert a blank line a position y. This method ignores the scrollback
// buffer. The caller has to add the length of the scrollback buffer to
// the position, if necessary.
@ -1023,17 +1022,21 @@ VT100.prototype.insertBlankLine = function(y, style) {
// method just adds a new line right after the last existing one. It does
// not add any missing lines in between. It is the caller's responsibility
// to do so.
if (style == undefined) {
if (!color) {
color = 'ansi0 bgAnsi15';
}
if (!style) {
style = '';
}
var line;
if (!style) {
if (color != 'ansi0 bgAnsi15' && !style) {
line = document.createElement('pre');
this.setTextContent(line, '\n');
} else {
line = document.createElement('div');
var span = document.createElement('span');
span.style.cssText = style;
span.style.className = color;
this.setTextContent(span, this.spaces(this.terminalWidth));
line.appendChild(span);
}
@ -1104,7 +1107,9 @@ VT100.prototype.truncateLines = function(width) {
}
// Prune white space from the end of the current line
var span = line.lastChild;
while (span && !span.style.cssText.length) {
while (span &&
span.className == 'ansi0 bgAnsi15' &&
!span.style.cssText.length) {
// Scan backwards looking for first non-space character
var s = this.getTextContent(span);
for (var i = s.length; i--; ) {
@ -1135,7 +1140,10 @@ VT100.prototype.truncateLines = function(width) {
}
};
VT100.prototype.putString = function(x, y, text, style) {
VT100.prototype.putString = function(x, y, text, color, style) {
if (!color) {
color = 'ansi0 bgAnsi15';
}
if (!style) {
style = '';
}
@ -1192,12 +1200,15 @@ VT100.prototype.putString = function(x, y, text, style) {
// If current <span> is not long enough, pad with spaces or add new
// span
s = this.getTextContent(span);
var oldColor = span.className;
var oldStyle = span.style.cssText;
if (xPos + s.length < x) {
if (oldStyle != '') {
if (oldColor != 'ansi0 bgAnsi15' || oldStyle != '') {
span = document.createElement('span');
line.appendChild(span);
span.className = 'ansi0 bgAnsi15';
span.style.cssText = '';
oldColor = 'ansi0 bgAnsi15';
oldStyle = '';
xPos += s.length;
s = '';
@ -1209,7 +1220,8 @@ VT100.prototype.putString = function(x, y, text, style) {
// If styles do not match, create a new <span>
var del = text.length - s.length + x - xPos;
if (oldStyle != style && (oldStyle || style)) {
if (oldColor != color ||
(oldStyle != style && (oldStyle || style))) {
if (xPos == x) {
// Replacing text at beginning of existing <span>
if (text.length >= s.length) {
@ -1236,6 +1248,7 @@ VT100.prototype.putString = function(x, y, text, style) {
span = sibling;
if (remainder.length) {
sibling = document.createElement('span');
sibling.className = oldColor;
sibling.style.cssText = oldStyle;
this.setTextContent(sibling, remainder);
line.insertBefore(sibling, span.nextSibling);
@ -1245,6 +1258,7 @@ VT100.prototype.putString = function(x, y, text, style) {
span = sibling;
if (remainder.length) {
sibling = document.createElement('span');
sibling.className = oldColor;
sibling.style.cssText = oldStyle;
this.setTextContent(sibling, remainder);
line.appendChild(sibling);
@ -1252,6 +1266,7 @@ VT100.prototype.putString = function(x, y, text, style) {
}
s = text;
}
span.className = color;
span.style.cssText = style;
} else {
// Overwrite (partial) <span> with new text
@ -1278,7 +1293,8 @@ VT100.prototype.putString = function(x, y, text, style) {
}
// Merge <span> with next sibling, if styles are identical
if (sibling && span.style.cssText == sibling.style.cssText) {
if (sibling && span.className == sibling.className &&
span.style.cssText == sibling.style.cssText) {
this.setTextContent(span,
this.getTextContent(span) +
this.getTextContent(sibling));
@ -1348,6 +1364,7 @@ VT100.prototype.putString = function(x, y, text, style) {
if (text.length) {
// Merge <span> with previous sibling, if styles are identical
if ((sibling = span.previousSibling) &&
span.className == sibling.className &&
span.style.cssText == sibling.style.cssText) {
this.setTextContent(span,
this.getTextContent(sibling) +
@ -1357,7 +1374,9 @@ VT100.prototype.putString = function(x, y, text, style) {
// Prune white space from the end of the current line
span = line.lastChild;
while (span && !span.style.cssText.length) {
while (span &&
span.className == 'ansi0 bgAnsi15' &&
!span.style.cssText.length) {
// Scan backwards looking for first non-space character
s = this.getTextContent(span);
for (var i = s.length; i--; ) {
@ -1418,11 +1437,10 @@ VT100.prototype.gotoXaY = function(x, y) {
VT100.prototype.refreshInvertedState = function() {
if (this.isInverted) {
this.scrollable.style.color = this.ansi[15];
this.scrollable.style.backgroundColor = this.ansi[0];
this.scrollable.className += ' inverted';
} else {
this.scrollable.style.color = '';
this.scrollable.style.backgroundColor = '';
this.scrollable.className = this.scrollable.className.
replace(/ *inverted/, '');
}
};
@ -1502,7 +1520,7 @@ VT100.prototype.spaces = function(i) {
return s;
};
VT100.prototype.clearRegion = function(x, y, w, h, style) {
VT100.prototype.clearRegion = function(x, y, w, h, color, style) {
w += x;
if (x < 0) {
x = 0;
@ -1529,7 +1547,7 @@ VT100.prototype.clearRegion = function(x, y, w, h, style) {
// child nodes.
if (!this.numScrollbackLines &&
w == this.terminalWidth && h == this.terminalHeight &&
!style) {
(color == undefined || color == 'ansi0 bgAnsi15') && !style) {
var console = this.console[this.currentScreen];
while (console.lastChild) {
console.removeChild(console.lastChild);
@ -1541,7 +1559,7 @@ VT100.prototype.clearRegion = function(x, y, w, h, style) {
var cy = this.cursorY;
var s = this.spaces(w);
for (var i = y+h; i-- > y; ) {
this.putString(x, i, s, style);
this.putString(x, i, s, color, style);
}
hidden ? this.showCursor(cx, cy) : this.putString(cx, cy, '', undefined);
}
@ -1549,16 +1567,19 @@ VT100.prototype.clearRegion = function(x, y, w, h, style) {
VT100.prototype.copyLineSegment = function(dX, dY, sX, sY, w) {
var text = [ ];
var className = [ ];
var style = [ ];
var console = this.console[this.currentScreen];
if (sY >= console.childNodes.length) {
text[0] = this.spaces(w);
style[0] = null;
className[0] = undefined;
style[0] = undefined;
} else {
var line = console.childNodes[sY];
if (line.tagName != 'DIV' || !line.childNodes.length) {
text[0] = this.spaces(w);
style[0] = null;
className[0] = undefined;
style[0] = undefined;
} else {
var x = 0;
for (var span = line.firstChild; span && w > 0; span = span.nextSibling){
@ -1567,6 +1588,7 @@ VT100.prototype.copyLineSegment = function(dX, dY, sX, sY, w) {
if (x + len > sX) {
var o = sX > x ? sX - x : 0;
text[text.length] = s.substr(o, w);
className[className.length] = span.className;
style[style.length] = span.style.cssText;
w -= len - o;
}
@ -1574,7 +1596,8 @@ VT100.prototype.copyLineSegment = function(dX, dY, sX, sY, w) {
}
if (w > 0) {
text[text.length] = this.spaces(w);
style[style.length] = null;
className[className.length] = undefined;
style[style.length] = undefined;
}
}
}
@ -1582,13 +1605,20 @@ VT100.prototype.copyLineSegment = function(dX, dY, sX, sY, w) {
var cx = this.cursorX;
var cy = this.cursorY;
for (var i = 0; i < text.length; i++) {
this.putString(dX, dY - this.numScrollbackLines, text[i], style[i]);
var color;
if (className[i]) {
color = className[i];
} else {
color = 'ansi0 bgAnsi15';
}
this.putString(dX, dY - this.numScrollbackLines, text[i], color, style[i]);
dX += text[i].length;
}
hidden ? this.showCursor(cx, cy) : this.putString(cx, cy, '', undefined);
};
VT100.prototype.scrollRegion = function(x, y, w, h, incX, incY, style) {
VT100.prototype.scrollRegion = function(x, y, w, h, incX, incY,
color, style) {
var left = incX < 0 ? -incX : 0;
var right = incX > 0 ? incX : 0;
var up = incY < 0 ? -incY : 0;
@ -1623,9 +1653,7 @@ VT100.prototype.scrollRegion = function(x, y, w, h, incX, incY, style) {
// fill with underlined spaces. N.B. this is different from the
// cases when the user blanks a region. User-initiated blanking
// always fills with all of the current attributes.
this.attributeHelper.cssText
= style.replace(/text-decoration:underline;/, "");
style = this.attributeHelper.cssText;
style = style.replace(/text-decoration:underline;/, '');
}
// Compute current scroll position
@ -1654,7 +1682,7 @@ VT100.prototype.scrollRegion = function(x, y, w, h, incX, incY, style) {
// Add new lines at bottom in order to force scrolling
for (var i = 0; i < y; i++) {
this.insertBlankLine(console.childNodes.length, style);
this.insertBlankLine(console.childNodes.length, color, style);
}
// Adjust the number of lines in the scrollback buffer by
@ -1691,7 +1719,7 @@ VT100.prototype.scrollRegion = function(x, y, w, h, incX, incY, style) {
console.childNodes.length > this.numScrollbackLines+y+h+incY) {
for (var i = -incY; i-- > 0; ) {
this.insertBlankLine(this.numScrollbackLines + y + h + incY,
style);
color, style);
}
}
}
@ -1703,7 +1731,7 @@ VT100.prototype.scrollRegion = function(x, y, w, h, incX, incY, style) {
console.removeChild(console.childNodes[this.numScrollbackLines+y+h]);
}
for (var i = incY; i--; ) {
this.insertBlankLine(this.numScrollbackLines + y, style);
this.insertBlankLine(this.numScrollbackLines + y, color, style);
}
}
} else {
@ -1725,14 +1753,14 @@ VT100.prototype.scrollRegion = function(x, y, w, h, incX, incY, style) {
// Clear blank regions
if (incX > 0) {
this.clearRegion(x, y, incX, h, style);
this.clearRegion(x, y, incX, h, color, style);
} else if (incX < 0) {
this.clearRegion(x + w + incX, y, -incX, h, style);
this.clearRegion(x + w + incX, y, -incX, h, color, style);
}
if (incY > 0) {
this.clearRegion(x, y, w, incY, style);
this.clearRegion(x, y, w, incY, color, style);
} else if (incY < 0) {
this.clearRegion(x, y + h + incY, w, -incY, style);
this.clearRegion(x, y + h + incY, w, -incY, color, style);
}
}
@ -1801,7 +1829,7 @@ VT100.prototype.toggleBell = function() {
};
VT100.prototype.about = function() {
alert("VT100 Terminal Emulator " + "2.9 (revision 166)" +
alert("VT100 Terminal Emulator " + "2.9 (revision 167)" +
"\nCopyright 2008-2009 by Markus Gutschke\n" +
"For more information check http://shellinabox.com");
};
@ -1829,9 +1857,11 @@ VT100.prototype.showContextMenu = function(x, y) {
'<li id="reset">Reset</li>' +
'<hr />' +
'<li id="beginconfig">' +
(this.utfEnabled ? '&#10004; ' : '') + 'Unicode</li>' +
(this.utfEnabled ? '<img src="enabled.gif" />' : '') +
'Unicode</li>' +
'<li id="endconfig">' +
(this.visualBell ? '&#10004; ' : '') + 'Visual Bell</li>'+
(this.visualBell ? '<img src="enabled.gif" />' : '') +
'Visual Bell</li>'+
(this.usercss.firstChild ?
'<hr id="beginusercss" />' +
this.usercss.innerHTML +
@ -2576,7 +2606,7 @@ VT100.prototype.lf = function(count) {
if (this.cursorY == this.bottom - 1) {
this.scrollRegion(0, this.top + 1,
this.terminalWidth, this.bottom - this.top - 1,
0, -1, this.style);
0, -1, this.color, this.style);
offset = undefined;
} else if (this.cursorY < this.terminalHeight - 1) {
this.gotoXY(this.cursorX, this.cursorY + 1);
@ -2599,7 +2629,7 @@ VT100.prototype.ri = function(count) {
if (this.cursorY == this.top) {
this.scrollRegion(0, this.top,
this.terminalWidth, this.bottom - this.top - 1,
0, 1, this.style);
0, 1, this.color, this.style);
} else if (this.cursorY > 0) {
this.gotoXY(this.cursorX, this.cursorY - 1);
}
@ -2615,10 +2645,11 @@ VT100.prototype.respondSecondaryDA = function() {
this.respondString += '\u001B[>0;0;0c';
};
VT100.prototype.updateStyle = function() {
var style = '';
this.style = '';
if (this.attr & 0x0200 /* ATTR_UNDERLINE */) {
style += 'text-decoration:underline;';
this.style = 'text-decoration:underline;';
}
var bg = (this.attr >> 4) & 0xF;
var fg = this.attr & 0xF;
@ -2649,14 +2680,7 @@ VT100.prototype.updateStyle = function() {
}
}
if (fg != 0) {
style += 'color:' + this.ansi[fg] + ';';
}
if (bg != 15) {
style += 'background-color:' + this.ansi[bg] + ';';
}
this.attributeHelper.cssText = style;
this.style = this.attributeHelper.cssText;
this.color = 'ansi' + fg + ' bgAnsi' + bg;
};
VT100.prototype.setAttrColors = function(attr) {
@ -2750,7 +2774,7 @@ VT100.prototype.csiAt = function(number) {
}
this.scrollRegion(this.cursorX, this.cursorY,
this.terminalWidth - this.cursorX - number, 1,
number, 0, this.style);
number, 0, this.color, this.style);
this.needWrap = false;
};
@ -2758,22 +2782,26 @@ VT100.prototype.csiJ = function(number) {
switch (number) {
case 0: // Erase from cursor to end of display
this.clearRegion(this.cursorX, this.cursorY,
this.terminalWidth - this.cursorX, 1, this.style);
this.terminalWidth - this.cursorX, 1,
this.color, this.style);
if (this.cursorY < this.terminalHeight-2) {
this.clearRegion(0, this.cursorY+1,
this.terminalWidth, this.terminalHeight-this.cursorY-1,
this.style);
this.color, this.style);
}
break;
case 1: // Erase from start to cursor
if (this.cursorY > 0) {
this.clearRegion(0, 0,
this.terminalWidth, this.cursorY, this.style);
this.terminalWidth, this.cursorY,
this.color, this.style);
}
this.clearRegion(0, this.cursorY, this.cursorX + 1, 1, this.style);
this.clearRegion(0, this.cursorY, this.cursorX + 1, 1,
this.color, this.style);
break;
case 2: // Erase whole display
this.clearRegion(0, 0, this.terminalWidth, this.terminalHeight,this.style);
this.clearRegion(0, 0, this.terminalWidth, this.terminalHeight,
this.color, this.style);
break;
default:
return;
@ -2785,13 +2813,16 @@ VT100.prototype.csiK = function(number) {
switch (number) {
case 0: // Erase from cursor to end of line
this.clearRegion(this.cursorX, this.cursorY,
this.terminalWidth - this.cursorX, 1, this.style);
this.terminalWidth - this.cursorX, 1,
this.color, this.style);
break;
case 1: // Erase from start of line to cursor
this.clearRegion(0, this.cursorY, this.cursorX + 1, 1, this.style);
this.clearRegion(0, this.cursorY, this.cursorX + 1, 1,
this.color, this.style);
break;
case 2: // Erase whole line
this.clearRegion(0, this.cursorY, this.terminalWidth, 1, this.style);
this.clearRegion(0, this.cursorY, this.terminalWidth, 1,
this.color, this.style);
break;
default:
return;
@ -2812,7 +2843,7 @@ VT100.prototype.csiL = function(number) {
}
this.scrollRegion(0, this.cursorY,
this.terminalWidth, this.bottom - this.cursorY - number,
0, number, this.style);
0, number, this.color, this.style);
needWrap = false;
};
@ -2829,7 +2860,7 @@ VT100.prototype.csiM = function(number) {
}
this.scrollRegion(0, this.cursorY + number,
this.terminalWidth, this.bottom - this.cursorY - number,
0, -number, this.style);
0, -number, this.color, this.style);
needWrap = false;
};
@ -2890,7 +2921,7 @@ VT100.prototype.csiP = function(number) {
}
this.scrollRegion(this.cursorX + number, this.cursorY,
this.terminalWidth - this.cursorX - number, 1,
-number, 0, this.style);
-number, 0, this.color, this.style);
needWrap = false;
};
@ -2902,7 +2933,8 @@ VT100.prototype.csiX = function(number) {
if (number > this.terminalWidth - this.cursorX) {
number = this.terminalWidth - this.cursorX;
}
this.clearRegion(this.cursorX, this.cursorY, number, 1, this.style);
this.clearRegion(this.cursorX, this.cursorY, number, 1,
this.color, this.style);
needWrap = false;
};
@ -3224,7 +3256,7 @@ VT100.prototype.renderString = function(s, showCursor) {
// call to this.showCursor()
this.cursor.style.visibility = '';
}
this.putString(this.cursorX, this.cursorY, s, this.style);
this.putString(this.cursorX, this.cursorY, s, this.color, this.style);
};
VT100.prototype.vt100 = function(s) {
@ -3299,7 +3331,7 @@ VT100.prototype.vt100 = function(s) {
if (this.insertMode) {
this.scrollRegion(this.cursorX, this.cursorY,
this.terminalWidth - this.cursorX - 1, 1,
1, 0, this.style);
1, 0, this.color, this.style);
}
this.lastCharacter = String.fromCharCode(ch);
lineBuf += this.lastCharacter;

View file

@ -174,7 +174,6 @@ function VT100(container) {
'(?:[?](?:(?![ \u00A0]|[,.)}"\u0027!]+[ \u00A0]|[,.)}"\u0027!]+$).)*)?');
}
this.initializeElements(container);
this.initializeAnsiColors();
this.maxScrollbackLines = 500;
this.npar = 0;
this.par = [ ];
@ -210,6 +209,7 @@ VT100.prototype.reset = function(clearHistory) {
suppressAllAudio;
this.utfCount = 0;
this.utfChar = 0;
this.color = 'ansi0 bgAnsi15';
this.style = '';
this.attr = ATTR_DEFAULT;
this.useGMap = 0;
@ -236,19 +236,8 @@ VT100.prototype.reset = function(clearHistory) {
this.showCursor();
this.isInverted = false;
this.refreshInvertedState();
this.clearRegion(0, 0, this.terminalWidth, this.terminalHeight, this.style);
};
VT100.prototype.initializeAnsiColors = function() {
var elem = document.createElement('pre');
this.container.appendChild(elem);
this.setTextContent(elem, ' ');
this.ansi = [ ];
for (var i = 0; i < 16; i++) {
elem.id = 'ansi' + i;
this.ansi[i] = this.getCurrentComputedStyle(elem, 'backgroundColor');
}
this.container.removeChild(elem);
this.clearRegion(0, 0, this.terminalWidth, this.terminalHeight,
this.color, this.style);
};
VT100.prototype.addListener = function(elem, event, listener) {
@ -319,8 +308,17 @@ VT100.prototype.initializeUserCSSStyles = function() {
if (++i >= begin) {
--c;
var label = vt100.usercss.childNodes[j];
label.innerHTML =
label.innerHTML.replace(/^\u2714 /, '');
// Restore label to just the text content
if (typeof label.textContent == 'undefined') {
var s = label.innerText;
label.innerHTML = '';
label.appendChild(document.createTextNode(s));
} else {
label.textContent= label.textContent;
}
// User style sheets are number sequentially
var sheet = document.getElementById(
'usercss-' + i);
if (i == current) {
@ -330,7 +328,8 @@ VT100.prototype.initializeUserCSSStyles = function() {
sheet.disabled = false;
}
if (!sheet.disabled) {
label.innerHTML= '&#10004; ' + label.innerHTML;
label.innerHTML= '<img src="enabled.gif" />' +
label.innerHTML;
}
} else {
sheet.disabled = true;
@ -355,7 +354,9 @@ VT100.prototype.initializeUserCSSStyles = function() {
// both ends), or whether this is a on/off toggle, which can be grouped
// together with other on/off options.
group +=
'<li>' + (enabled ? '&#10004; ' : '') + label + '</li>';
'<li>' + (enabled ? '<img src="enabled.gif" />' : '') +
label +
'</li>';
}
this.usercss.innerHTML = menu;
}
@ -384,8 +385,7 @@ VT100.prototype.initializeElements = function(container) {
!this.getChildById(this.container, 'usercss') ||
!this.getChildById(this.container, 'space') ||
!this.getChildById(this.container, 'input') ||
!this.getChildById(this.container, 'cliphelper') ||
!this.getChildById(this.container, 'attrib')) {
!this.getChildById(this.container, 'cliphelper')) {
// Only enable the "embed" object, if we have a suitable plugin. Otherwise,
// we might get a pointless warning that a suitable plugin is not yet
// installed. If in doubt, we'd rather just stay silent.
@ -432,7 +432,6 @@ VT100.prototype.initializeElements = function(container) {
'<pre><div><span id="space"></span></div></pre>' +
'<input type="textfield" id="input" />' +
'<input type="textfield" id="cliphelper" />' +
'<span id="attrib">&nbsp;</span>' +
(typeof suppressAllAudio != 'undefined' &&
suppressAllAudio ? "" :
embed + '<bgsound id="beep_bgsound" loop=1 />') +
@ -474,7 +473,6 @@ VT100.prototype.initializeElements = function(container) {
this.input = this.getChildById(this.container, 'input');
this.cliphelper = this.getChildById(this.container,
'cliphelper');
this.attributeHelper = this.getChildById(this.container, 'attrib');
// Add any user selectable style sheets to the menu
this.initializeUserCSSStyles();
@ -642,6 +640,7 @@ VT100.prototype.repairElements = function(console) {
for (var span = line.firstChild; span; span = span.nextSibling) {
var newSpan = document.createElement(span.tagName);
newSpan.style.cssText = span.style.cssText;
newSpan.style.className = span.style.className;
this.setTextContent(newSpan, this.getTextContent(span));
newLine.appendChild(newSpan);
}
@ -1015,7 +1014,7 @@ VT100.prototype.setTextContent = function(elem, s) {
}
};
VT100.prototype.insertBlankLine = function(y, style) {
VT100.prototype.insertBlankLine = function(y, color, style) {
// Insert a blank line a position y. This method ignores the scrollback
// buffer. The caller has to add the length of the scrollback buffer to
// the position, if necessary.
@ -1023,17 +1022,21 @@ VT100.prototype.insertBlankLine = function(y, style) {
// method just adds a new line right after the last existing one. It does
// not add any missing lines in between. It is the caller's responsibility
// to do so.
if (style == undefined) {
if (!color) {
color = 'ansi0 bgAnsi15';
}
if (!style) {
style = '';
}
var line;
if (!style) {
if (color != 'ansi0 bgAnsi15' && !style) {
line = document.createElement('pre');
this.setTextContent(line, '\n');
} else {
line = document.createElement('div');
var span = document.createElement('span');
span.style.cssText = style;
span.style.className = color;
this.setTextContent(span, this.spaces(this.terminalWidth));
line.appendChild(span);
}
@ -1104,7 +1107,9 @@ VT100.prototype.truncateLines = function(width) {
}
// Prune white space from the end of the current line
var span = line.lastChild;
while (span && !span.style.cssText.length) {
while (span &&
span.className == 'ansi0 bgAnsi15' &&
!span.style.cssText.length) {
// Scan backwards looking for first non-space character
var s = this.getTextContent(span);
for (var i = s.length; i--; ) {
@ -1135,7 +1140,10 @@ VT100.prototype.truncateLines = function(width) {
}
};
VT100.prototype.putString = function(x, y, text, style) {
VT100.prototype.putString = function(x, y, text, color, style) {
if (!color) {
color = 'ansi0 bgAnsi15';
}
if (!style) {
style = '';
}
@ -1192,12 +1200,15 @@ VT100.prototype.putString = function(x, y, text, style) {
// If current <span> is not long enough, pad with spaces or add new
// span
s = this.getTextContent(span);
var oldColor = span.className;
var oldStyle = span.style.cssText;
if (xPos + s.length < x) {
if (oldStyle != '') {
if (oldColor != 'ansi0 bgAnsi15' || oldStyle != '') {
span = document.createElement('span');
line.appendChild(span);
span.className = 'ansi0 bgAnsi15';
span.style.cssText = '';
oldColor = 'ansi0 bgAnsi15';
oldStyle = '';
xPos += s.length;
s = '';
@ -1209,7 +1220,8 @@ VT100.prototype.putString = function(x, y, text, style) {
// If styles do not match, create a new <span>
var del = text.length - s.length + x - xPos;
if (oldStyle != style && (oldStyle || style)) {
if (oldColor != color ||
(oldStyle != style && (oldStyle || style))) {
if (xPos == x) {
// Replacing text at beginning of existing <span>
if (text.length >= s.length) {
@ -1236,6 +1248,7 @@ VT100.prototype.putString = function(x, y, text, style) {
span = sibling;
if (remainder.length) {
sibling = document.createElement('span');
sibling.className = oldColor;
sibling.style.cssText = oldStyle;
this.setTextContent(sibling, remainder);
line.insertBefore(sibling, span.nextSibling);
@ -1245,6 +1258,7 @@ VT100.prototype.putString = function(x, y, text, style) {
span = sibling;
if (remainder.length) {
sibling = document.createElement('span');
sibling.className = oldColor;
sibling.style.cssText = oldStyle;
this.setTextContent(sibling, remainder);
line.appendChild(sibling);
@ -1252,6 +1266,7 @@ VT100.prototype.putString = function(x, y, text, style) {
}
s = text;
}
span.className = color;
span.style.cssText = style;
} else {
// Overwrite (partial) <span> with new text
@ -1278,7 +1293,8 @@ VT100.prototype.putString = function(x, y, text, style) {
}
// Merge <span> with next sibling, if styles are identical
if (sibling && span.style.cssText == sibling.style.cssText) {
if (sibling && span.className == sibling.className &&
span.style.cssText == sibling.style.cssText) {
this.setTextContent(span,
this.getTextContent(span) +
this.getTextContent(sibling));
@ -1348,6 +1364,7 @@ VT100.prototype.putString = function(x, y, text, style) {
if (text.length) {
// Merge <span> with previous sibling, if styles are identical
if ((sibling = span.previousSibling) &&
span.className == sibling.className &&
span.style.cssText == sibling.style.cssText) {
this.setTextContent(span,
this.getTextContent(sibling) +
@ -1357,7 +1374,9 @@ VT100.prototype.putString = function(x, y, text, style) {
// Prune white space from the end of the current line
span = line.lastChild;
while (span && !span.style.cssText.length) {
while (span &&
span.className == 'ansi0 bgAnsi15' &&
!span.style.cssText.length) {
// Scan backwards looking for first non-space character
s = this.getTextContent(span);
for (var i = s.length; i--; ) {
@ -1418,11 +1437,10 @@ VT100.prototype.gotoXaY = function(x, y) {
VT100.prototype.refreshInvertedState = function() {
if (this.isInverted) {
this.scrollable.style.color = this.ansi[15];
this.scrollable.style.backgroundColor = this.ansi[0];
this.scrollable.className += ' inverted';
} else {
this.scrollable.style.color = '';
this.scrollable.style.backgroundColor = '';
this.scrollable.className = this.scrollable.className.
replace(/ *inverted/, '');
}
};
@ -1502,7 +1520,7 @@ VT100.prototype.spaces = function(i) {
return s;
};
VT100.prototype.clearRegion = function(x, y, w, h, style) {
VT100.prototype.clearRegion = function(x, y, w, h, color, style) {
w += x;
if (x < 0) {
x = 0;
@ -1529,7 +1547,7 @@ VT100.prototype.clearRegion = function(x, y, w, h, style) {
// child nodes.
if (!this.numScrollbackLines &&
w == this.terminalWidth && h == this.terminalHeight &&
!style) {
(color == undefined || color == 'ansi0 bgAnsi15') && !style) {
var console = this.console[this.currentScreen];
while (console.lastChild) {
console.removeChild(console.lastChild);
@ -1541,7 +1559,7 @@ VT100.prototype.clearRegion = function(x, y, w, h, style) {
var cy = this.cursorY;
var s = this.spaces(w);
for (var i = y+h; i-- > y; ) {
this.putString(x, i, s, style);
this.putString(x, i, s, color, style);
}
hidden ? this.showCursor(cx, cy) : this.putString(cx, cy, '', undefined);
}
@ -1549,16 +1567,19 @@ VT100.prototype.clearRegion = function(x, y, w, h, style) {
VT100.prototype.copyLineSegment = function(dX, dY, sX, sY, w) {
var text = [ ];
var className = [ ];
var style = [ ];
var console = this.console[this.currentScreen];
if (sY >= console.childNodes.length) {
text[0] = this.spaces(w);
style[0] = null;
className[0] = undefined;
style[0] = undefined;
} else {
var line = console.childNodes[sY];
if (line.tagName != 'DIV' || !line.childNodes.length) {
text[0] = this.spaces(w);
style[0] = null;
className[0] = undefined;
style[0] = undefined;
} else {
var x = 0;
for (var span = line.firstChild; span && w > 0; span = span.nextSibling){
@ -1567,6 +1588,7 @@ VT100.prototype.copyLineSegment = function(dX, dY, sX, sY, w) {
if (x + len > sX) {
var o = sX > x ? sX - x : 0;
text[text.length] = s.substr(o, w);
className[className.length] = span.className;
style[style.length] = span.style.cssText;
w -= len - o;
}
@ -1574,7 +1596,8 @@ VT100.prototype.copyLineSegment = function(dX, dY, sX, sY, w) {
}
if (w > 0) {
text[text.length] = this.spaces(w);
style[style.length] = null;
className[className.length] = undefined;
style[style.length] = undefined;
}
}
}
@ -1582,13 +1605,20 @@ VT100.prototype.copyLineSegment = function(dX, dY, sX, sY, w) {
var cx = this.cursorX;
var cy = this.cursorY;
for (var i = 0; i < text.length; i++) {
this.putString(dX, dY - this.numScrollbackLines, text[i], style[i]);
var color;
if (className[i]) {
color = className[i];
} else {
color = 'ansi0 bgAnsi15';
}
this.putString(dX, dY - this.numScrollbackLines, text[i], color, style[i]);
dX += text[i].length;
}
hidden ? this.showCursor(cx, cy) : this.putString(cx, cy, '', undefined);
};
VT100.prototype.scrollRegion = function(x, y, w, h, incX, incY, style) {
VT100.prototype.scrollRegion = function(x, y, w, h, incX, incY,
color, style) {
var left = incX < 0 ? -incX : 0;
var right = incX > 0 ? incX : 0;
var up = incY < 0 ? -incY : 0;
@ -1623,9 +1653,7 @@ VT100.prototype.scrollRegion = function(x, y, w, h, incX, incY, style) {
// fill with underlined spaces. N.B. this is different from the
// cases when the user blanks a region. User-initiated blanking
// always fills with all of the current attributes.
this.attributeHelper.cssText
= style.replace(/text-decoration:underline;/, "");
style = this.attributeHelper.cssText;
style = style.replace(/text-decoration:underline;/, '');
}
// Compute current scroll position
@ -1654,7 +1682,7 @@ VT100.prototype.scrollRegion = function(x, y, w, h, incX, incY, style) {
// Add new lines at bottom in order to force scrolling
for (var i = 0; i < y; i++) {
this.insertBlankLine(console.childNodes.length, style);
this.insertBlankLine(console.childNodes.length, color, style);
}
// Adjust the number of lines in the scrollback buffer by
@ -1691,7 +1719,7 @@ VT100.prototype.scrollRegion = function(x, y, w, h, incX, incY, style) {
console.childNodes.length > this.numScrollbackLines+y+h+incY) {
for (var i = -incY; i-- > 0; ) {
this.insertBlankLine(this.numScrollbackLines + y + h + incY,
style);
color, style);
}
}
}
@ -1703,7 +1731,7 @@ VT100.prototype.scrollRegion = function(x, y, w, h, incX, incY, style) {
console.removeChild(console.childNodes[this.numScrollbackLines+y+h]);
}
for (var i = incY; i--; ) {
this.insertBlankLine(this.numScrollbackLines + y, style);
this.insertBlankLine(this.numScrollbackLines + y, color, style);
}
}
} else {
@ -1725,14 +1753,14 @@ VT100.prototype.scrollRegion = function(x, y, w, h, incX, incY, style) {
// Clear blank regions
if (incX > 0) {
this.clearRegion(x, y, incX, h, style);
this.clearRegion(x, y, incX, h, color, style);
} else if (incX < 0) {
this.clearRegion(x + w + incX, y, -incX, h, style);
this.clearRegion(x + w + incX, y, -incX, h, color, style);
}
if (incY > 0) {
this.clearRegion(x, y, w, incY, style);
this.clearRegion(x, y, w, incY, color, style);
} else if (incY < 0) {
this.clearRegion(x, y + h + incY, w, -incY, style);
this.clearRegion(x, y + h + incY, w, -incY, color, style);
}
}
@ -1829,9 +1857,11 @@ VT100.prototype.showContextMenu = function(x, y) {
'<li id="reset">Reset</li>' +
'<hr />' +
'<li id="beginconfig">' +
(this.utfEnabled ? '&#10004; ' : '') + 'Unicode</li>' +
(this.utfEnabled ? '<img src="enabled.gif" />' : '') +
'Unicode</li>' +
'<li id="endconfig">' +
(this.visualBell ? '&#10004; ' : '') + 'Visual Bell</li>'+
(this.visualBell ? '<img src="enabled.gif" />' : '') +
'Visual Bell</li>'+
(this.usercss.firstChild ?
'<hr id="beginusercss" />' +
this.usercss.innerHTML +
@ -2576,7 +2606,7 @@ VT100.prototype.lf = function(count) {
if (this.cursorY == this.bottom - 1) {
this.scrollRegion(0, this.top + 1,
this.terminalWidth, this.bottom - this.top - 1,
0, -1, this.style);
0, -1, this.color, this.style);
offset = undefined;
} else if (this.cursorY < this.terminalHeight - 1) {
this.gotoXY(this.cursorX, this.cursorY + 1);
@ -2599,7 +2629,7 @@ VT100.prototype.ri = function(count) {
if (this.cursorY == this.top) {
this.scrollRegion(0, this.top,
this.terminalWidth, this.bottom - this.top - 1,
0, 1, this.style);
0, 1, this.color, this.style);
} else if (this.cursorY > 0) {
this.gotoXY(this.cursorX, this.cursorY - 1);
}
@ -2615,10 +2645,11 @@ VT100.prototype.respondSecondaryDA = function() {
this.respondString += '\u001B[>0;0;0c';
};
VT100.prototype.updateStyle = function() {
var style = '';
this.style = '';
if (this.attr & ATTR_UNDERLINE) {
style += 'text-decoration:underline;';
this.style = 'text-decoration:underline;';
}
var bg = (this.attr >> 4) & 0xF;
var fg = this.attr & 0xF;
@ -2649,14 +2680,7 @@ VT100.prototype.updateStyle = function() {
}
}
if (fg != 0) {
style += 'color:' + this.ansi[fg] + ';';
}
if (bg != 15) {
style += 'background-color:' + this.ansi[bg] + ';';
}
this.attributeHelper.cssText = style;
this.style = this.attributeHelper.cssText;
this.color = 'ansi' + fg + ' bgAnsi' + bg;
};
VT100.prototype.setAttrColors = function(attr) {
@ -2750,7 +2774,7 @@ VT100.prototype.csiAt = function(number) {
}
this.scrollRegion(this.cursorX, this.cursorY,
this.terminalWidth - this.cursorX - number, 1,
number, 0, this.style);
number, 0, this.color, this.style);
this.needWrap = false;
};
@ -2758,22 +2782,26 @@ VT100.prototype.csiJ = function(number) {
switch (number) {
case 0: // Erase from cursor to end of display
this.clearRegion(this.cursorX, this.cursorY,
this.terminalWidth - this.cursorX, 1, this.style);
this.terminalWidth - this.cursorX, 1,
this.color, this.style);
if (this.cursorY < this.terminalHeight-2) {
this.clearRegion(0, this.cursorY+1,
this.terminalWidth, this.terminalHeight-this.cursorY-1,
this.style);
this.color, this.style);
}
break;
case 1: // Erase from start to cursor
if (this.cursorY > 0) {
this.clearRegion(0, 0,
this.terminalWidth, this.cursorY, this.style);
this.terminalWidth, this.cursorY,
this.color, this.style);
}
this.clearRegion(0, this.cursorY, this.cursorX + 1, 1, this.style);
this.clearRegion(0, this.cursorY, this.cursorX + 1, 1,
this.color, this.style);
break;
case 2: // Erase whole display
this.clearRegion(0, 0, this.terminalWidth, this.terminalHeight,this.style);
this.clearRegion(0, 0, this.terminalWidth, this.terminalHeight,
this.color, this.style);
break;
default:
return;
@ -2785,13 +2813,16 @@ VT100.prototype.csiK = function(number) {
switch (number) {
case 0: // Erase from cursor to end of line
this.clearRegion(this.cursorX, this.cursorY,
this.terminalWidth - this.cursorX, 1, this.style);
this.terminalWidth - this.cursorX, 1,
this.color, this.style);
break;
case 1: // Erase from start of line to cursor
this.clearRegion(0, this.cursorY, this.cursorX + 1, 1, this.style);
this.clearRegion(0, this.cursorY, this.cursorX + 1, 1,
this.color, this.style);
break;
case 2: // Erase whole line
this.clearRegion(0, this.cursorY, this.terminalWidth, 1, this.style);
this.clearRegion(0, this.cursorY, this.terminalWidth, 1,
this.color, this.style);
break;
default:
return;
@ -2812,7 +2843,7 @@ VT100.prototype.csiL = function(number) {
}
this.scrollRegion(0, this.cursorY,
this.terminalWidth, this.bottom - this.cursorY - number,
0, number, this.style);
0, number, this.color, this.style);
needWrap = false;
};
@ -2829,7 +2860,7 @@ VT100.prototype.csiM = function(number) {
}
this.scrollRegion(0, this.cursorY + number,
this.terminalWidth, this.bottom - this.cursorY - number,
0, -number, this.style);
0, -number, this.color, this.style);
needWrap = false;
};
@ -2890,7 +2921,7 @@ VT100.prototype.csiP = function(number) {
}
this.scrollRegion(this.cursorX + number, this.cursorY,
this.terminalWidth - this.cursorX - number, 1,
-number, 0, this.style);
-number, 0, this.color, this.style);
needWrap = false;
};
@ -2902,7 +2933,8 @@ VT100.prototype.csiX = function(number) {
if (number > this.terminalWidth - this.cursorX) {
number = this.terminalWidth - this.cursorX;
}
this.clearRegion(this.cursorX, this.cursorY, number, 1, this.style);
this.clearRegion(this.cursorX, this.cursorY, number, 1,
this.color, this.style);
needWrap = false;
};
@ -3224,7 +3256,7 @@ VT100.prototype.renderString = function(s, showCursor) {
// call to this.showCursor()
this.cursor.style.visibility = '';
}
this.putString(this.cursorX, this.cursorY, s, this.style);
this.putString(this.cursorX, this.cursorY, s, this.color, this.style);
};
VT100.prototype.vt100 = function(s) {
@ -3299,7 +3331,7 @@ VT100.prototype.vt100 = function(s) {
if (this.insertMode) {
this.scrollRegion(this.cursorX, this.cursorY,
this.terminalWidth - this.cursorX - 1, 1,
1, 0, this.style);
1, 0, this.color, this.style);
}
this.lastCharacter = String.fromCharCode(ch);
lineBuf += this.lastCharacter;

View file

@ -1,6 +1,6 @@
#vt100 #scrollable {
color: white;
background-color: black;
}
#vt100 #ansi0 { background-color: #ffffff; }
#vt100 #ansi15 { background-color: #000000; }
#vt100 #scrollable { color: #ffffff;
background-color: #000000; }
#vt100 #scrollable.inverted { color: #000000;
background-color: #ffffff; }
#vt100 .ansi15 { color: #000000; }
#vt100 .bgAnsi0 { background-color: #ffffff; }