Felix Meschberger | 044c4bf | 2012-01-31 12:47:45 +0000 | [diff] [blame] | 1 | // |
| 2 | // Licensed to the Apache Software Foundation (ASF) under one or more |
| 3 | // contributor license agreements. See the NOTICE file distributed with |
| 4 | // this work for additional information regarding copyright ownership. |
| 5 | // The ASF licenses this file to You under the Apache License, Version 2.0 |
| 6 | // (the "License"); you may not use this file except in compliance with |
| 7 | // the License. You may obtain a copy of the License at |
| 8 | // |
| 9 | // http://www.apache.org/licenses/LICENSE-2.0 |
| 10 | // |
| 11 | // Unless required by applicable law or agreed to in writing, software |
| 12 | // distributed under the License is distributed on an "AS IS" BASIS, |
| 13 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| 14 | // See the License for the specific language governing permissions and |
| 15 | // limitations under the License. |
| 16 | // |
| 17 | |
| 18 | // |
| 19 | // Based on http://antony.lesuisse.org/software/ajaxterm/ |
| 20 | // Public Domain License |
| 21 | // |
| 22 | |
| 23 | gogo = { }; |
| 24 | |
| 25 | gogo.Terminal_ctor = function(div, width, height) { |
| 26 | |
| 27 | var query0 = "w=" + width + "&h=" + height; |
| 28 | var query1 = query0 + "&k="; |
| 29 | var buf = ""; |
| 30 | var timeout; |
| 31 | var error_timeout; |
| 32 | var keybuf = []; |
| 33 | var sending = 0; |
| 34 | var rmax = 1; |
| 35 | var force = 1; |
| 36 | |
| 37 | var dstat = document.createElement('pre'); |
| 38 | var sled = document.createElement('span'); |
Felix Meschberger | 99c60c8 | 2012-06-01 14:37:54 +0000 | [diff] [blame^] | 39 | var sdebug = document.getElementById('statline'); |
Felix Meschberger | 044c4bf | 2012-01-31 12:47:45 +0000 | [diff] [blame] | 40 | var dterm = document.createElement('div'); |
| 41 | |
| 42 | function debug(s) { |
| 43 | sdebug.innerHTML = s; |
| 44 | } |
| 45 | |
| 46 | function error() { |
| 47 | sled.className = 'off'; |
Felix Meschberger | 99c60c8 | 2012-06-01 14:37:54 +0000 | [diff] [blame^] | 48 | debug("Gogo Shell Processor not available"); |
Felix Meschberger | 044c4bf | 2012-01-31 12:47:45 +0000 | [diff] [blame] | 49 | } |
| 50 | |
| 51 | function update() { |
Felix Meschberger | 99c60c8 | 2012-06-01 14:37:54 +0000 | [diff] [blame^] | 52 | if (sending == 0 /* && keybuf.length > 0 */ ) { |
Felix Meschberger | 044c4bf | 2012-01-31 12:47:45 +0000 | [diff] [blame] | 53 | sending = 1; |
| 54 | sled.className = 'on'; |
| 55 | var r = new XMLHttpRequest(); |
| 56 | var send = ""; |
| 57 | while (keybuf.length > 0) { |
| 58 | send += keybuf.pop(); |
| 59 | } |
| 60 | var query = query1 + send; |
| 61 | if (force) { |
| 62 | query = query + "&f=1"; |
| 63 | force = 0; |
| 64 | } |
| 65 | r.open("POST", "gogo", true); |
| 66 | r.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded'); |
| 67 | r.onreadystatechange = function () { |
| 68 | if (r.readyState == 4) { |
| 69 | if (r.status == 200) { |
| 70 | window.clearTimeout(error_timeout); |
| 71 | if (r.responseText.length > 0) { |
| 72 | dterm.innerHTML = r.responseText; |
| 73 | rmax = 100; |
| 74 | } else { |
| 75 | rmax *= 2; |
| 76 | if (rmax > 2000) |
| 77 | rmax = 2000; |
| 78 | } |
| 79 | sending=0; |
| 80 | sled.className = 'off'; |
| 81 | timeout = window.setTimeout(update, rmax); |
Felix Meschberger | 99c60c8 | 2012-06-01 14:37:54 +0000 | [diff] [blame^] | 82 | } else if (r.status == 500) { |
| 83 | debug("Gogo Shell Processor not available") |
Felix Meschberger | 044c4bf | 2012-01-31 12:47:45 +0000 | [diff] [blame] | 84 | } else { |
Felix Meschberger | 99c60c8 | 2012-06-01 14:37:54 +0000 | [diff] [blame^] | 85 | debug("General failure with Gogo Shell: " + r.status); |
Felix Meschberger | 044c4bf | 2012-01-31 12:47:45 +0000 | [diff] [blame] | 86 | } |
| 87 | } |
| 88 | } |
| 89 | error_timeout = window.setTimeout(error, 5000); |
| 90 | r.send(query); |
| 91 | } |
| 92 | } |
| 93 | |
| 94 | function queue(s) { |
| 95 | keybuf.unshift(s); |
| 96 | if (sending == 0) { |
| 97 | window.clearTimeout(timeout); |
| 98 | timeout = window.setTimeout(update, 1); |
| 99 | } |
| 100 | } |
| 101 | |
| 102 | function keypress(ev, fromkeydown) { |
| 103 | // Translate to standard keycodes |
| 104 | if (!ev) |
| 105 | ev = window.event; |
| 106 | var kc; |
| 107 | if (ev.keyCode) |
| 108 | kc = ev.keyCode; |
| 109 | if (!fromkeydown && ev.which) |
| 110 | kc = ev.which; |
| 111 | if (ev.ctrlKey) { |
| 112 | if (kc >= 0 && kc <= 32) |
| 113 | kc = kc; |
| 114 | else if (kc >= 65 && kc <= 90) |
| 115 | kc -= 64; |
| 116 | else if (kc >= 97 && kc <= 122) |
| 117 | kc -= 96; |
| 118 | else { |
| 119 | switch (kc) { |
| 120 | case 54: kc=30; break; // Ctrl-^ |
| 121 | case 109: kc=31; break; // Ctrl-_ |
| 122 | case 219: kc=27; break; // Ctrl-[ |
| 123 | case 220: kc=28; break; // Ctrl-\ |
| 124 | case 221: kc=29; break; // Ctrl-] |
| 125 | default: return true; |
| 126 | } |
| 127 | } |
| 128 | } else if (fromkeydown) { |
| 129 | switch(kc) { |
| 130 | case 8: break; // Backspace |
| 131 | case 9: break; // Tab |
| 132 | case 27: break; // ESC |
| 133 | case 33: kc = 63276; break; // PgUp |
| 134 | case 34: kc = 63277; break; // PgDn |
| 135 | case 35: kc = 63275; break; // End |
| 136 | case 36: kc = 63273; break; // Home |
| 137 | case 37: kc = 63234; break; // Left |
| 138 | case 38: kc = 63232; break; // Up |
| 139 | case 39: kc = 63235; break; // Right |
| 140 | case 40: kc = 63233; break; // Down |
| 141 | case 45: kc = 63302; break; // Ins |
| 142 | case 46: kc = 63272; break; // Del |
| 143 | case 112: kc = 63236; break; // F1 |
| 144 | case 113: kc = 63237; break; // F2 |
| 145 | case 114: kc = 63238; break; // F3 |
| 146 | case 115: kc = 63239; break; // F4 |
| 147 | case 116: kc = 63240; break; // F5 |
| 148 | case 117: kc = 63241; break; // F6 |
| 149 | case 118: kc = 63242; break; // F7 |
| 150 | case 119: kc = 63243; break; // F8 |
| 151 | case 120: kc = 63244; break; // F9 |
| 152 | case 121: kc = 63245; break; // F10 |
| 153 | case 122: kc = 63246; break; // F11 |
| 154 | case 123: kc = 63247; break; // F12 |
| 155 | default: return true; |
| 156 | } |
| 157 | } |
| 158 | |
| 159 | var k = ""; |
| 160 | // Build character |
| 161 | switch (kc) { |
| 162 | case 126: k = "~~"; break; |
| 163 | case 63232: k = "~A"; break; // Up |
| 164 | case 63233: k = "~B"; break; // Down |
| 165 | case 63234: k = "~D"; break; // Left |
| 166 | case 63235: k = "~C"; break; // Right |
| 167 | case 63276: k = "~1"; break; // PgUp |
| 168 | case 63277: k = "~2"; break; // PgDn |
| 169 | case 63273: k = "~H"; break; // Home |
| 170 | case 63275: k = "~F"; break; // End |
| 171 | case 63302: k = "~3"; break; // Ins |
| 172 | case 63272: k = "~4"; break; // Del |
| 173 | case 63236: k = "~a"; break; // F1 |
| 174 | case 63237: k = "~b"; break; // F2 |
| 175 | case 63238: k = "~c"; break; // F3 |
| 176 | case 63239: k = "~d"; break; // F4 |
| 177 | case 63240: k = "~e"; break; // F5 |
| 178 | case 63241: k = "~f"; break; // F6 |
| 179 | case 63242: k = "~g"; break; // F7 |
| 180 | case 63243: k = "~h"; break; // F8 |
| 181 | case 63244: k = "~i"; break; // F9 |
| 182 | case 63245: k = "~j"; break; // F10 |
| 183 | case 63246: k = "~k"; break; // F11 |
| 184 | case 63247: k = "~l"; break; // F12 |
| 185 | default: k = String.fromCharCode(kc); break; |
| 186 | } |
| 187 | |
Felix Meschberger | 99c60c8 | 2012-06-01 14:37:54 +0000 | [diff] [blame^] | 188 | var s = encodeURIComponent(k); |
| 189 | |
Felix Meschberger | 044c4bf | 2012-01-31 12:47:45 +0000 | [diff] [blame] | 190 | // debug("fromkeydown=" + fromkeydown + ", ev.keyCode=" + ev.keyCode + ", " + |
| 191 | // "ev.which=" + ev.which + ", ev.ctrlKey=" + ev.ctrlKey + ", " + |
Felix Meschberger | 99c60c8 | 2012-06-01 14:37:54 +0000 | [diff] [blame^] | 192 | // "kc=" + kc + ", k=" + k + ", s=" + s); |
Felix Meschberger | 044c4bf | 2012-01-31 12:47:45 +0000 | [diff] [blame] | 193 | |
Felix Meschberger | 99c60c8 | 2012-06-01 14:37:54 +0000 | [diff] [blame^] | 194 | queue(s); |
Felix Meschberger | 044c4bf | 2012-01-31 12:47:45 +0000 | [diff] [blame] | 195 | |
| 196 | ev.cancelBubble = true; |
| 197 | if (ev.stopPropagation) ev.stopPropagation(); |
| 198 | if (ev.preventDefault) ev.preventDefault(); |
| 199 | |
| 200 | return true; |
| 201 | } |
| 202 | |
| 203 | function keydown(ev) { |
| 204 | if (!ev) |
| 205 | ev = window.event; |
| 206 | o = { 9:1, 8:1, 27:1, 33:1, 34:1, 35:1, 36:1, 37:1, 38:1, 39:1, 40:1, 45:1, 46:1, 112:1, |
| 207 | 113:1, 114:1, 115:1, 116:1, 117:1, 118:1, 119:1, 120:1, 121:1, 122:1, 123:1 }; |
| 208 | if (o[ev.keyCode] || ev.ctrlKey || ev.altKey) { |
| 209 | keypress(ev, true); |
Felix Meschberger | 99c60c8 | 2012-06-01 14:37:54 +0000 | [diff] [blame^] | 210 | } else { |
| 211 | ev.cancelBubble = true; |
| 212 | if (ev.stopPropagation) ev.stopPropagation(); |
| 213 | if (ev.preventDefault) ev.preventDefault(); |
Felix Meschberger | 044c4bf | 2012-01-31 12:47:45 +0000 | [diff] [blame] | 214 | } |
| 215 | } |
Felix Meschberger | 99c60c8 | 2012-06-01 14:37:54 +0000 | [diff] [blame^] | 216 | |
| 217 | function ignoreKey(ev) { |
| 218 | if (!ev) { |
| 219 | ev = window.event; |
| 220 | } |
| 221 | |
| 222 | ev.cancelBubble = true; |
| 223 | if (ev.stopPropagation) ev.stopPropagation(); |
| 224 | if (ev.preventDefault) ev.preventDefault(); |
| 225 | } |
Felix Meschberger | 044c4bf | 2012-01-31 12:47:45 +0000 | [diff] [blame] | 226 | |
| 227 | function init() { |
| 228 | if (typeof(XMLHttpRequest) == "undefined") { |
| 229 | XMLHttpRequest = function() { |
| 230 | try { return new ActiveXObject("Msxml2.XMLHTTP.6.0"); } |
| 231 | catch(e) {} |
| 232 | try { return new ActiveXObject("Msxml2.XMLHTTP.3.0"); } |
| 233 | catch(e) {} |
| 234 | try { return new ActiveXObject("Msxml2.XMLHTTP"); } |
| 235 | catch(e) {} |
| 236 | try { return new ActiveXObject("Microsoft.XMLHTTP"); } |
| 237 | catch(e) {} |
| 238 | throw new Error("This browser does not support XMLHttpRequest."); |
| 239 | }; |
| 240 | } |
Felix Meschberger | 99c60c8 | 2012-06-01 14:37:54 +0000 | [diff] [blame^] | 241 | |
Felix Meschberger | 044c4bf | 2012-01-31 12:47:45 +0000 | [diff] [blame] | 242 | sled.appendChild(document.createTextNode('\xb7')); |
| 243 | sled.className = 'off'; |
| 244 | dstat.appendChild(sled); |
| 245 | dstat.appendChild(document.createTextNode(' ')); |
Felix Meschberger | 99c60c8 | 2012-06-01 14:37:54 +0000 | [diff] [blame^] | 246 | // dstat.appendChild(sdebug); |
Felix Meschberger | 044c4bf | 2012-01-31 12:47:45 +0000 | [diff] [blame] | 247 | dstat.className = 'stat'; |
Felix Meschberger | 99c60c8 | 2012-06-01 14:37:54 +0000 | [diff] [blame^] | 248 | |
Felix Meschberger | 044c4bf | 2012-01-31 12:47:45 +0000 | [diff] [blame] | 249 | div.appendChild(dstat); |
| 250 | var d = document.createElement('div'); |
| 251 | d.appendChild(dterm); |
| 252 | div.appendChild(d); |
Felix Meschberger | 99c60c8 | 2012-06-01 14:37:54 +0000 | [diff] [blame^] | 253 | |
Felix Meschberger | 044c4bf | 2012-01-31 12:47:45 +0000 | [diff] [blame] | 254 | document.onkeypress = keypress; |
Felix Meschberger | 99c60c8 | 2012-06-01 14:37:54 +0000 | [diff] [blame^] | 255 | document.onkeydown = ignoreKey; |
| 256 | document.onkeyup = ignoreKey; |
Felix Meschberger | 044c4bf | 2012-01-31 12:47:45 +0000 | [diff] [blame] | 257 | timeout = window.setTimeout(update, 100); |
| 258 | } |
| 259 | |
| 260 | init(); |
| 261 | |
| 262 | } |
| 263 | |
| 264 | gogo.Terminal = function(div, width, height) { |
| 265 | return new this.Terminal_ctor(div, width, height); |
| 266 | } |
| 267 | |