+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
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 \
shellinabox/vt100.jspp \
shellinabox/shell_in_a_box.jspp \
shellinabox/styles.css \
+ shellinabox/enabled.gif \
shellinabox/favicon.ico \
shellinabox/beep.wav \
config.h
${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 "$<" "$@"
@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 "$<" "$@"
@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)` \
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) \
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.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 \
shellinabox/vt100.jspp \
shellinabox/shell_in_a_box.jspp \
shellinabox/styles.css \
+ shellinabox/enabled.gif \
shellinabox/favicon.ico \
shellinabox/beep.wav \
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)
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) \
-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)
${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 "$<" "$@"
@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 "$<" "$@"
@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)` \
#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"
ac_compiler_gnu=$ac_cv_c_compiler_gnu
-VCS_REVISION=166
+VCS_REVISION=167
cat >>confdefs.h <<_ACEOF
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])
README
TODO
shellinabox/white-on-black.css
+shellinabox/black-on-white.css
+shellinabox/monochrome.css
+shellinabox/color.css
'}' +
'</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>
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 {
--- /dev/null
+#vt100 #scrollable { color: #ffffff;
+ background-color: #000000; }
+#vt100 #scrollable.inverted { color: #000000;
+ background-color: #ffffff; }
+#vt100 .ansi15 { color: #000000; }
+#vt100 .bgAnsi0 { background-color: #ffffff; }
--- /dev/null
+#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; }
'(?:[?](?:(?![ \u00A0]|[,.)}"\u0027!]+[ \u00A0]|[,.)}"\u0027!]+$).)*)?');
}
this.initializeElements(container);
- this.initializeAnsiColors();
this.maxScrollbackLines = 500;
this.npar = 0;
this.par = [ ];
suppressAllAudio;
this.utfCount = 0;
this.utfChar = 0;
+ this.color = 'ansi0 bgAnsi15';
this.style = '';
this.attr = 0x00F0 /* ATTR_DEFAULT */;
this.useGMap = 0;
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) {
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) {
sheet.disabled = false;
}
if (!sheet.disabled) {
- label.innerHTML= '✔ ' + label.innerHTML;
+ label.innerHTML= '<img src="enabled.gif" />' +
+ label.innerHTML;
}
} else {
sheet.disabled = true;
// both ends), or whether this is a on/off toggle, which can be grouped
// together with other on/off options.
group +=
- '<li>' + (enabled ? '✔ ' : '') + label + '</li>';
+ '<li>' + (enabled ? '<img src="enabled.gif" />' : '') +
+ label +
+ '</li>';
}
this.usercss.innerHTML = menu;
}
!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.
'<pre><div><span id="space"></span></div></pre>' +
'<input type="textfield" id="input" />' +
'<input type="textfield" id="cliphelper" />' +
- '<span id="attrib"> </span>' +
(typeof suppressAllAudio != 'undefined' &&
suppressAllAudio ? "" :
embed + '<bgsound id="beep_bgsound" loop=1 />') +
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();
for (var line = console.firstChild; line; line = line.nextSibling) {
if (!line.clientHeight) {
var newLine = document.createElement(line.tagName);
- newLine.style.cssText = line.style.cssText;
- newLine.className = line.className;
+ newLine.style.cssText = line.style.cssText;
+ newLine.className = line.className;
if (line.tagName == 'DIV') {
for (var span = line.firstChild; span; span = span.nextSibling) {
- var newSpan = document.createElement(span.tagName);
- newSpan.style.cssText = span.style.cssText;
+ 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);
}
this.setTextContent(newLine, this.getTextContent(line));
}
line.parentNode.replaceChild(newLine, line);
- line = newLine;
+ line = newLine;
}
}
};
}
};
-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.
// 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) {
- style = '';
+ if (!color) {
+ color = 'ansi0 bgAnsi15';
}
- var line;
if (!style) {
- line = document.createElement('pre');
+ style = '';
+ }
+ var line;
+ 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;
+ 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);
}
- line.style.height = this.cursorHeight + 'px';
- var console = this.console[this.currentScreen];
+ line.style.height = this.cursorHeight + 'px';
+ var console = this.console[this.currentScreen];
if (console.childNodes.length > y) {
console.insertBefore(line, console.childNodes[y]);
} else {
}
// 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--; ) {
}
};
-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 = '';
}
// 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 = '';
// 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) {
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);
span = sibling;
if (remainder.length) {
sibling = document.createElement('span');
+ sibling.className = oldColor;
sibling.style.cssText = oldStyle;
this.setTextContent(sibling, remainder);
line.appendChild(sibling);
}
s = text;
}
+ span.className = color;
span.style.cssText = style;
} else {
// Overwrite (partial) <span> with new text
}
// 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));
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) +
// 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--; ) {
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/, '');
}
};
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;
// 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);
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);
}
};
VT100.prototype.copyLineSegment = function(dX, dY, sX, sY, w) {
- var text = [ ];
- var style = [ ];
- var console = this.console[this.currentScreen];
+ 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;
+ text[0] = this.spaces(w);
+ 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;
+ text[0] = this.spaces(w);
+ className[0] = undefined;
+ style[0] = undefined;
} else {
- var x = 0;
+ var x = 0;
for (var span = line.firstChild; span && w > 0; span = span.nextSibling){
- var s = this.getTextContent(span);
- var len = s.length;
+ var s = this.getTextContent(span);
+ var len = s.length;
if (x + len > sX) {
- var o = sX > x ? sX - x : 0;
- text[text.length] = s.substr(o, w);
- style[style.length] = span.style.cssText;
- w -= len - o;
+ 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;
}
- x += len;
+ x += len;
}
if (w > 0) {
- text[text.length] = this.spaces(w);
- style[style.length] = null;
+ text[text.length] = this.spaces(w);
+ className[className.length] = undefined;
+ style[style.length] = undefined;
}
}
}
- var hidden = this.hideCursor();
- var cx = this.cursorX;
- var cy = this.cursorY;
+ var hidden = this.hideCursor();
+ 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]);
- dX += text[i].length;
+ 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;
// 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
// 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
console.childNodes.length > this.numScrollbackLines+y+h+incY) {
for (var i = -incY; i-- > 0; ) {
this.insertBlankLine(this.numScrollbackLines + y + h + incY,
- style);
+ color, 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 {
// 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);
}
}
};
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");
};
'<li id="reset">Reset</li>' +
'<hr />' +
'<li id="beginconfig">' +
- (this.utfEnabled ? '✔ ' : '') + 'Unicode</li>' +
+ (this.utfEnabled ? '<img src="enabled.gif" />' : '') +
+ 'Unicode</li>' +
'<li id="endconfig">' +
- (this.visualBell ? '✔ ' : '') + 'Visual Bell</li>'+
+ (this.visualBell ? '<img src="enabled.gif" />' : '') +
+ 'Visual Bell</li>'+
(this.usercss.firstChild ?
'<hr id="beginusercss" />' +
this.usercss.innerHTML +
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);
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);
}
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;
+ var bg = (this.attr >> 4) & 0xF;
+ var fg = this.attr & 0xF;
if (this.attr & 0x0100 /* ATTR_REVERSE */) {
- var tmp = bg;
- bg = fg;
- fg = tmp;
+ var tmp = bg;
+ bg = fg;
+ fg = tmp;
}
if ((this.attr & (0x0100 /* ATTR_REVERSE */ | 0x0400 /* ATTR_DIM */)) == 0x0400 /* ATTR_DIM */) {
- fg = 8; // Dark grey
+ fg = 8; // Dark grey
} else if (this.attr & 0x0800 /* ATTR_BRIGHT */) {
- fg |= 8;
+ fg |= 8;
}
if (this.attr & 0x1000 /* ATTR_BLINK */) {
- bg ^= 8;
+ bg ^= 8;
}
// Make some readability enhancements. Most notably, disallow identical
// background and foreground colors.
if (bg == fg) {
- if ((fg ^= 8) == 7) {
- fg = 8;
+ if ((fg ^= 8) == 7) {
+ fg = 8;
}
}
// And disallow bright colors on a light-grey background.
if (bg == 7 && fg >= 8) {
- if ((fg -= 8) == 7) {
- fg = 8;
+ if ((fg -= 8) == 7) {
+ fg = 8;
}
}
- 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) {
}
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;
};
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;
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;
}
this.scrollRegion(0, this.cursorY,
this.terminalWidth, this.bottom - this.cursorY - number,
- 0, number, this.style);
+ 0, number, this.color, this.style);
needWrap = false;
};
}
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;
};
}
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;
};
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;
};
// 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) {
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;
void setWindowSize(int pty, int width, int height) {
if (width > 0 && height > 0) {
- struct winsize win;
- win.ws_row = height;
- win.ws_col = width;
- win.ws_xpixel = 0;
- win.ws_ypixel = 0;
- ioctl(pty, TIOCSWINSZ, &win);
+ #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;
+ ioctl(pty, TIOCSWINSZ, &win);
+ }
+ #endif
}
}
--- /dev/null
+#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; }
};
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 ?
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[];
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 {
'(?:[?](?:(?![ \u00A0]|[,.)}"\u0027!]+[ \u00A0]|[,.)}"\u0027!]+$).)*)?');
}
this.initializeElements(container);
- this.initializeAnsiColors();
this.maxScrollbackLines = 500;
this.npar = 0;
this.par = [ ];
suppressAllAudio;
this.utfCount = 0;
this.utfChar = 0;
+ this.color = 'ansi0 bgAnsi15';
this.style = '';
this.attr = 0x00F0 /* ATTR_DEFAULT */;
this.useGMap = 0;
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) {
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) {
sheet.disabled = false;
}
if (!sheet.disabled) {
- label.innerHTML= '✔ ' + label.innerHTML;
+ label.innerHTML= '<img src="enabled.gif" />' +
+ label.innerHTML;
}
} else {
sheet.disabled = true;
// both ends), or whether this is a on/off toggle, which can be grouped
// together with other on/off options.
group +=
- '<li>' + (enabled ? '✔ ' : '') + label + '</li>';
+ '<li>' + (enabled ? '<img src="enabled.gif" />' : '') +
+ label +
+ '</li>';
}
this.usercss.innerHTML = menu;
}
!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.
'<pre><div><span id="space"></span></div></pre>' +
'<input type="textfield" id="input" />' +
'<input type="textfield" id="cliphelper" />' +
- '<span id="attrib"> </span>' +
(typeof suppressAllAudio != 'undefined' &&
suppressAllAudio ? "" :
embed + '<bgsound id="beep_bgsound" loop=1 />') +
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();
for (var line = console.firstChild; line; line = line.nextSibling) {
if (!line.clientHeight) {
var newLine = document.createElement(line.tagName);
- newLine.style.cssText = line.style.cssText;
- newLine.className = line.className;
+ newLine.style.cssText = line.style.cssText;
+ newLine.className = line.className;
if (line.tagName == 'DIV') {
for (var span = line.firstChild; span; span = span.nextSibling) {
- var newSpan = document.createElement(span.tagName);
- newSpan.style.cssText = span.style.cssText;
+ 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);
}
this.setTextContent(newLine, this.getTextContent(line));
}
line.parentNode.replaceChild(newLine, line);
- line = newLine;
+ line = newLine;
}
}
};
}
};
-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.
// 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) {
- style = '';
+ if (!color) {
+ color = 'ansi0 bgAnsi15';
}
- var line;
if (!style) {
- line = document.createElement('pre');
+ style = '';
+ }
+ var line;
+ 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;
+ 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);
}
- line.style.height = this.cursorHeight + 'px';
- var console = this.console[this.currentScreen];
+ line.style.height = this.cursorHeight + 'px';
+ var console = this.console[this.currentScreen];
if (console.childNodes.length > y) {
console.insertBefore(line, console.childNodes[y]);
} else {
}
// 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--; ) {
}
};
-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 = '';
}
// 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 = '';
// 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) {
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);
span = sibling;
if (remainder.length) {
sibling = document.createElement('span');
+ sibling.className = oldColor;
sibling.style.cssText = oldStyle;
this.setTextContent(sibling, remainder);
line.appendChild(sibling);
}
s = text;
}
+ span.className = color;
span.style.cssText = style;
} else {
// Overwrite (partial) <span> with new text
}
// 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));
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) +
// 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--; ) {
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/, '');
}
};
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;
// 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);
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);
}
};
VT100.prototype.copyLineSegment = function(dX, dY, sX, sY, w) {
- var text = [ ];
- var style = [ ];
- var console = this.console[this.currentScreen];
+ 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;
+ text[0] = this.spaces(w);
+ 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;
+ text[0] = this.spaces(w);
+ className[0] = undefined;
+ style[0] = undefined;
} else {
- var x = 0;
+ var x = 0;
for (var span = line.firstChild; span && w > 0; span = span.nextSibling){
- var s = this.getTextContent(span);
- var len = s.length;
+ var s = this.getTextContent(span);
+ var len = s.length;
if (x + len > sX) {
- var o = sX > x ? sX - x : 0;
- text[text.length] = s.substr(o, w);
- style[style.length] = span.style.cssText;
- w -= len - o;
+ 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;
}
- x += len;
+ x += len;
}
if (w > 0) {
- text[text.length] = this.spaces(w);
- style[style.length] = null;
+ text[text.length] = this.spaces(w);
+ className[className.length] = undefined;
+ style[style.length] = undefined;
}
}
}
- var hidden = this.hideCursor();
- var cx = this.cursorX;
- var cy = this.cursorY;
+ var hidden = this.hideCursor();
+ 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]);
- dX += text[i].length;
+ 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;
// 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
// 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
console.childNodes.length > this.numScrollbackLines+y+h+incY) {
for (var i = -incY; i-- > 0; ) {
this.insertBlankLine(this.numScrollbackLines + y + h + incY,
- style);
+ color, 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 {
// 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);
}
}
};
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");
};
'<li id="reset">Reset</li>' +
'<hr />' +
'<li id="beginconfig">' +
- (this.utfEnabled ? '✔ ' : '') + 'Unicode</li>' +
+ (this.utfEnabled ? '<img src="enabled.gif" />' : '') +
+ 'Unicode</li>' +
'<li id="endconfig">' +
- (this.visualBell ? '✔ ' : '') + 'Visual Bell</li>'+
+ (this.visualBell ? '<img src="enabled.gif" />' : '') +
+ 'Visual Bell</li>'+
(this.usercss.firstChild ?
'<hr id="beginusercss" />' +
this.usercss.innerHTML +
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);
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);
}
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;
+ var bg = (this.attr >> 4) & 0xF;
+ var fg = this.attr & 0xF;
if (this.attr & 0x0100 /* ATTR_REVERSE */) {
- var tmp = bg;
- bg = fg;
- fg = tmp;
+ var tmp = bg;
+ bg = fg;
+ fg = tmp;
}
if ((this.attr & (0x0100 /* ATTR_REVERSE */ | 0x0400 /* ATTR_DIM */)) == 0x0400 /* ATTR_DIM */) {
- fg = 8; // Dark grey
+ fg = 8; // Dark grey
} else if (this.attr & 0x0800 /* ATTR_BRIGHT */) {
- fg |= 8;
+ fg |= 8;
}
if (this.attr & 0x1000 /* ATTR_BLINK */) {
- bg ^= 8;
+ bg ^= 8;
}
// Make some readability enhancements. Most notably, disallow identical
// background and foreground colors.
if (bg == fg) {
- if ((fg ^= 8) == 7) {
- fg = 8;
+ if ((fg ^= 8) == 7) {
+ fg = 8;
}
}
// And disallow bright colors on a light-grey background.
if (bg == 7 && fg >= 8) {
- if ((fg -= 8) == 7) {
- fg = 8;
+ if ((fg -= 8) == 7) {
+ fg = 8;
}
}
- 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) {
}
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;
};
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;
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;
}
this.scrollRegion(0, this.cursorY,
this.terminalWidth, this.bottom - this.cursorY - number,
- 0, number, this.style);
+ 0, number, this.color, this.style);
needWrap = false;
};
}
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;
};
}
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;
};
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;
};
// 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) {
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;
'(?:[?](?:(?![ \u00A0]|[,.)}"\u0027!]+[ \u00A0]|[,.)}"\u0027!]+$).)*)?');
}
this.initializeElements(container);
- this.initializeAnsiColors();
this.maxScrollbackLines = 500;
this.npar = 0;
this.par = [ ];
suppressAllAudio;
this.utfCount = 0;
this.utfChar = 0;
+ this.color = 'ansi0 bgAnsi15';
this.style = '';
this.attr = ATTR_DEFAULT;
this.useGMap = 0;
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) {
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) {
sheet.disabled = false;
}
if (!sheet.disabled) {
- label.innerHTML= '✔ ' + label.innerHTML;
+ label.innerHTML= '<img src="enabled.gif" />' +
+ label.innerHTML;
}
} else {
sheet.disabled = true;
// both ends), or whether this is a on/off toggle, which can be grouped
// together with other on/off options.
group +=
- '<li>' + (enabled ? '✔ ' : '') + label + '</li>';
+ '<li>' + (enabled ? '<img src="enabled.gif" />' : '') +
+ label +
+ '</li>';
}
this.usercss.innerHTML = menu;
}
!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.
'<pre><div><span id="space"></span></div></pre>' +
'<input type="textfield" id="input" />' +
'<input type="textfield" id="cliphelper" />' +
- '<span id="attrib"> </span>' +
(typeof suppressAllAudio != 'undefined' &&
suppressAllAudio ? "" :
embed + '<bgsound id="beep_bgsound" loop=1 />') +
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();
for (var line = console.firstChild; line; line = line.nextSibling) {
if (!line.clientHeight) {
var newLine = document.createElement(line.tagName);
- newLine.style.cssText = line.style.cssText;
- newLine.className = line.className;
+ newLine.style.cssText = line.style.cssText;
+ newLine.className = line.className;
if (line.tagName == 'DIV') {
for (var span = line.firstChild; span; span = span.nextSibling) {
- var newSpan = document.createElement(span.tagName);
- newSpan.style.cssText = span.style.cssText;
+ 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);
}
this.setTextContent(newLine, this.getTextContent(line));
}
line.parentNode.replaceChild(newLine, line);
- line = newLine;
+ line = newLine;
}
}
};
}
};
-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.
// 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) {
- style = '';
+ if (!color) {
+ color = 'ansi0 bgAnsi15';
}
- var line;
if (!style) {
- line = document.createElement('pre');
+ style = '';
+ }
+ var line;
+ 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;
+ 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);
}
- line.style.height = this.cursorHeight + 'px';
- var console = this.console[this.currentScreen];
+ line.style.height = this.cursorHeight + 'px';
+ var console = this.console[this.currentScreen];
if (console.childNodes.length > y) {
console.insertBefore(line, console.childNodes[y]);
} else {
}
// 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--; ) {
}
};
-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 = '';
}
// 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 = '';
// 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) {
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);
span = sibling;
if (remainder.length) {
sibling = document.createElement('span');
+ sibling.className = oldColor;
sibling.style.cssText = oldStyle;
this.setTextContent(sibling, remainder);
line.appendChild(sibling);
}
s = text;
}
+ span.className = color;
span.style.cssText = style;
} else {
// Overwrite (partial) <span> with new text
}
// 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));
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) +
// 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--; ) {
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/, '');
}
};
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;
// 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);
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);
}
};
VT100.prototype.copyLineSegment = function(dX, dY, sX, sY, w) {
- var text = [ ];
- var style = [ ];
- var console = this.console[this.currentScreen];
+ 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;
+ text[0] = this.spaces(w);
+ 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;
+ text[0] = this.spaces(w);
+ className[0] = undefined;
+ style[0] = undefined;
} else {
- var x = 0;
+ var x = 0;
for (var span = line.firstChild; span && w > 0; span = span.nextSibling){
- var s = this.getTextContent(span);
- var len = s.length;
+ var s = this.getTextContent(span);
+ var len = s.length;
if (x + len > sX) {
- var o = sX > x ? sX - x : 0;
- text[text.length] = s.substr(o, w);
- style[style.length] = span.style.cssText;
- w -= len - o;
+ 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;
}
- x += len;
+ x += len;
}
if (w > 0) {
- text[text.length] = this.spaces(w);
- style[style.length] = null;
+ text[text.length] = this.spaces(w);
+ className[className.length] = undefined;
+ style[style.length] = undefined;
}
}
}
- var hidden = this.hideCursor();
- var cx = this.cursorX;
- var cy = this.cursorY;
+ var hidden = this.hideCursor();
+ 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]);
- dX += text[i].length;
+ 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;
// 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
// 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
console.childNodes.length > this.numScrollbackLines+y+h+incY) {
for (var i = -incY; i-- > 0; ) {
this.insertBlankLine(this.numScrollbackLines + y + h + incY,
- style);
+ color, 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 {
// 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);
}
}
'<li id="reset">Reset</li>' +
'<hr />' +
'<li id="beginconfig">' +
- (this.utfEnabled ? '✔ ' : '') + 'Unicode</li>' +
+ (this.utfEnabled ? '<img src="enabled.gif" />' : '') +
+ 'Unicode</li>' +
'<li id="endconfig">' +
- (this.visualBell ? '✔ ' : '') + 'Visual Bell</li>'+
+ (this.visualBell ? '<img src="enabled.gif" />' : '') +
+ 'Visual Bell</li>'+
(this.usercss.firstChild ?
'<hr id="beginusercss" />' +
this.usercss.innerHTML +
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);
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);
}
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;
+ var bg = (this.attr >> 4) & 0xF;
+ var fg = this.attr & 0xF;
if (this.attr & ATTR_REVERSE) {
- var tmp = bg;
- bg = fg;
- fg = tmp;
+ var tmp = bg;
+ bg = fg;
+ fg = tmp;
}
if ((this.attr & (ATTR_REVERSE | ATTR_DIM)) == ATTR_DIM) {
- fg = 8; // Dark grey
+ fg = 8; // Dark grey
} else if (this.attr & ATTR_BRIGHT) {
- fg |= 8;
+ fg |= 8;
}
if (this.attr & ATTR_BLINK) {
- bg ^= 8;
+ bg ^= 8;
}
// Make some readability enhancements. Most notably, disallow identical
// background and foreground colors.
if (bg == fg) {
- if ((fg ^= 8) == 7) {
- fg = 8;
+ if ((fg ^= 8) == 7) {
+ fg = 8;
}
}
// And disallow bright colors on a light-grey background.
if (bg == 7 && fg >= 8) {
- if ((fg -= 8) == 7) {
- fg = 8;
+ if ((fg -= 8) == 7) {
+ fg = 8;
}
}
- 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) {
}
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;
};
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;
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;
}
this.scrollRegion(0, this.cursorY,
this.terminalWidth, this.bottom - this.cursorY - number,
- 0, number, this.style);
+ 0, number, this.color, this.style);
needWrap = false;
};
}
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;
};
}
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;
};
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;
};
// 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) {
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;
-#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; }