\n';
1565 | var rstr='';
1566 | for (var c=0; c'+rstr+'<\/td><\/tr>\n';
1570 | }
1571 | s+='<\/table><\/td><\/tr>\n';
1572 | s+='<\/table><\/td><\/tr>\n';
1573 | s+='<\/table>\n';
1574 | var termOffset=2+this.conf.frameWidth;
1575 | if (this.globals.hasSubDivs) {
1576 | for (var r=0; r<\/div>\n';
1578 | }
1579 | this.globals.termStringStart='';
1580 | this.globals.termStringEnd='<\/td><\/tr><\/table>';
1581 | }
1582 | this.globals.writeElement(this.termDiv,s);
1583 | }
1584 | if (!rebuild) {
1585 | this.globals.setElementXY(this.termDiv,this.conf.x,this.conf.y);
1586 | this.globals.setVisible(this.termDiv,1);
1587 | }
1588 | window.status='';
1589 | },
1590 |
1591 | rebuild: function() {
1592 | // check for bounds and array lengths
1593 | var rl=this.conf.rows;
1594 | var cl=this.conf.cols;
1595 | for (var r=0; r=rl) {
1610 | r=rl-1;
1611 | resetcrsr=true;
1612 | }
1613 | if (this.c>=cl) {
1614 | c=cl-1;
1615 | resetcrsr=true;
1616 | }
1617 | if (resetcrsr && this.cursoractive) this.cursorOn();
1618 | // and actually rebuild
1619 | this._makeTerm(true);
1620 | for (var r=0; r';
1668 | for (var k=tstls.length-1; k>=0; k--) {
1669 | var st=tstls[k];
1670 | if (curStyle & st) s+=tscls[st];
1671 | }
1672 | }
1673 | curStyle=cs;
1674 | for (var k=0; k>>8;
1681 | clr= (cc<16)? tclrs[cc] : '#'+tnclrs[cc-16];
1682 | }
1683 | else if (curStyle & 0xff0000) {
1684 | clr='#'+twclrs[(curStyle & 0xff0000)>>>16];
1685 | }
1686 | if (clr) {
1687 | if (curStyle&1) {
1688 | s+='';
1689 | }
1690 | else if (blur) {
1691 | s+='';
1692 | }
1693 | else {
1694 | s+='';
1695 | }
1696 | }
1697 | }
1698 | s+= (tspcl[c])? tspcl[c] : String.fromCharCode(c);
1699 | }
1700 | if (curStyle>0) {
1701 | if (curStyle & 0xffff00) s+='';
1702 | for (var k=tstls.length-1; k>=0; k--) {
1703 | var st=tstls[k];
1704 | if (curStyle&st) s+=tscls[st];
1705 | }
1706 | }
1707 | s+=this.globals.termStringEnd;
1708 | this.globals.writeElement(this.termDiv+'_r'+r,s);
1709 | },
1710 |
1711 | guiReady: function() {
1712 | var ready=true;
1713 | if (this.globals.guiElementsReady(this.termDiv)) {
1714 | for (var r=0; r='0' && c<='9') || (c>='a' && c<='f') || (c>='A' && c<='F'))? true:false;
1803 | },
1804 |
1805 | isHexOnlyChar: function(c) {
1806 | return ((c>='a' && c<='f') || (c>='A' && c<='F'))? true:false;
1807 | },
1808 |
1809 | hexToNum: {
1810 | '0': 0, '1': 1, '2': 2, '3': 3, '4': 4, '5': 5, '6': 6, '7': 7,
1811 | '8': 8, '9': 9, 'a': 10, 'b': 11, 'c': 12, 'd': 13, 'e': 14, 'f': 15,
1812 | 'A': 10, 'B': 11, 'C': 12, 'D': 13, 'E': 14, 'F': 15
1813 | },
1814 |
1815 | // data for color support
1816 |
1817 | webColors: [],
1818 | webColorCodes: [''],
1819 |
1820 | colors: {
1821 | // ANSI bright (bold) color set
1822 | black: 1,
1823 | red: 2,
1824 | green: 3,
1825 | yellow: 4,
1826 | blue: 5,
1827 | magenta: 6,
1828 | cyan: 7,
1829 | white: 8,
1830 | // dark color set
1831 | grey: 9,
1832 | red2: 10,
1833 | green2: 11,
1834 | yellow2: 12,
1835 | blue2: 13,
1836 | magenta2: 14,
1837 | cyan2: 15,
1838 | // synonyms
1839 | red1: 2,
1840 | green1: 3,
1841 | yellow1: 4,
1842 | blue1: 5,
1843 | magenta1: 6,
1844 | cyan1: 7,
1845 | gray: 9,
1846 | darkred: 10,
1847 | darkgreen: 11,
1848 | darkyellow: 12,
1849 | darkblue: 13,
1850 | darkmagenta: 14,
1851 | darkcyan: 15,
1852 | // default color
1853 | 'default': 0,
1854 | clear: 0
1855 | },
1856 |
1857 | colorCodes: [
1858 | '', '#000000', '#ff0000', '#00ff00', '#ffff00', '#0066ff', '#ff00ff', '#00ffff', '#ffffff',
1859 | '#808080', '#990000', '#009900', '#999900', '#003399', '#990099', '#009999'
1860 | ],
1861 |
1862 | nsColors: {
1863 | 'aliceblue': 1, 'antiquewhite': 2, 'aqua': 3, 'aquamarine': 4,
1864 | 'azure': 5, 'beige': 6, 'black': 7, 'blue': 8,
1865 | 'blueviolet': 9, 'brown': 10, 'burlywood': 11, 'cadetblue': 12,
1866 | 'chartreuse': 13, 'chocolate': 14, 'coral': 15, 'cornflowerblue': 16,
1867 | 'cornsilk': 17, 'crimson': 18, 'darkblue': 19, 'darkcyan': 20,
1868 | 'darkgoldenrod': 21, 'darkgray': 22, 'darkgreen': 23, 'darkkhaki': 24,
1869 | 'darkmagenta': 25, 'darkolivegreen': 26, 'darkorange': 27, 'darkorchid': 28,
1870 | 'darkred': 29, 'darksalmon': 30, 'darkseagreen': 31, 'darkslateblue': 32,
1871 | 'darkslategray': 33, 'darkturquoise': 34, 'darkviolet': 35, 'deeppink': 36,
1872 | 'deepskyblue': 37, 'dimgray': 38, 'dodgerblue': 39, 'firebrick': 40,
1873 | 'floralwhite': 41, 'forestgreen': 42, 'fuchsia': 43, 'gainsboro': 44,
1874 | 'ghostwhite': 45, 'gold': 46, 'goldenrod': 47, 'gray': 48,
1875 | 'green': 49, 'greenyellow': 50, 'honeydew': 51, 'hotpink': 52,
1876 | 'indianred': 53, 'indigo': 54, 'ivory': 55, 'khaki': 56,
1877 | 'lavender': 57, 'lavenderblush': 58, 'lawngreen': 59, 'lemonchiffon': 60,
1878 | 'lightblue': 61, 'lightcoral': 62, 'lightcyan': 63, 'lightgoldenrodyellow': 64,
1879 | 'lightgreen': 65, 'lightgrey': 66, 'lightpink': 67, 'lightsalmon': 68,
1880 | 'lightseagreen': 69, 'lightskyblue': 70, 'lightslategray': 71, 'lightsteelblue': 72,
1881 | 'lightyellow': 73, 'lime': 74, 'limegreen': 75, 'linen': 76,
1882 | 'maroon': 77, 'mediumaquamarine': 78, 'mediumblue': 79, 'mediumorchid': 80,
1883 | 'mediumpurple': 81, 'mediumseagreen': 82, 'mediumslateblue': 83, 'mediumspringgreen': 84,
1884 | 'mediumturquoise': 85, 'mediumvioletred': 86, 'midnightblue': 87, 'mintcream': 88,
1885 | 'mistyrose': 89, 'moccasin': 90, 'navajowhite': 91, 'navy': 92,
1886 | 'oldlace': 93, 'olive': 94, 'olivedrab': 95, 'orange': 96,
1887 | 'orangered': 97, 'orchid': 98, 'palegoldenrod': 99, 'palegreen': 100,
1888 | 'paleturquoise': 101, 'palevioletred': 102, 'papayawhip': 103, 'peachpuff': 104,
1889 | 'peru': 105, 'pink': 106, 'plum': 107, 'powderblue': 108,
1890 | 'purple': 109, 'red': 110, 'rosybrown': 111, 'royalblue': 112,
1891 | 'saddlebrown': 113, 'salmon': 114, 'sandybrown': 115, 'seagreen': 116,
1892 | 'seashell': 117, 'sienna': 118, 'silver': 119, 'skyblue': 120,
1893 | 'slateblue': 121, 'slategray': 122, 'snow': 123, 'springgreen': 124,
1894 | 'steelblue': 125, 'tan': 126, 'teal': 127, 'thistle': 128,
1895 | 'tomato': 129, 'turquoise': 130, 'violet': 131, 'wheat': 132,
1896 | 'white': 133, 'whitesmoke': 134, 'yellow': 135, 'yellowgreen': 136
1897 | },
1898 |
1899 | nsColorCodes: [
1900 | '',
1901 | 'f0f8ff', 'faebd7', '00ffff', '7fffd4',
1902 | 'f0ffff', 'f5f5dc', '000000', '0000ff',
1903 | '8a2be2', 'a52a2a', 'deb887', '5f9ea0',
1904 | '7fff00', 'd2691e', 'ff7f50', '6495ed',
1905 | 'fff8dc', 'dc143c', '00008b', '008b8b',
1906 | 'b8860b', 'a9a9a9', '006400', 'bdb76b',
1907 | '8b008b', '556b2f', 'ff8c00', '9932cc',
1908 | '8b0000', 'e9967a', '8fbc8f', '483d8b',
1909 | '2f4f4f', '00ced1', '9400d3', 'ff1493',
1910 | '00bfff', '696969', '1e90ff', 'b22222',
1911 | 'fffaf0', '228b22', 'ff00ff', 'dcdcdc',
1912 | 'f8f8ff', 'ffd700', 'daa520', '808080',
1913 | '008000', 'adff2f', 'f0fff0', 'ff69b4',
1914 | 'cd5c5c', '4b0082', 'fffff0', 'f0e68c',
1915 | 'e6e6fa', 'fff0f5', '7cfc00', 'fffacd',
1916 | 'add8e6', 'f08080', 'e0ffff', 'fafad2',
1917 | '90ee90', 'd3d3d3', 'ffb6c1', 'ffa07a',
1918 | '20b2aa', '87cefa', '778899', 'b0c4de',
1919 | 'ffffe0', '00ff00', '32cd32', 'faf0e6',
1920 | '800000', '66cdaa', '0000cd', 'ba55d3',
1921 | '9370db', '3cb371', '7b68ee', '00fa9a',
1922 | '48d1cc', 'c71585', '191970', 'f5fffa',
1923 | 'ffe4e1', 'ffe4b5', 'ffdead', '000080',
1924 | 'fdf5e6', '808000', '6b8e23', 'ffa500',
1925 | 'ff4500', 'da70d6', 'eee8aa', '98fb98',
1926 | 'afeeee', 'db7093', 'ffefd5', 'ffdab9',
1927 | 'cd853f', 'ffc0cb', 'dda0dd', 'b0e0e6',
1928 | '800080', 'ff0000', 'bc8f8f', '4169e1',
1929 | '8b4513', 'fa8072', 'f4a460', '2e8b57',
1930 | 'fff5ee', 'a0522d', 'c0c0c0', '87ceeb',
1931 | '6a5acd', '708090', 'fffafa', '00ff7f',
1932 | '4682b4', 'd2b48c', '008080', 'd8bfd8',
1933 | 'ff6347', '40e0d0', 'ee82ee', 'f5deb3',
1934 | 'ffffff', 'f5f5f5', 'ffff00', '9acd32'
1935 | ],
1936 | _webSwatchChars: ['0','3','6','9','c','f'],
1937 | _initWebColors: function() {
1938 | // generate long and short web color ref
1939 | var tg=Terminal.prototype.globals;
1940 | var ws=tg._webColorSwatch;
1941 | var wn=tg.webColors;
1942 | var cc=tg.webColorCodes;
1943 | var n=1;
1944 | var a, b, c, al, bl, bs, cl;
1945 | for (var i=0; i<6; i++) {
1946 | a=tg._webSwatchChars[i];
1947 | al=a+a;
1948 | for (var j=0; j<6; j++) {
1949 | b=tg._webSwatchChars[j];
1950 | bl=al+b+b;
1951 | bs=a+b;
1952 | for (var k=0; k<6; k++) {
1953 | c=tg._webSwatchChars[k];
1954 | cl=bl+c+c;
1955 | wn[bs+c]=wn[cl]=n;
1956 | cc[n]=cl;
1957 | n++;
1958 | }
1959 | }
1960 | }
1961 | },
1962 |
1963 | webifyColor: function(s) {
1964 | // return nearest web color in 3 digit format
1965 | // (do without RegExp for compatibility)
1966 | var tg=Terminal.prototype.globals;
1967 | if (s.length==6) {
1968 | var c='';
1969 | for (var i=0; i<6; i+=2) {
1970 | var a=s.charAt(i);
1971 | var b=s.charAt(i+1);
1972 | if (tg.isHexChar(a) && tg.isHexChar(b)) {
1973 | c+=tg._webSwatchChars[Math.round(parseInt(a+b,16)/255*5)];
1974 | }
1975 | else {
1976 | return '';
1977 | }
1978 | }
1979 | return c;
1980 | }
1981 | else if (s.length==3) {
1982 | var c='';
1983 | for (var i=0; i<3; i++) {
1984 | var a=s.charAt(i);
1985 | if (tg.isHexChar(a)) {
1986 | c+=tg._webSwatchChars[Math.round(parseInt(a,16)/15*5)];
1987 | }
1988 | else {
1989 | return '';
1990 | }
1991 | }
1992 | return c;
1993 | }
1994 | else {
1995 | return '';
1996 | }
1997 | },
1998 |
1999 | // public methods for color support
2000 |
2001 | setColor: function(label, value) {
2002 | var tg=Terminal.prototype.globals;
2003 | if (typeof label == 'number' && label>=1 && label<=15) {
2004 | tg.colorCodes[label]=value;
2005 | }
2006 | else if (typeof label == 'string') {
2007 | label=label.toLowerCase();
2008 | if (label.length==1 && tg.isHexChar(label)) {
2009 | var n=tg.hexToNum[label];
2010 | if (n) tg.colorCodes[n]=value;
2011 | }
2012 | else if (typeof tg.colors[label] != 'undefined') {
2013 | var n=tg.colors[label];
2014 | if (n) tg.colorCodes[n]=value;
2015 | }
2016 | }
2017 | },
2018 |
2019 | getColorString: function(label) {
2020 | var tg=Terminal.prototype.globals;
2021 | if (typeof label == 'number' && label>=0 && label<=15) {
2022 | return tg.colorCodes[label];
2023 | }
2024 | else if (typeof label == 'string') {
2025 | label=label.toLowerCase();
2026 | if (label.length==1 && tg.isHexChar(label)) {
2027 | return tg.colorCodes[tg.hexToNum[label]];
2028 | }
2029 | else if (typeof tg.colors[label] != 'undefined') {
2030 | return tg.colorCodes[tg.colors[label]];
2031 | }
2032 | }
2033 | return '';
2034 | },
2035 |
2036 | getColorCode: function(label) {
2037 | var tg=Terminal.prototype.globals;
2038 | if (typeof label == 'number' && label>=0 && label<=15) {
2039 | return label;
2040 | }
2041 | else if (typeof label == 'string') {
2042 | label=label.toLowerCase();
2043 | if (label.length==1 && tg.isHexChar(label)) {
2044 | return parseInt(label,16);
2045 | }
2046 | else if (typeof tg.colors[label] != 'undefined') {
2047 | return tg.colors[label];
2048 | }
2049 | }
2050 | return 0;
2051 | },
2052 |
2053 | // import/paste methods (methods return success)
2054 |
2055 | insertText: function(text) {
2056 | // auto-types a given string to the active terminal
2057 | // returns success (false indicates a lock or no active terminal)
2058 | var tg=Terminal.prototype.globals;
2059 | var termRef = tg.activeTerm;
2060 | if (!termRef || termRef.closed || tg.keylock || termRef.lock || termRef.charMode || termRef.fieldMode) return false;
2061 | // terminal open and unlocked, so type the text
2062 | for (var i=0; i;
2107 | // (no history entry for this)
2108 | termRef.lineBuffer = text;
2109 | termRef.lastLine = '';
2110 | termRef.inputChar = 0;
2111 | termRef.handler();
2112 | return true;
2113 | },
2114 |
2115 | // text related service functions
2116 |
2117 | normalize: function(n,m) {
2118 | var s=''+n;
2119 | while (s.length=0) {
2141 | t=t.substring(0,ofs)+s2+t.substring(ofs+l1);
2142 | ofs=t.indexOf(s1,ofs+l2);
2143 | }
2144 | return t;
2145 | },
2146 |
2147 |
2148 | // config data for text wrap
2149 |
2150 | wrapChars: {
2151 | // keys: charCode
2152 | // values: 1 = white space, 2 = wrap after, 3 = wrap before, 4 = conditional word break
2153 | 9: 1, // tab
2154 | 10: 1, // new line - don't change this (used internally)!!!
2155 | 12: 4, // form feed (use this for conditional word breaks)
2156 | 13: 1, // cr
2157 | 32: 1, // blank
2158 | 40: 3, // (
2159 | 45: 2, // dash/hyphen
2160 | 61: 2, // =
2161 | 91: 3, // [
2162 | 94: 3, // caret (non-printing chars)
2163 | 123: 3 // {
2164 | },
2165 |
2166 |
2167 | // keyboard methods & controls
2168 |
2169 | setFocus: function(termref) {
2170 | Terminal.prototype.globals.activeTerm=termref;
2171 | Terminal.prototype.globals.clearRepeatTimer();
2172 | },
2173 |
2174 | termKey: {
2175 | // codes of special keys
2176 | 'NUL': 0x00,
2177 | 'SOH': 0x01,
2178 | 'STX': 0x02,
2179 | 'ETX': 0x03,
2180 | 'EOT': 0x04,
2181 | 'ENQ': 0x05,
2182 | 'ACK': 0x06,
2183 | 'BEL': 0x07,
2184 | 'BS': 0x08,
2185 | 'BACKSPACE': 0x08,
2186 | 'HT': 0x09,
2187 | 'TAB': 0x09,
2188 | 'LF': 0x0A,
2189 | 'VT': 0x0B,
2190 | 'FF': 0x0C,
2191 | 'CR': 0x0D,
2192 | 'SO': 0x0E,
2193 | 'SI': 0x0F,
2194 | 'DLE': 0x10,
2195 | 'DC1': 0x11,
2196 | 'DC2': 0x12,
2197 | 'DC3': 0x13,
2198 | 'DC4': 0x14,
2199 | 'NAK': 0x15,
2200 | 'SYN': 0x16,
2201 | 'ETB': 0x17,
2202 | 'CAN': 0x18,
2203 | 'EM': 0x19,
2204 | 'SUB': 0x1A,
2205 | 'ESC': 0x1B,
2206 | 'IS4': 0x1C,
2207 | 'IS3': 0x1D,
2208 | 'IS2': 0x1E,
2209 | 'IS1': 0x1F,
2210 | 'DEL': 0x7F,
2211 | // other specials
2212 | 'EURO': 0x20AC,
2213 | // cursor mapping
2214 | 'LEFT': 0x1C,
2215 | 'RIGHT': 0x1D,
2216 | 'UP': 0x1E,
2217 | 'DOWN': 0x1F
2218 | },
2219 |
2220 | // map some DOM_VK_* properties to values defined in termKey
2221 | termDomKeyRef: {},
2222 | _domKeyMappingData: {
2223 | 'LEFT': 'LEFT',
2224 | 'RIGHT': 'RIGHT',
2225 | 'UP': 'UP',
2226 | 'DOWN': 'DOWN',
2227 | 'BACK_SPACE': 'BS',
2228 | 'RETURN': 'CR',
2229 | 'ENTER': 'CR',
2230 | 'ESCAPE': 'ESC',
2231 | 'DELETE': 'DEL',
2232 | 'TAB': 'TAB'
2233 | },
2234 | _initDomKeyRef: function() {
2235 | var tg=Terminal.prototype.globals;
2236 | var m=tg._domKeyMappingData;
2237 | var r=tg.termDomKeyRef;
2238 | var k=tg.termKey;
2239 | for (var i in m) r['DOM_VK_'+i]=k[m[i]];
2240 | },
2241 |
2242 | registerEvent: function(obj, eventType, handler, capture) {
2243 | if (obj.addEventListener) {
2244 | obj.addEventListener(eventType.toLowerCase(), handler, capture);
2245 | }
2246 | /*
2247 | else if (obj.attachEvent) {
2248 | obj.attachEvent('on'+eventType.toLowerCase(), handler);
2249 | }
2250 | */
2251 | else {
2252 | var et=eventType.toUpperCase();
2253 | if (window.Event && window.Event[et] && obj.captureEvents) obj.captureEvents(Event[et]);
2254 | obj['on'+eventType.toLowerCase()]=handler;
2255 | }
2256 | },
2257 | releaseEvent: function(obj, eventType, handler, capture) {
2258 | if (obj.removeEventListener) {
2259 | obj.removeEventListener(eventType.toLowerCase(), handler, capture);
2260 | }
2261 | /*
2262 | else if (obj.detachEvent) {
2263 | obj.detachEvent('on'+eventType.toLowerCase(), handler);
2264 | }
2265 | */
2266 | else {
2267 | var et=eventType.toUpperCase();
2268 | if (window.Event && window.Event[et] && obj.releaseEvents) obj.releaseEvents(Event[et]);
2269 | et='on'+eventType.toLowerCase();
2270 | if (obj[et] && obj[et]==handler) obj.et=null;
2271 | }
2272 | },
2273 |
2274 | enableKeyboard: function(term) {
2275 | var tg=Terminal.prototype.globals;
2276 | if (!tg.kbdEnabled) {
2277 | tg.registerEvent(document, 'keypress', tg.keyHandler, true);
2278 | tg.registerEvent(document, 'keydown', tg.keyFix, true);
2279 | tg.registerEvent(document, 'keyup', tg.clearRepeatTimer, true);
2280 | tg.kbdEnabled=true;
2281 | }
2282 | tg.activeTerm=term;
2283 | },
2284 |
2285 | disableKeyboard: function(term) {
2286 | var tg=Terminal.prototype.globals;
2287 | if (tg.kbdEnabled) {
2288 | tg.releaseEvent(document, 'keypress', tg.keyHandler, true);
2289 | tg.releaseEvent(document, 'keydown', tg.keyFix, true);
2290 | tg.releaseEvent(document, 'keyup', tg.clearRepeatTimer, true);
2291 | tg.kbdEnabled=false;
2292 | }
2293 | tg.activeTerm=null;
2294 | },
2295 |
2296 | // remap some special key mappings on keydown
2297 |
2298 | keyFix: function(e) {
2299 | var tg=Terminal.prototype.globals;
2300 | var term=tg.activeTerm;
2301 | var ch;
2302 | if (tg.keylock || term.lock) return true;
2303 | if (window.event) {
2304 | if (!e) e=window.event;
2305 | ch=e.keyCode;
2306 | if (e.DOM_VK_UP) {
2307 | for (var i in tg.termDomKeyRef) {
2308 | if (e[i] && ch == e[i]) {
2309 | tg.keyHandler({which:tg.termDomKeyRef[i],_remapped:true,_repeat:(ch==0x1B)? true:false});
2310 | if (e.preventDefault) e.preventDefault();
2311 | if (e.stopPropagation) e.stopPropagation();
2312 | e.cancelBubble=true;
2313 | return false;
2314 | }
2315 | }
2316 | e.cancelBubble=false;
2317 | return true;
2318 | }
2319 | else {
2320 | // no DOM support
2321 | var termKey=term.termKey;
2322 | var keyHandler=tg.keyHandler;
2323 | if (ch==8 && !term.isOpera) { keyHandler({which:termKey.BS,_remapped:true,_repeat:true}); }
2324 | else if (ch==9) { keyHandler({which:termKey.TAB,_remapped:true,_repeat: (term.printTab)? false:true}); }
2325 | else if (ch==27) { keyHandler({which:termKey.ESC,_remapped:true,_repeat: (term.printTab)? false:true}); }
2326 | else if (ch==37) { keyHandler({which:termKey.LEFT,_remapped:true,_repeat:true}); }
2327 | else if (ch==39) { keyHandler({which:termKey.RIGHT,_remapped:true,_repeat:true}); }
2328 | else if (ch==38) { keyHandler({which:termKey.UP,_remapped:true,_repeat:true}); }
2329 | else if (ch==40) { keyHandler({which:termKey.DOWN,_remapped:true,_repeat:true}); }
2330 | else if (ch==127 || ch==46) { keyHandler({which:termKey.DEL,_remapped:true,_repeat:true}); }
2331 | else if (ch>=57373 && ch<=57376) {
2332 | if (ch==57373) { keyHandler({which:termKey.UP,_remapped:true,_repeat:true}); }
2333 | else if (ch==57374) { keyHandler({which:termKey.DOWN,_remapped:true,_repeat:true}); }
2334 | else if (ch==57375) { keyHandler({which:termKey.LEFT,_remapped:true,_repeat:true}); }
2335 | else if (ch==57376) { keyHandler({which:termKey.RIGHT,_remapped:true,_repeat:true}); }
2336 | }
2337 | else {
2338 | e.cancelBubble=false;
2339 | return true;
2340 | }
2341 | if (e.preventDefault) e.preventDefault();
2342 | if (e.stopPropagation) e.stopPropagation();
2343 | e.cancelBubble=true;
2344 | return false;
2345 | }
2346 | }
2347 | },
2348 |
2349 | clearRepeatTimer: function(e) {
2350 | var tg=Terminal.prototype.globals;
2351 | if (tg.keyRepeatTimer) {
2352 | clearTimeout(tg.keyRepeatTimer);
2353 | tg.keyRepeatTimer=null;
2354 | }
2355 | },
2356 |
2357 | doKeyRepeat: function(ch) {
2358 | Terminal.prototype.globals.keyHandler({which:ch,_remapped:true,_repeated:true})
2359 | },
2360 |
2361 | keyHandler: function(e) {
2362 | var tg=Terminal.prototype.globals;
2363 | var term=tg.activeTerm;
2364 | if (tg.keylock || term.lock || term.isMac && e && e.metaKey) return true;
2365 | if (window.event) {
2366 | if (window.event.preventDefault) window.event.preventDefault();
2367 | if (window.event.stopPropagation) window.event.stopPropagation();
2368 | }
2369 | else if (e) {
2370 | if (e.preventDefault) e.preventDefault();
2371 | if (e.stopPropagation) e.stopPropagation();
2372 | }
2373 | var ch;
2374 | var ctrl=false;
2375 | var shft=false;
2376 | var remapped=false;
2377 | var termKey=term.termKey;
2378 | var keyRepeat=0;
2379 | if (e) {
2380 | ch=e.which;
2381 | ctrl=((e.ctrlKey && !e.altKey) || e.modifiers==2);
2382 | shft=(e.shiftKey || e.modifiers==4);
2383 | if (e._remapped) {
2384 | remapped=true;
2385 | if (window.event) {
2386 | //ctrl=(ctrl || window.event.ctrlKey);
2387 | ctrl=(ctrl || (window.event.ctrlKey && !window.event.altKey));
2388 | shft=(shft || window.event.shiftKey);
2389 | }
2390 | }
2391 | if (e._repeated) {
2392 | keyRepeat=2;
2393 | }
2394 | else if (e._repeat) {
2395 | keyRepeat=1;
2396 | }
2397 | }
2398 | else if (window.event) {
2399 | ch=window.event.keyCode;
2400 | //ctrl=(window.event.ctrlKey);
2401 | ctrl=(window.event.ctrlKey && !window.event.altKey); // allow alt gr == ctrl alt
2402 | shft=(window.event.shiftKey);
2403 | if (window.event._repeated) {
2404 | keyRepeat=2;
2405 | }
2406 | else if (window.event._repeat) {
2407 | keyRepeat=1;
2408 | }
2409 | }
2410 | else {
2411 | return true;
2412 | }
2413 | if (ch=='' && remapped==false) {
2414 | // map specials
2415 | if (e==null) e=window.event;
2416 | if (e.charCode==0 && e.keyCode) {
2417 | if (e.DOM_VK_UP) {
2418 | var dkr=tg.termDomKeyRef;
2419 | for (var i in dkr) {
2420 | if (e[i] && e.keyCode == e[i]) {
2421 | ch=dkr[i];
2422 | break;
2423 | }
2424 | }
2425 | }
2426 | else {
2427 | // NS4
2428 | if (e.keyCode==28) { ch=termKey.LEFT; }
2429 | else if (e.keyCode==29) { ch=termKey.RIGHT; }
2430 | else if (e.keyCode==30) { ch=termKey.UP; }
2431 | else if (e.keyCode==31) { ch=termKey.DOWN; }
2432 | // Mozilla alike but no DOM support
2433 | else if (e.keyCode==37) { ch=termKey.LEFT; }
2434 | else if (e.keyCode==39) { ch=termKey.RIGHT; }
2435 | else if (e.keyCode==38) { ch=termKey.UP; }
2436 | else if (e.keyCode==40) { ch=termKey.DOWN; }
2437 | // just to have the TAB mapping here too
2438 | else if (e.keyCode==9) { ch=termKey.TAB; }
2439 | }
2440 | }
2441 | }
2442 | // leave on unicode private use area (might be function key etc)
2443 | if ((ch>=0xE000) && (ch<= 0xF8FF)) return;
2444 | if (keyRepeat) {
2445 | tg.clearRepeatTimer();
2446 | tg.keyRepeatTimer = window.setTimeout(
2447 | 'Terminal.prototype.globals.doKeyRepeat('+ch+')',
2448 | (keyRepeat==1)? tg.keyRepeatDelay1:tg.keyRepeatDelay2
2449 | );
2450 | }
2451 | // key actions
2452 | if (term.charMode) {
2453 | term.insert=false;
2454 | term.inputChar=ch;
2455 | term.lineBuffer='';
2456 | term.handler();
2457 | if (ch<=32 && window.event) window.event.cancelBubble=true;
2458 | return false;
2459 | }
2460 | if (!ctrl) {
2461 | // special keys
2462 | if (ch==termKey.CR) {
2463 | term.lock=true;
2464 | term.cursorOff();
2465 | term.insert=false;
2466 | if (term.rawMode) {
2467 | term.lineBuffer=term.lastLine;
2468 | }
2469 | else if (term.fieldMode) {
2470 | term.lineBuffer=term.lastLine;
2471 | term.exitFieldMode();
2472 | }
2473 | else {
2474 | term.lineBuffer=term._getLine(true);
2475 | if (
2476 | term.lineBuffer!='' &&
2477 | (!term.historyUnique || term.history.length==0 ||
2478 | term.lineBuffer!=term.history[term.history.length-1])
2479 | ) {
2480 | term.history[term.history.length]=term.lineBuffer;
2481 | }
2482 | term.histPtr=term.history.length;
2483 | }
2484 | term.lastLine='';
2485 | term.inputChar=0;
2486 | term.handler();
2487 | if (window.event) window.event.cancelBubble=true;
2488 | return false;
2489 | }
2490 | else if (term.fieldMode) {
2491 | if (ch==termKey.ESC) {
2492 | term.lineBuffer=term.lastLine='';
2493 | term.exitFieldMode();
2494 | term.lastLine='';
2495 | term.inputChar=0;
2496 | term.handler();
2497 | if (window.event) window.event.cancelBubble=true;
2498 | return false;
2499 | }
2500 | else if (ch==termKey.LEFT) {
2501 | if (term.fieldC>0) term.fieldC--;
2502 | }
2503 | else if (ch==termKey.RIGHT) {
2504 | if (term.fieldC0) {
2508 | term.lastLine=term.lastLine.substring(0,term.fieldC-1)+term.lastLine.substring(term.fieldC);
2509 | term.fieldC--;
2510 | }
2511 | }
2512 | else if (ch==termKey.DEL) {
2513 | if (term.fieldC=32) {
2518 | term.lastLine=term.lastLine.substring(0,term.fieldC)+String.fromCharCode(ch)+term.lastLine.substring(term.fieldC);
2519 | term.fieldC++;
2520 | }
2521 | term.drawField();
2522 | return false;
2523 | }
2524 | else if (ch==termKey.ESC && term.conf.closeOnESC) {
2525 | term.close();
2526 | if (window.event) window.event.cancelBubble=true;
2527 | return false;
2528 | }
2529 | if (ch<32 && term.rawMode) {
2530 | if (window.event) window.event.cancelBubble=true;
2531 | return false;
2532 | }
2533 | else {
2534 | if (ch==termKey.LEFT) {
2535 | term.cursorLeft();
2536 | if (window.event) window.event.cancelBubble=true;
2537 | return false;
2538 | }
2539 | else if (ch==termKey.RIGHT) {
2540 | term.cursorRight();
2541 | if (window.event) window.event.cancelBubble=true;
2542 | return false;
2543 | }
2544 | else if (ch==termKey.UP) {
2545 | term.cursorOff();
2546 | if (term.histPtr==term.history.length) term.lastLine=term._getLine();
2547 | term._clearLine();
2548 | if (term.history.length && term.histPtr>=0) {
2549 | if (term.histPtr>0) term.histPtr--;
2550 | term.type(term.history[term.histPtr]);
2551 | }
2552 | else if (term.lastLine) {
2553 | term.type(term.lastLine);
2554 | }
2555 | term.cursorOn();
2556 | if (window.event) window.event.cancelBubble=true;
2557 | return false;
2558 | }
2559 | else if (ch==termKey.DOWN) {
2560 | term.cursorOff();
2561 | if (term.histPtr==term.history.length) term.lastLine=term._getLine();
2562 | term._clearLine();
2563 | if (term.history.length && term.histPtr<=term.history.length) {
2564 | if (term.histPtr=65 && ch<=96) || ch==63) {
2617 | // remap canonical
2618 | if (ch==63) {
2619 | ch=31;
2620 | }
2621 | else {
2622 | ch-=64;
2623 | }
2624 | }
2625 | term.inputChar=ch;
2626 | term.ctrlHandler();
2627 | if (window.event) window.event.cancelBubble=true;
2628 | return false;
2629 | }
2630 | else if (ctrl || !term.isPrintable(ch,true)) {
2631 | if (window.event) window.event.cancelBubble=true;
2632 | return false;
2633 | }
2634 | else if (term.isPrintable(ch,true)) {
2635 | if (term.blinkTimer) clearTimeout(term.blinkTimer);
2636 | if (term.insert) {
2637 | term.cursorOff();
2638 | term._scrollRight(term.r,term.c);
2639 | }
2640 | term._charOut(ch);
2641 | term.cursorOn();
2642 | if (ch==32 && window.event) {
2643 | window.event.cancelBubble=true;
2644 | }
2645 | else if (window.opera && window.event) {
2646 | window.event.cancelBubble=true;
2647 | }
2648 | return false;
2649 | }
2650 | }
2651 | return true;
2652 | },
2653 |
2654 |
2655 | // gui mappings
2656 |
2657 | hasSubDivs: false,
2658 | termStringStart: '',
2659 | termStringEnd: '',
2660 |
2661 | termSpecials: {
2662 | // special HTML escapes
2663 | 0: ' ',
2664 | 1: ' ',
2665 | 9: ' ',
2666 | 32: ' ',
2667 | 34: '"',
2668 | 38: '&',
2669 | 60: '<',
2670 | 62: '>',
2671 | 127: '◊',
2672 | 0x20AC: '€'
2673 | },
2674 |
2675 | // extensive list of max 8 styles (2^n, n<16)
2676 | termStyles: [1,2,4,8, 16],
2677 | // style markup: one letter keys, reserved keys: "p" (plain), "c" (color)
2678 | termStyleMarkup: {
2679 | 'r': 1,
2680 | 'u': 2,
2681 | 'i': 4,
2682 | 's': 8,
2683 | 'b': 16 // map "b" to 16 (italics) for ANSI mapping
2684 | },
2685 | // mappings for styles (heading HTML)
2686 | termStyleOpen: {
2687 | 1: '',
2688 | 2: '',
2689 | 4: '',
2690 | 8: '',
2691 | 16: ''
2692 | },
2693 | // mapping for styles (trailing HTML)
2694 | termStyleClose: {
2695 | 1: '<\/span>',
2696 | 2: '<\/u>',
2697 | 4: '<\/i>',
2698 | 8: '<\/strike>',
2699 | 16: ''
2700 | },
2701 |
2702 | // method to install custom styles
2703 | assignStyle: function(styleCode, markup, htmlOpen, htmlClose) {
2704 | var tg=Terminal.prototype.globals;
2705 | // check params
2706 | if (!styleCode || isNaN(styleCode)) {
2707 | if (styleCode>=256) {
2708 | alert('termlib.js:\nCould not assign style.\n'+s+' is not a valid power of 2 between 0 and 256.');
2709 | return;
2710 | }
2711 | }
2712 | var s=styleCode&0xff;
2713 | var matched=false;
2714 | for (var i=0; i<8; i++) {
2715 | if ((s>>>i)&1) {
2716 | if (matched) {
2717 | alert('termlib.js:\nCould not assign style code.\n'+s+' is not a power of 2!');
2718 | return;
2719 | }
2720 | matched=true;
2721 | }
2722 | }
2723 | if (!matched) {
2724 | alert('termlib.js:\nCould not assign style code.\n'+s+' is not a valid power of 2 between 0 and 256.');
2725 | return;
2726 | }
2727 | markup=String(markup).toLowerCase();
2728 | if (markup=='c' || markup=='p') {
2729 | alert('termlib.js:\nCould not assign mark up.\n"'+markup+'" is a reserved code.');
2730 | return;
2731 | }
2732 | if (markup.length>1) {
2733 | alert('termlib.js:\nCould not assign mark up.\n"'+markup+'" is not a single letter code.');
2734 | return;
2735 | }
2736 | var exists=false;
2737 | for (var i=0; i=32) {
2899 | var cs=unescape("%"+high+low);
2900 | termString_keyref[cc]=cs;
2901 | termString_keycoderef[cs]=cc;
2902 | }
2903 | }
2904 | }
2905 | },
2906 |
2907 | _extendMissingStringMethods: function() {
2908 | if (!String.fromCharCode || !String.prototype.charCodeAt) {
2909 | Terminal.prototype.globals._termString_makeKeyref();
2910 | }
2911 | if (!String.fromCharCode) {
2912 | String.fromCharCode=function(cc) {
2913 | return (cc!=null)? Terminal.prototype.globals.termString_keyref[cc] : '';
2914 | };
2915 | }
2916 | if (!String.prototype.charCodeAt) {
2917 | String.prototype.charCodeAt=function(n) {
2918 | cs=this.charAt(n);
2919 | return (Terminal.prototype.globals.termString_keycoderef[cs])?
2920 | Terminal.prototype.globals.termString_keycoderef[cs] : 0;
2921 | };
2922 | }
2923 | }
2924 |
2925 | // end of Terminal.prototype.globals
2926 | }
2927 |
2928 | // end of Terminal.prototype
2929 | }
2930 |
2931 | // initialize global data
2932 | Terminal.prototype.globals._initGlobals();
2933 |
2934 | // global entities for backward compatibility with termlib 1.x applications
2935 | var TerminalDefaults = Terminal.prototype.Defaults;
2936 | var termDefaultHandler = Terminal.prototype.defaultHandler;
2937 | var TermGlobals = Terminal.prototype.globals;
2938 | var termKey = Terminal.prototype.globals.termKey;
2939 | var termDomKeyRef = Terminal.prototype.globals.termDomKeyRef;
2940 |
2941 |
2942 | /*
2943 | === termlib.js Socket Extension v.1.02 ===
2944 |
2945 | (c) Norbert Landsteiner 2003-2007
2946 | mass:werk - media environments
2947 |
2948 |
2949 | # Synopsis:
2950 | Integrates async XMLHttpRequests (AJAX/JSON) tightly into termlib.js
2951 |
2952 | # Example:
2953 |
2954 | myTerm = new Terminal( { handler: myTermHandler } );
2955 | myTerm.open();
2956 |
2957 | function myTermHandler() {
2958 | this.newLine();
2959 | if (this.lineBuffer == 'get file') {
2960 | myTerm.send(
2961 | {
2962 | url: 'myservice',
2963 | data: {
2964 | book: 'theBook',
2965 | chapter: 7,
2966 | page: 45
2967 | },
2968 | callback: myCallback
2969 | }
2970 | );
2971 | return;
2972 | }
2973 | else {
2974 | // ...
2975 | }
2976 | this.prompt();
2977 | }
2978 |
2979 | function myCallback() {
2980 | if (this.socket.success) {
2981 | this.write(this.socket.responseText);
2982 | }
2983 | else {
2984 | this.write('OOPS: ' + this.socket.status + ' ' + this.socket.statusText);
2985 | if (this.socket.errno) {
2986 | this.newLine();
2987 | this.write('Error: ' + this.socket.errstring);
2988 | }
2989 | }
2990 | this.prompt();
2991 | }
2992 |
2993 |
2994 | # Documentation:
2995 |
2996 | for usage and description see readme.txt chapter 13:
2997 |
2998 |
2999 | or refer to the sample page:
3000 |
3001 |
3002 | */
3003 |
3004 | Terminal.prototype._HttpSocket = function() {
3005 | var req=null;
3006 | if (window.XMLHttpRequest) {
3007 | try {
3008 | req=new XMLHttpRequest();
3009 | }
3010 | catch(e) {}
3011 | }
3012 | else if (window.ActiveXObject) {
3013 | var prtcls=this._msXMLHttpObjects;
3014 | for (var i=0; i1) this.prototype._msXMLHttpObjects= [ prtcls[i] ];
3020 | break;
3021 | }
3022 | }
3023 | catch(e) {}
3024 | }
3025 | }
3026 | this.request=req;
3027 | this.url;
3028 | this.data=null;
3029 | this.query='';
3030 | this.timeoutTimer=null;
3031 | this.localMode=Boolean(window.location.href.search(/^file:/i)==0);
3032 | this.error=0;
3033 | }
3034 |
3035 | Terminal.prototype._HttpSocket.prototype = {
3036 | version: '1.02',
3037 | // config
3038 | useXMLEncoding: false, // use ";" as separator if true, "&" else
3039 | defaulTimeout: 10000, // request timeout in ticks (milliseconds)
3040 | defaultMethod: 'GET',
3041 | forceNewline: true, // translate line-breaks in responseText to newlines
3042 |
3043 | // static const
3044 | errno: {
3045 | OK: 0,
3046 | NOTIMPLEMENTED: 1,
3047 | FATALERROR: 2,
3048 | TIMEOUT: 3,
3049 | NETWORKERROR: 4,
3050 | LOCALFILEERROR: 5
3051 | },
3052 | errstring: [
3053 | '',
3054 | 'XMLHttpRequest not implemented.',
3055 | 'Could not open XMLHttpRequest.',
3056 | 'The connection timed out.',
3057 | 'Network error.',
3058 | 'The requested local document was not found.'
3059 | ],
3060 |
3061 | // private static data
3062 | _msXMLHttpObjects: [
3063 | 'Msxml2.XMLHTTP',
3064 | 'Microsoft.XMLHTTP',
3065 | 'Msxml2.XMLHTTP.5.0',
3066 | 'Msxml2.XMLHTTP.4.0',
3067 | 'Msxml2.XMLHTTP.3.0'
3068 | ],
3069 |
3070 | // internal methods
3071 | serializeData: function() {
3072 | this.query=this.serialize(this.data);
3073 | },
3074 | serialize: function(data) {
3075 | var v='';
3076 | if( data != null ) {
3077 | switch (typeof data) {
3078 | case 'object':
3079 | var d=[];
3080 | if (data instanceof Array) {
3081 | // array
3082 | for (var i=0; i= 200 && r.status < 300) {
3167 | success=true;
3168 | }
3169 | else if (r.status >= 12000) {
3170 | // MSIE network error
3171 | failed=true;
3172 | this.error=this.errno.NETWORKERROR;
3173 | }
3174 | }
3175 | }
3176 | }
3177 | catch(e) {}
3178 | if (!failed) {
3179 | response.status=r.status;
3180 | response.statusText= (r.status==404)? 'Not Found':r.statusText; // force correct header
3181 | response.responseText=r.responseText;
3182 | response.responseXML=r.responseXML;
3183 | if (this.getHeaders) {
3184 | if (this.getHeaders instanceof Array) {
3185 | for (var i=0; i
6 |
7 |
8 |
9 |
10 | ### COMPATIBILITY WARNING ###
11 |
12 | Dropped support of Netscape 4 (layers) with version 1.5!
13 | Netscape 4 is now outdated for more than 10 years. Any further support of this browser
14 | would be of academic nature. As a benefit this step allows us to include the socket
15 | extension in the main library, so there are no additional files to load anymore.
16 |
17 |
18 | For the first time there is a backward compatibility issue from version 1.3 to version 1.4:
19 | The following applies to the style vector for the `type()' method while using colors:
20 |
21 | while with version 1.3 a color was encoded using the color code times 16 (0xf), e.g.:
22 |
23 | myTerm.type( 'This is red.', 2*16 );
24 |
25 | this changed with version 1.4 to the color code times 256 (0xff), e.g.:
26 |
27 | myTerm.type( 'This is red.', 2*256 );
28 |
29 |
30 | All other style encodings or color API remain unchanged.
31 | Since this feature was only introduced in version 1.3 and there are no known applications
32 | that would use a statement like the above (since you would usually use the `write()' method
33 | for complex output), this seems to be good bargain for some codes for custom styles.
34 | C.f.: sect 7.5 "TermGlobals.assignStyle()"
35 |
36 |
37 | ### Mac OS X Dead-Keys ###
38 |
39 | (Dead-keys: combinations of accents and characters that are built by two consecutively pressed keys.)
40 | Mac OS X 10.5 and later doesn't fire a keyboard event for dead keys anymore.
41 | It's possible to fix this for Safari by a custom dead keys emulation, but not for Chrome or Firefox.
42 | "termlib.js" provides automatic translations of common dead-keys for Safari in German (de-de).
43 | In case you would need dead-keys for another language, please contact me via http://www.masswerk.at/.
44 |
45 |
46 |
47 | Contents:
48 |
49 | 1 About
50 | 2 Creating a new Terminal Instance
51 | 2.1 Configuration Values
52 | 3 Using the Terminal
53 | 3.1 The Default Handler
54 | 3.2 Input Modes
55 | 3.2.1 Normal Line Input (Command Line Mode)
56 | 3.2.1.2 Special Keys (ctrlHandler)
57 | 3.2.2 Raw Mode
58 | 3.2.3 Character Mode
59 | 3.3 Other Handlers
60 | 3.3.1 initHandler
61 | 3.3.2 exitHandler
62 | 3.4 Flags for Behaviour Control
63 | 4 Output Methods
64 | 4.1 Terminal.type()
65 | 4.2 Terminal.write()
66 | 4.3 Terminal.typeAt()
67 | 4.4 Terminal.setChar()
68 | 4.5 Terminal.newLine()
69 | 4.6 Terminal.clear()
70 | 4.7 Terminal.statusLine()
71 | 4.8 Terminal.printRowFromString()
72 | 4.9 Terminal.redraw()
73 | 4.10 Using Color
74 | 4.11 Text Wrap - Terminal.wrapOn(), Terminal.wrapOff()
75 | 4.12 ANSI Support
76 | 5 Cursor Methods and Editing
77 | 5.1 Terminal.cursorOn()
78 | 5.2 Terminal.cursorOff()
79 | 5.3 Terminal.cursorSet()
80 | 5.4 Terminal.cursorLeft()
81 | 5.5 Terminal.cursorRight()
82 | 5.6 Terminal.backspace()
83 | 5.7 Terminal.fwdDelete()
84 | 5.8 Terminal.isPrintable()
85 | 6 Other Methods of the Terminal Object
86 | 6.1 Terminal.prompt()
87 | 6.2 Terminal.reset()
88 | 6.3 Terminal.open()
89 | 6.4 Terminal.close()
90 | 6.5 Terminal.focus()
91 | 6.6 Terminal.moveTo()
92 | 6.7 Terminal.resizeTo()
93 | 6.8 Terminal.getDimensions()
94 | 6.9 Terminal.rebuild()
95 | 6.10 Terminal.backupScreen()
96 | 6.11 Terminal.restoreScreen()
97 | 6.12 Terminal.swapBackup()
98 | 6.13 Terminal.setTextColor()
99 | 6.14 Terminal.setTextBlur()
100 | 7 Global Static Methods (TermGlobals)
101 | 7.1 TermGlobals.setFocus()
102 | 7.2 TermGlobals.keylock (Global Locking Flag)
103 | 7.3 TermGlobals Text Methods
104 | 7.3.1 TermGlobals.normalize()
105 | 7.3.2 TermGlobals.fillLeft()
106 | 7.3.3 TermGlobals.center()
107 | 7.3.4 TermGlobals.stringReplace()
108 | 7.4 TermGlobals Import Methods
109 | 7.4.1 TermGlobals.insertText()
110 | 7.4.2 TermGlobals.importEachLine()
111 | 7.4.3 TermGlobals.importMultiLine()
112 | 7.5 TermGlobals.assignStyle()
113 | 8 Localization
114 | 9 The Socket Extension (Remote Communication)
115 | 9.1 A First Example
116 | 9.2 The send() API
117 | 9.3 Global Config Settings
118 | 9.4 The Callback (Response Handling)
119 | 9.5 Error Codes
120 | 9.6 Note on Compatibly / Browser Requirements
121 | 9.7 termlib_socket.js Version History
122 | 10 Cross Browser Functions
123 | 11 Architecture, Internals
124 | 11.1 Global Entities
125 | 11.2 I/O Architecture
126 | 11.3 Compatibility
127 | 12 History
128 | 13 Example for a Command Line Parser
129 | 14 License
130 | 15 Disclaimer
131 | 16 Donations
132 | 17 References
133 |
134 |
135 |
136 |
137 | 1 About
138 |
139 | The Terminal library "termlib.js" provides an object oriented constructor and control
140 | methods for a terminal-like DHTML interface.
141 |
142 | "termlib.js" features direct keyboard input and powerful output methods for multiple
143 | instances of the `Terminal' object (including focus control).
144 | "termlib.js" also comprises methods for a transparent handling of client-server com-
145 | munications via XMLHttpRequests (see sect. 9 "The Socket Extension").
146 |
147 | The library was written with the aim of simple usage and a maximum of compatibility with
148 | minimal foot print in the global namespace.
149 |
150 |
151 | A simple example:
152 |
153 | // creating a terminal and using it
154 |
155 | var term = new Terminal( {handler: termHandler} );
156 | term.open();
157 |
158 | function termHandler() {
159 | var line = this.lineBuffer;
160 | this.newLine();
161 | if (line == "help") {
162 | this.write(helpPage)
163 | }
164 | else if (line == "exit") {
165 | this.close();
166 | return;
167 | }
168 | else if (line != "") {
169 | this.write("You typed: "+line);
170 | }
171 | this.prompt();
172 | }
173 |
174 | var helpPage = [
175 | "This is the monstrous help page for my groovy terminal.",
176 | "Commands available:",
177 | " help ... print this monstrous help page",
178 | " exit ... leave this groovy terminal",
179 | " ",
180 | "Have fun!"
181 | ];
182 |
183 |
184 | You should provide CSS font definitions for the classes ".term" (normal video) and
185 | ".termReverse" (reverse video) in a monospaced font.
186 | A sample stylesheet "term_styles.css" comes with this library.
187 |
188 | See the sample application "multiterm_test.html" for a demo of multiple terminals.
189 |
190 | v.1.01: If you configure to use another font class (see 2.1 Configuration Values),
191 | you must provide a subclass ".termReverse" for reversed video.
192 |
193 | p.e.: .myFontClass .termReverse {
194 | /* your definitions for reverse video here */
195 | }
196 |
197 | With the addition of `conf.fontClass' you can now create multiple
198 | instances with independend appearences.
199 |
200 |
201 |
202 |
203 | 2 Creating a new Terminal Instance
204 |
205 | Use the `new' constructor to create a new instance of the Terminal object. You will want
206 | to supply a configuration object as an argument to the constructor. If the `new'
207 | constructor is called without an object as its first argument, default values are used.
208 |
209 | p.e.:
210 |
211 | // creating a new instance of Terminal
212 |
213 | var conf= {
214 | x: 100,
215 | y: 100,
216 | cols: 80,
217 | rows: 24
218 | }
219 |
220 | var term = new Term(conf);
221 | term.open();
222 |
223 | `Terminal.open()' initializes the terminal and makes it visible to the user.
224 | This is handled in by separate method to allow the re-initilization of instances
225 | previously closed.
226 |
227 | NOTE:
228 | The division or HTML-element that holds the terminal must be present when calling
229 | `Terminal.open()'. So you must not call this method from the header of a HTML-document at
230 | compile time.
231 |
232 |
233 |
234 | 2.1 Configuration Values
235 |
236 | Set any of these values in your configuration object to override:
237 |
238 |
239 | LABEL DEFAULT VALUE COMMENT
240 |
241 | x 100 terminal's position x in px
242 | y 100 terminal's position y in px
243 | divDiv 'termDiv' id of terminals CSS division
244 | bgColor '#181818' background color (HTML hex value)
245 | frameColor '#555555' frame color (HTML hex value)
246 | frameWidth 1 frame border width in px
247 | fontClass 'term' class name of CSS font definition to use
248 | cols 80 number of cols per row
249 | rows 24 number of rows
250 | rowHeight 15 a row's line-height in px
251 | blinkDelay 500 delay for cursor blinking in milliseconds
252 | crsrBlinkMode false true for blinking cursor
253 | crsrBlockMode true true for block-cursor else underscore
254 | DELisBS false handle as
255 | printTab true handle as printable (prints as space)
256 | printEuro true handle unicode 0x20AC (Euro sign) as printable
257 | catchCtrlH true handle ^H as
258 | closeOnESC true close terminal on
259 | historyUnique false prevent consecutive and identical entries in history
260 | id 0 terminal id
261 | ps '>' prompt string
262 | greeting '%+r Terminal ready. %-r' string for greeting if no initHandler is used
263 | handler defaultHandler reference to handler for command interpretation
264 | ctrlHandler null reference to handler called on uncatched special keys
265 | initHandler null reference to handler called at end of init()
266 | exitHandler null reference to handler called on close()
267 | wrapping false text wrapping for `write()' on/off
268 | mapANSI false enable mapping of ANSI escape sequences (SGR only)
269 | ANSItrueBlack false force ANSI 30m to be rendered as black (default: fg color)
270 | textColor '' String, default text color (color 0), overrides any CSS rules
271 | textBlur 0 Number, if set, adds a CSS text-shadow with the given number of px
272 | ("text-shadow: 0 0 px "), use this with textColor
273 |
274 |
275 | At least you will want to specify `handler' to implement your own command parser.
276 |
277 | Note: While `id' is not used by the Termninal object, it provides an easy way to identify
278 | multiple terminals by the use of "this.id". (e.g.: "if (this.id == 1) startupterm = true;")
279 |
280 | p.e.:
281 |
282 | // creating two individual Terminal instances
283 |
284 | var term1 = new Terminal(
285 | {
286 | id: 1,
287 | x: 200,
288 | y: 10,
289 | cols: 80,
290 | rows: 12,
291 | greeting: "*** This is Terminal 1 ***",
292 | handler: myTerminalHandler
293 | }
294 | );
295 | term1.open();
296 |
297 | var term2 = new Terminal(
298 | {
299 | id: 2,
300 | x, 200,
301 | y: 220,
302 | cols: 80
303 | rows: 12,
304 | greeting: "*** This is Terminal 2 ***",
305 | handler: myTerminalHandler
306 | }
307 | );
308 | term2.open();
309 |
310 |
311 |
312 |
313 | 3 Using the Terminal
314 |
315 | There are 4 different handlers that are called by a Terminal instance to process input and
316 | some flags to control the input mode and behaviour.
317 |
318 |
319 |
320 | 3.1 The Default Handler (a simlple example for input handling)
321 |
322 | If no handlers are defined in the configuration object, a default handler is called to
323 | handle a line of user input. The default command line handler `defaultHandler' just
324 | closes the command line with a new line and echos the input back to the user:
325 |
326 | function termDefaultHandler() {
327 | this.newLine();
328 | if (this.lineBuffer != '') {
329 | this.type('You typed: '+this.lineBuffer);
330 | this.newLine();
331 | }
332 | this.prompt();
333 | }
334 |
335 | // Note: This used to be top level function. With version 1.4 `termDefaultHandler' became
336 | // a reference to the method `Terminal.prototype.defaultHandler'.
337 |
338 | First you may note that the instance is refered to as `this'. So you need not worry about
339 | which Terminal instance is calling your handler. As the handler is entered, the terminal
340 | is locked for user input and the cursor is off. The current input is available as a string
341 | value in `this.lineBuffer'.
342 |
343 | The method `type()' just does what it says and types a string at the current cursor
344 | position to the terminal screen.
345 |
346 | `newLine()' moves the cursor to a new line.
347 |
348 | The method `prompt()' adds a new line if the cursor isn't at the start of a line, outputs
349 | the prompt string (as specified in the configuration), activates the cursor, and unlocks
350 | the terminal for further input. While you're doing normal command line processing, always
351 | call `prompt()' when leaving your handler.
352 |
353 | In fact this is all you need to create your own terminal application. Please see at least
354 | the method `write()' for a more powerful output method.
355 |
356 | Below we will refer to all methods of the Terminal object as `Terminal.()'.
357 | You can call them as `this.()' in a handler or as methods of your named instance
358 | in other context (e.g.: "myTerminal.close()").
359 |
360 | [In technical terms these methods are methods of the Terminal's prototype object, while
361 | the properties are properties of a Termninal instance. Since this doesn't make any
362 | difference to your script, we'll refer to both as `Terminal.'.]
363 |
364 |
365 |
366 | 3.2 Input Modes
367 |
368 | 3.2.1 Normal Line Input (Command Line Mode)
369 |
370 | By default the terminal is in normal input mode. Any printable characters in the range of
371 | ASCII 0x20 - 0xff are echoed to the terminal and may be edited with the use of the cursor
372 | keys and the key.
373 | The cursor keys UP and DOWN let the user browse in the command line history (the list of
374 | all commands issued previously in this Terminal instance).
375 |
376 | If the user presses or , the line is read from the terminal buffer, converted
377 | to a string, and placed in `Terminal.lineBuffer' (-> `this.lineBuffer') for further use.
378 | The terminal is then locked for further input and the specified handler
379 | (`Terminal.handler') is called.
380 |
381 |
382 | 3.2.1.2 Special Keys (ctrlHandler)
383 |
384 | If a special character (ASCII<0x20) or an according combination of and a key is
385 | pressed, which is not caught for editing or "enter", and a handler for `ctrlHandler' is
386 | specified, this handler is called.
387 | The ASCII value of the special character is available in `Terminal.inputChar'. Please note
388 | that the terminal is neither locked, nor is the cursor off - all further actions have to
389 | be controlled by `ctrlHandler'. (The tracking of - combinations as "^C" usually
390 | works but cannot be taken for granted.)
391 |
392 | A named reference of the special control values in POSIX form (as well as the values of
393 | the cursor keys [LEFT, RIGHT, UP, DOWN]) is available in the `termKey' object.
394 |
395 | Note:
396 | With version 1.4 `termKey' is a reference to `Terminal.prototype.globals.termKey'.
397 | This object is also mapped to `Terminal.prototype.termKey', so you may also access it as
398 | "this.termKey" inside handlers.
399 |
400 | p.e.:
401 |
402 | // a simple ctrlHandler
403 |
404 | function myCtrlHandler() {
405 | if (this.inputChar == termKey.ETX) {
406 | // exit on ^C (^C == ASCII 0x03 == )
407 | this.close();
408 | }
409 | }
410 |
411 | If no `ctrlHandler' is specified, control keys are ignored (default).
412 |
413 |
414 | 3.2.2 Raw Mode
415 |
416 | If the flag `Terminal.rawMode' is set to a value evaluating to `true', no special keys are
417 | tracked but and (and , if the flag `Terminal.closeOnESC' is set).
418 | The input is NOT echoed to the terminal. All printable key values [0x20-0xff] are
419 | transformed to characters and added to `Terminal.lineBuffer' sequentially. The command
420 | line input is NOT added to the history.
421 |
422 | This mode is especially suitable for password input.
423 |
424 | p.e.:
425 |
426 | // using raw mode for password input
427 |
428 | function myTermHandler() {
429 | this.newLine();
430 | // we stored a flag in Terminal.env to track the status
431 | if (this.env.getpassword) {
432 | // leave raw mode
433 | this.rawMode = false;
434 | if (passwords[this.env.user] == this.lineBuffer) {
435 | // matched
436 | this.type('Welcome '+this.env.user);
437 | this.env.loggedin = true;
438 | }
439 | else {
440 | this.type('Sorry.');
441 | }
442 | this.env.getpassword = false;
443 | }
444 | else {
445 | // simple parsing
446 | var args = this.lineBuffer.split(' ');
447 | var cmd = args[0];
448 | if (cmd == 'login') {
449 | var user = args[1];
450 | if (!user) {
451 | this.type('usage: login ');
452 | }
453 | else {
454 | this.env.user = user;
455 | this.env.getpassword = true;
456 | this.type('password? ');
457 | // enter raw mode
458 | this.rawMode = true;
459 | // leave without prompt so we must unlock first
460 | this.lock = false;
461 | return;
462 | }
463 | }
464 | /*
465 | other actions ...
466 | */
467 | }
468 | this.prompt();
469 | }
470 |
471 | In this example a handler is set up to process the command "login " and ask for
472 | a password for the given user name in raw mode. Note the use of the object `Terminal.env'
473 | which is just an empty object set up at the creation of the Terminal instance. Its only
474 | purpose is to provide an individual namespace for private data to be stored by a Terminal
475 | instance.
476 |
477 | NOTE: The flag `Terminal.lock' is used to control the keyboard locking. If we would not
478 | set this to `false' before leaving in raw mode, we would be caught in dead-lock, since no
479 | input could be entered and our handler wouldn't be called again. - A dreadful end of our
480 | terminal session.
481 |
482 | NOTE: Raw mode utilizes the property `Terminal.lastLine' to collect the input string.
483 | This is normally emty, when a handler is called. This is not the case if your script left
484 | the input process on a call of ctrlHandler. You should clear `Terminal.lastLine' in such
485 | a case, if you're going to enter raw mode immediatly after this.
486 |
487 |
488 | 3.2.3 Character Mode
489 |
490 | If the flag `Terminal.charMode' is set to a value evaluating to `true', the terminal is in
491 | character mode. In this mode the numeric ASCII value of the next key typed is stored in
492 | `Terminal.inputChar'. The input is NOT echoed to the terminal. NO locking or cursor
493 | control is performed and left to the handler.
494 | You can use this mode to implement your editor or a console game.
495 | `Terminal.charMode' takes precedence over `Terminal.rawMode'.
496 |
497 | p.e.:
498 |
499 | // using char mode
500 |
501 | function myTermHandler() {
502 | // this is the normal handler
503 | this.newLine();
504 | // simple parsing
505 | var args = this.lineBuffer.split(' ');
506 | var cmd = args[0];
507 | if (cmd == 'edit') {
508 | // init the editor
509 | myEditor(this);
510 | // redirect the handler to editor
511 | this.handler = myEditor;
512 | // leave in char mode
513 | this.charMode = true;
514 | // show cursor
515 | this.cursorOn();
516 | // don't forget unlocking
517 | this.lock = false;
518 | return;
519 | }
520 | /*
521 | other actions ...
522 | */
523 | this.prompt();
524 | }
525 |
526 | function myEditor(initterm) {
527 | // our dummy editor (featuring modal behaviour)
528 | if (initterm) {
529 | // perform initialization tasks
530 | initterm.clear();
531 | initterm.write('this is a simple test editor; leave with then "q"%n%n');
532 | initterm.env.mode = '';
533 | // store a reference of the calling handler
534 | initterm.env.handler = initterm.handler;
535 | return;
536 | }
537 | // called as handler -> lock first
538 | this.lock=true;
539 | // hide cursor
540 | this.cursorOff();
541 | var key = this.inputChar;
542 | if (this.env.mode == 'ctrl') {
543 | // control mode
544 | if (key == 113) {
545 | // "q" => quit
546 | // leave charMode and reset the handler to normal
547 | this.charMode = false;
548 | this.handler = this.env.handler;
549 | // clear the screen
550 | this.clear();
551 | // prompt and return
552 | this.prompt();
553 | return;
554 | }
555 | else {
556 | // leave control mode
557 | this.env.mode = '';
558 | }
559 | }
560 | else {
561 | // edit mode
562 | if (key == termKey.ESC) {
563 | // enter control mode
564 | // we'd better indicate this in a status line ...
565 | this.env.mode = 'ctrl';
566 | }
567 | else if (key == termKey.LEFT) {
568 | // cursor left
569 | }
570 | else if (key == termKey.RIGHT) {
571 | // cursor right
572 | }
573 | if (key == termKey.UP) {
574 | // cursor up
575 | }
576 | else if (key == termKey.DOWN) {
577 | // cursor down
578 | }
579 | else if (key == termKey.CR) {
580 | // cr or enter
581 | }
582 | else if (key == termKey.BS) {
583 | // backspace
584 | }
585 | else if (key == termKey.DEL) {
586 | // fwd delete
587 | // conf.DELisBS is not evaluated in charMode!
588 | }
589 | else if (this.isPrintable(key)) {
590 | // printable char - just type it
591 | var ch = String.fromCharCode(key);
592 | this.type(ch);
593 | }
594 | }
595 | // leave unlocked with cursor
596 | this.lock = false;
597 | this.cursorOn();
598 | }
599 |
600 |
601 | Note the redirecting of the input handler to replace the command line handler by the
602 | editor. The method `Terminal.clear()' clears the terminal.
603 | `Terminal.cursorOn()' and `Terminal.cursorOff()' are used to show and hide the cursor.
604 |
605 |
606 |
607 | 3.3 Other Handlers
608 |
609 | There are two more handlers that can be specified in the configuration object:
610 |
611 |
612 | 3.3.1 initHandler
613 |
614 | `initHandler' is called at the end of the initialization triggered by `Terminal.open()'.
615 | The default action - if no `initHandler' is specified - is:
616 |
617 | // default initilization
618 |
619 | this.write(this.conf.greeting);
620 | this.newLine();
621 | this.prompt();
622 |
623 | Use `initHandler' to perform your own start up tasks (e.g. show a start up screen). Keep
624 | in mind that you should unlock the terminal and possibly show a cursor to give the
625 | impression of a usable terminal.
626 |
627 |
628 | 3.3.2 exitHandler
629 |
630 | `exitHandler' is called by `Terminal.close()' just before hiding the terminal. You can use
631 | this handler to implement any tasks to be performed on exit. Note that this handler is
632 | called even if the terminal is closed on outside of your inputHandlers control.
633 |
634 | See the file "multiterm_test.html" for an example.
635 |
636 |
637 |
638 | 3.4 Overview: Flags for Behaviour Control
639 |
640 | These falgs are accessible as `Terminal.' at runtime. If not stated else, the
641 | initial value may be specified in the configuration object.
642 | The configuration object and its properties are accessible at runtime via `Terminal.conf'.
643 |
644 |
645 | NAME DEFAULT VALUE MEANING
646 |
647 | blink_delay 500 delay for cursor blinking in milliseconds.
648 |
649 | crsrBlinkMode false true for blinking cursor.
650 | if false, cursor is static.
651 |
652 | crsrBlockMode true true for block-cursor else underscore.
653 |
654 | DELisBS false handle as .
655 |
656 | printTab true handle as printable (prints as space)
657 | if false is handled as a control character
658 |
659 | printEuro true handle the euro sign as valid input char.
660 | if false char 0x20AC is printed, but not accepted
661 | in the command line
662 |
663 | catchCtrlH true handle ^H as .
664 | if false, ^H must be tracked by a custom
665 | ctrlHandler.
666 |
667 | closeOnESC true close terminal on .
668 | if true, is not available for ctrHandler.
669 |
670 |
671 | historyUnique false unique history entries.
672 | if true, entries that are identical to the last
673 | entry in the user history will not be added.
674 |
675 | charMode false terminal in character mode (tracks next key-code).
676 | (runtime only)
677 |
678 | rawMode false terminal in raw mode (no echo, no editing).
679 | (runtime only)
680 |
681 | wrapping false text wrapping on/off
682 |
683 | mapANSI false filter ANSI escape sequences and apply SGR styles
684 | and color codes for write()
685 |
686 | ANSItrueBlack false force output of ANSI code 30m (black) as black
687 | (default: render color 0 as foreground color)
688 |
689 |
690 | Not exactly a flag but useful:
691 |
692 | ps '>' prompt string.
693 |
694 |
695 |
696 |
697 | 4 Output Methods
698 |
699 | Please note that any output to the terminal implies an advance of the cursor. This means,
700 | that if your output reaches the last column of your terminal, the cursor is advanced and
701 | a new line is opened automatically. This procedure may include scrolling to make room for
702 | the new line. While this is not of much interest for most purposes, please note that, if
703 | you output a string of length 80 to a 80-columns-terminal, and a new line, and another
704 | string, this will result in an empty line between the two strings.
705 |
706 |
707 | 4.1 Terminal.type( [,] )
708 |
709 | Types the string at the current cursor position to the terminal. Long lines are
710 | broken where the last column of the terminal is reached and continued in the next line.
711 | `Terminal.write()' does not support any kind of arbitrary line breaks. (This is just a
712 | basic output routine. See `Terminal.write()' for a more powerful output method.)
713 |
714 | A bitvector may be supplied as an optional second argument to represent a style or a
715 | combination of styles. The meanings of the bits set are interpreted as follows:
716 |
717 | :
718 |
719 | 1 ... reverse (2 power 0)
720 | 2 ... underline (2 power 1)
721 | 4 ... italics (2 power 2)
722 | 8 ... strike (2 power 3)
723 | 16 ... bold (2 power 4) *displayed as italics, used internally for ANSI-mapping*
724 |
725 | So "Terminal.type( 'text', 5 )" types "text" in italics and reverse video.
726 |
727 | Note:
728 | There is no bold, for most monospaced fonts (including Courier) tend to render wider in
729 | bold. Since this would bring the terminal's layout out of balance, we just can't use bold
730 | as a style. - Sorry.
731 |
732 | The HTML-representation of this styles are defined in "TermGlobals.termStyleOpen" and
733 | "TermGlobals.termStyleClose".
734 | (Version 1.4: "TermGlobals" is now a reference to "Terminal.prototype.globals".)
735 |
736 | Version 1.2 introduces additional styles for colors.
737 | Please read also sect. 4.10 "Using Color" for the extended color values.
738 |
739 |
740 | 4.2 Terminal.write( [,] )
741 |
742 | Writes a text with markup to the terminal. If an optional second argument evaluates to
743 | true, a UN*X-style utility like `more' is used to page the text. The text may be supplied
744 | as a single string (with newline character "\n") or as an array of lines. Any other input
745 | is transformed to a string value before output.
746 |
747 | 4.2.1 Mark-up:
748 |
749 | `Terminal.write()' employs a simple mark-up with the following syntax:
750 |
751 | : %((+|-)
22 |
23 |
24 |
25 |
26 |
27 |
62 | |
| |
|