]> andersk Git - test.git/commitdiff
Included example style sheets that allow switching to white-on-black or to
authorMarkus Gutschke <markus@shellinabox.com>
Wed, 12 Aug 2009 02:32:26 +0000 (02:32 +0000)
committerMarkus Gutschke <markus@shellinabox.com>
Wed, 12 Aug 2009 02:32:26 +0000 (02:32 +0000)
monochrome mode from the right click context menu. This required a couple of
architectural changes to the JavaScript code.

26 files changed:
ChangeLog
Makefile.am
Makefile.in
config.h
configure
configure.ac
debian/docs
demo/demo.html
demo/enabled.gif [new file with mode: 0644]
demo/styles.css
demo/usercss-0.css [new file with mode: 0644]
demo/usercss-1.css [new file with mode: 0644]
demo/usercss-2.css [new file with mode: 0644]
demo/usercss-3.css [new file with mode: 0644]
demo/vt100.js
shellinabox/black-on-white.css [new file with mode: 0644]
shellinabox/color.css [new file with mode: 0644]
shellinabox/enabled.gif [new file with mode: 0644]
shellinabox/launcher.c
shellinabox/monochrome.css [new file with mode: 0644]
shellinabox/shell_in_a_box.js
shellinabox/shellinaboxd.c
shellinabox/styles.css
shellinabox/vt100.js
shellinabox/vt100.jspp
shellinabox/white-on-black.css

index 62a56d33f573e0aeb63403914c0c423c5dc0d09f..763b71878c4bb03fa2917d56fcaefb1b5ae0db1c 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -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
index 1c78369a9e8eb884fb6e01b9c761c1f5f4fd8e15..e72456d9aada23c9b5324c83f6d5c1927099dbdc 100644 (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)`   \
index e61f461241b5e4d3bad407bde4755760c3d0d190..d56aa887b3504e86c8500f2f2349c2112a14ce9b 100644 (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)`   \
index d139dc5bfcf2ca6d24945cd503f6c8d482202e5e..5fc2644411f7526ec57d8ffd5f307d137afa9f5f 100644 (file)
--- a/config.h
+++ b/config.h
 #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"
index a9b93d9d4ed10c938faa2fc01de8206f85643052..2965c7f917bf27ce85658de56a6a5f8cf8b61d36 100755 (executable)
--- a/configure
+++ b/configure
@@ -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
index f640637cd5aa35113688807e1ea1f70a25f20c08..e0317169c427eb79dbe4e189aa272850d80b01d1 100644 (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])
index bc017c5bd33cde20789797ac99156e296ad7e54d..34380ab865c6b11efbbf55d6c3151b51e7ccb103 100644 (file)
@@ -6,3 +6,6 @@ NEWS
 README
 TODO
 shellinabox/white-on-black.css
+shellinabox/black-on-white.css
+shellinabox/monochrome.css
+shellinabox/color.css
index b726bfe042bbc48c6357461eff5269a75bacf368..aa419881c61191af46bf4184051fb39f0ac4ae59 100644 (file)
                        '}' +
                        '</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>
diff --git a/demo/enabled.gif b/demo/enabled.gif
new file mode 100644 (file)
index 0000000..07936e2
Binary files /dev/null and b/demo/enabled.gif differ
index ab66973ca4433afac4ddddb1aa9b27529f617442..6e465a12f23e878397afe04cada3ed2434c37dfd 100644 (file)
   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 {
diff --git a/demo/usercss-0.css b/demo/usercss-0.css
new file mode 100644 (file)
index 0000000..c64d5b1
--- /dev/null
@@ -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; }
diff --git a/demo/usercss-1.css b/demo/usercss-1.css
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/demo/usercss-2.css b/demo/usercss-2.css
new file mode 100644 (file)
index 0000000..b5c60a5
--- /dev/null
@@ -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; }
diff --git a/demo/usercss-3.css b/demo/usercss-3.css
new file mode 100644 (file)
index 0000000..e69de29
index 15a555b4a592d1a37790b5e6a3fd0d6c60003538..96fcc2b66529668d42befe79c6e59cc6bb4a866a 100644 (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();
@@ -636,12 +634,13 @@ VT100.prototype.repairElements = function(console) {
   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);
         }
@@ -649,7 +648,7 @@ VT100.prototype.repairElements = function(console) {
         this.setTextContent(newLine, this.getTextContent(line));
       }
       line.parentNode.replaceChild(newLine, line);
-      line                      = newLine;
+      line                        = newLine;
     }
   }
 };
@@ -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,22 +1022,26 @@ 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) {
-    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 {
@@ -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,54 +1559,66 @@ 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);
   }
 };
 
 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;
@@ -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,48 +2645,42 @@ 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;
+  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) {
@@ -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;
diff --git a/shellinabox/black-on-white.css b/shellinabox/black-on-white.css
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/shellinabox/color.css b/shellinabox/color.css
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/shellinabox/enabled.gif b/shellinabox/enabled.gif
new file mode 100644 (file)
index 0000000..07936e2
Binary files /dev/null and b/shellinabox/enabled.gif differ
index 47732ee03a811bce2a344c285d64f4c84d040b74..26976fbd2e89443551e354e5f36fe78ed361ca5b 100644 (file)
@@ -1195,12 +1195,24 @@ static void execService(int width, int height, struct Service *service,
 
 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
   }
 }
 
diff --git a/shellinabox/monochrome.css b/shellinabox/monochrome.css
new file mode 100644 (file)
index 0000000..b5c60a5
--- /dev/null
@@ -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; }
index 7b8c87231cd03f0ce0eee49f897f78f59f338dce..a6cb7253c69772db36f209cb95394f1f7c6b79ad 100644 (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 ?
index e077b28c70c320d2fd356deaaa71c6589a055d05..b89669a5215cba020fe4f45edcd63599c4d74ed3 100644 (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[];
index ab66973ca4433afac4ddddb1aa9b27529f617442..6e465a12f23e878397afe04cada3ed2434c37dfd 100644 (file)
   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 {
index 15a555b4a592d1a37790b5e6a3fd0d6c60003538..96fcc2b66529668d42befe79c6e59cc6bb4a866a 100644 (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();
@@ -636,12 +634,13 @@ VT100.prototype.repairElements = function(console) {
   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);
         }
@@ -649,7 +648,7 @@ VT100.prototype.repairElements = function(console) {
         this.setTextContent(newLine, this.getTextContent(line));
       }
       line.parentNode.replaceChild(newLine, line);
-      line                      = newLine;
+      line                        = newLine;
     }
   }
 };
@@ -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,22 +1022,26 @@ 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) {
-    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 {
@@ -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,54 +1559,66 @@ 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);
   }
 };
 
 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;
@@ -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,48 +2645,42 @@ 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;
+  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) {
@@ -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;
index 8759856a2db3d0a5e5feb71bba52ef5e34670ea4..925ea4453a1549d0273a30ec9c84399d07e3f4b3 100644 (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();
@@ -636,12 +634,13 @@ VT100.prototype.repairElements = function(console) {
   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);
         }
@@ -649,7 +648,7 @@ VT100.prototype.repairElements = function(console) {
         this.setTextContent(newLine, this.getTextContent(line));
       }
       line.parentNode.replaceChild(newLine, line);
-      line                      = newLine;
+      line                        = newLine;
     }
   }
 };
@@ -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,22 +1022,26 @@ 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) {
-    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 {
@@ -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,54 +1559,66 @@ 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);
   }
 };
 
 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;
@@ -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,48 +2645,42 @@ 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;
+  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) {
@@ -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;
index db2dcf8825548ebf73a713d37466e4afbbe3f624..c64d5b1c7d676c2714bc9cc1ecf9925deabfc966 100644 (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; }
This page took 0.190752 seconds and 5 git commands to generate.