Import upstream ajaxterm 0.10
[invirt/packages/invirt-web.git] / code / static / ajaxterm / ajaxterm.js
1 ajaxterm={};
2 ajaxterm.Terminal_ctor=function(id,width,height) {
3         var ie=0;
4         if(window.ActiveXObject)
5                 ie=1;
6         var sid=""+Math.round(Math.random()*1000000000);
7         var query0="s="+sid+"&w="+width+"&h="+height;
8         var query1=query0+"&c=1&k=";
9         var buf="";
10         var timeout;
11         var error_timeout;
12         var keybuf=[];
13         var sending=0;
14         var rmax=1;
15
16         var div=document.getElementById(id);
17         var dstat=document.createElement('pre');
18         var sled=document.createElement('span');
19         var opt_get=document.createElement('a');
20         var opt_color=document.createElement('a');
21         var opt_paste=document.createElement('a');
22         var sdebug=document.createElement('span');
23         var dterm=document.createElement('div');
24
25         function debug(s) {
26                 sdebug.innerHTML=s;
27         }
28         function error() {
29                 sled.className='off';
30                 debug("Connection lost timeout ts:"+((new Date).getTime()));
31         }
32         function opt_add(opt,name) {
33                 opt.className='off';
34                 opt.innerHTML=' '+name+' ';
35                 dstat.appendChild(opt);
36                 dstat.appendChild(document.createTextNode(' '));
37         }
38         function do_get(event) {
39                 opt_get.className=(opt_get.className=='off')?'on':'off';
40                 debug('GET '+opt_get.className);
41         }
42         function do_color(event) {
43                 var o=opt_color.className=(opt_color.className=='off')?'on':'off';
44                 if(o=='on')
45                         query1=query0+"&c=1&k=";
46                 else
47                         query1=query0+"&k=";
48                 debug('Color '+opt_color.className);
49         }
50         function mozilla_clipboard() {
51                  // mozilla sucks
52                 try {
53                         netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");
54                 } catch (err) {
55                         debug('Access denied, <a href="http://kb.mozillazine.org/Granting_JavaScript_access_to_the_clipboard" target="_blank">more info</a>');
56                         return undefined;
57                 }
58                 var clip = Components.classes["@mozilla.org/widget/clipboard;1"].createInstance(Components.interfaces.nsIClipboard);
59                 var trans = Components.classes["@mozilla.org/widget/transferable;1"].createInstance(Components.interfaces.nsITransferable);
60                 if (!clip || !trans) {
61                         return undefined;
62                 }
63                 trans.addDataFlavor("text/unicode");
64                 clip.getData(trans,clip.kGlobalClipboard);
65                 var str=new Object();
66                 var strLength=new Object();
67                 try {
68                         trans.getTransferData("text/unicode",str,strLength);
69                 } catch(err) {
70                         return "";
71                 }
72                 if (str) {
73                         str=str.value.QueryInterface(Components.interfaces.nsISupportsString);
74                 }
75                 if (str) {
76                         return str.data.substring(0,strLength.value / 2);
77                 } else {
78                         return "";
79                 }
80         }
81         function do_paste(event) {
82                 var p=undefined;
83                 if (window.clipboardData) {
84                         p=window.clipboardData.getData("Text");
85                 } else if(window.netscape) {
86                         p=mozilla_clipboard();
87                 }
88                 if (p) {
89                         debug('Pasted');
90                         queue(encodeURIComponent(p));
91                 } else {
92                 }
93         }
94         function update() {
95 //              debug("ts: "+((new Date).getTime())+" rmax:"+rmax);
96                 if(sending==0) {
97                         sending=1;
98                         sled.className='on';
99                         var r=new XMLHttpRequest();
100                         var send="";
101                         while(keybuf.length>0) {
102                                 send+=keybuf.pop();
103                         }
104                         var query=query1+send;
105                         if(opt_get.className=='on') {
106                                 r.open("GET","u?"+query,true);
107                                 if(ie) {
108                                         r.setRequestHeader("If-Modified-Since", "Sat, 1 Jan 2000 00:00:00 GMT");
109                                 }
110                         } else {
111                                 r.open("POST","u",true);
112                         }
113                         r.setRequestHeader('Content-Type','application/x-www-form-urlencoded');
114                         r.onreadystatechange = function () {
115 //                              debug("xhr:"+((new Date).getTime())+" state:"+r.readyState+" status:"+r.status+" statusText:"+r.statusText);
116                                 if (r.readyState==4) {
117                                         if(r.status==200) {
118                                                 window.clearTimeout(error_timeout);
119                                                 de=r.responseXML.documentElement;
120                                                 if(de.tagName=="pre") {
121                                                         if(ie) {
122                                                                 Sarissa.updateContentFromNode(de, dterm);
123                                                         } else {
124                                                                 Sarissa.updateContentFromNode(de, dterm);
125 //                                                              old=div.firstChild;
126 //                                                              div.replaceChild(de,old);
127                                                         }
128                                                         rmax=100;
129                                                 } else {
130                                                         rmax*=2;
131                                                         if(rmax>2000)
132                                                                 rmax=2000;
133                                                 }
134                                                 sending=0;
135                                                 sled.className='off';
136                                                 timeout=window.setTimeout(update,rmax);
137                                         } else {
138                                                 debug("Connection error status:"+r.status);
139                                         }
140                                 }
141                         }
142                         error_timeout=window.setTimeout(error,5000);
143                         if(opt_get.className=='on') {
144                                 r.send(null);
145                         } else {
146                                 r.send(query);
147                         }
148                 }
149         }
150         function queue(s) {
151                 keybuf.unshift(s);
152                 if(sending==0) {
153                         window.clearTimeout(timeout);
154                         timeout=window.setTimeout(update,1);
155                 }
156         }
157         function keypress(ev) {
158                 if (!ev) var ev=window.event;
159 //              s="kp keyCode="+ev.keyCode+" which="+ev.which+" shiftKey="+ev.shiftKey+" ctrlKey="+ev.ctrlKey+" altKey="+ev.altKey;
160 //              debug(s);
161 //              return false;
162 //              else { if (!ev.ctrlKey || ev.keyCode==17) { return; }
163                 var kc;
164                 var k="";
165                 if (ev.keyCode)
166                         kc=ev.keyCode;
167                 if (ev.which)
168                         kc=ev.which;
169                 if (ev.altKey) {
170                         if (kc>=65 && kc<=90)
171                                 kc+=32;
172                         if (kc>=97 && kc<=122) {
173                                 k=String.fromCharCode(27)+String.fromCharCode(kc);
174                         }
175                 } else if (ev.ctrlKey) {
176                         if (kc>=65 && kc<=90) k=String.fromCharCode(kc-64); // Ctrl-A..Z
177                         else if (kc>=97 && kc<=122) k=String.fromCharCode(kc-96); // Ctrl-A..Z
178                         else if (kc==54)  k=String.fromCharCode(30); // Ctrl-^
179                         else if (kc==109) k=String.fromCharCode(31); // Ctrl-_
180                         else if (kc==219) k=String.fromCharCode(27); // Ctrl-[
181                         else if (kc==220) k=String.fromCharCode(28); // Ctrl-\
182                         else if (kc==221) k=String.fromCharCode(29); // Ctrl-]
183                         else if (kc==219) k=String.fromCharCode(29); // Ctrl-]
184                         else if (kc==219) k=String.fromCharCode(0);  // Ctrl-@
185                 } else if (ev.which==0) {
186                         if (kc==9) k=String.fromCharCode(9);  // Tab
187                         else if (kc==8) k=String.fromCharCode(127);  // Backspace
188                         else if (kc==27) k=String.fromCharCode(27); // Escape
189                         else {
190                                 if (kc==33) k="[5~";        // PgUp
191                                 else if (kc==34) k="[6~";   // PgDn
192                                 else if (kc==35) k="[4~";   // End
193                                 else if (kc==36) k="[1~";   // Home
194                                 else if (kc==37) k="[D";    // Left
195                                 else if (kc==38) k="[A";    // Up
196                                 else if (kc==39) k="[C";    // Right
197                                 else if (kc==40) k="[B";    // Down
198                                 else if (kc==45) k="[2~";   // Ins
199                                 else if (kc==46) k="[3~";   // Del
200                                 else if (kc==112) k="[[A";  // F1
201                                 else if (kc==113) k="[[B";  // F2
202                                 else if (kc==114) k="[[C";  // F3
203                                 else if (kc==115) k="[[D";  // F4
204                                 else if (kc==116) k="[[E";  // F5
205                                 else if (kc==117) k="[17~"; // F6
206                                 else if (kc==118) k="[18~"; // F7
207                                 else if (kc==119) k="[19~"; // F8
208                                 else if (kc==120) k="[20~"; // F9
209                                 else if (kc==121) k="[21~"; // F10
210                                 else if (kc==122) k="[23~"; // F11
211                                 else if (kc==123) k="[24~"; // F12
212                                 if (k.length) {
213                                         k=String.fromCharCode(27)+k;
214                                 }
215                         }
216                 } else {
217                         if (kc==8)
218                                 k=String.fromCharCode(127);  // Backspace
219                         else
220                                 k=String.fromCharCode(kc);
221                 }
222                 if(k.length) {
223 //                      queue(encodeURIComponent(k));
224                         if(k=="+") {
225                                 queue("%2B");
226                         } else {
227                                 queue(escape(k));
228                         }
229                 }
230                 ev.cancelBubble=true;
231                 if (ev.stopPropagation) ev.stopPropagation();
232                 if (ev.preventDefault)  ev.preventDefault();
233                 return false;
234         }
235         function keydown(ev) {
236                 if (!ev) var ev=window.event;
237                 if (ie) {
238 //                      s="kd keyCode="+ev.keyCode+" which="+ev.which+" shiftKey="+ev.shiftKey+" ctrlKey="+ev.ctrlKey+" altKey="+ev.altKey;
239 //                      debug(s);
240                         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,
241                         113:1,114:1,115:1,116:1,117:1,118:1,119:1,120:1,121:1,122:1,123:1};
242                         if (o[ev.keyCode] || ev.ctrlKey || ev.altKey) {
243                                 ev.which=0;
244                                 return keypress(ev);
245                         }
246                 }
247         }
248         function init() {
249                 sled.appendChild(document.createTextNode('\xb7'));
250                 sled.className='off';
251                 dstat.appendChild(sled);
252                 dstat.appendChild(document.createTextNode(' '));
253                 opt_add(opt_color,'Colors');
254                 opt_color.className='on';
255                 opt_add(opt_get,'GET');
256                 opt_add(opt_paste,'Paste');
257                 dstat.appendChild(sdebug);
258                 dstat.className='stat';
259                 div.appendChild(dstat);
260                 div.appendChild(dterm);
261                 if(opt_color.addEventListener) {
262                         opt_get.addEventListener('click',do_get,true);
263                         opt_color.addEventListener('click',do_color,true);
264                         opt_paste.addEventListener('click',do_paste,true);
265                 } else {
266                         opt_get.attachEvent("onclick", do_get);
267                         opt_color.attachEvent("onclick", do_color);
268                         opt_paste.attachEvent("onclick", do_paste);
269                 }
270                 document.onkeypress=keypress;
271                 document.onkeydown=keydown;
272                 timeout=window.setTimeout(update,100);
273         }
274         init();
275 }
276 ajaxterm.Terminal=function(id,width,height) {
277         return new this.Terminal_ctor(id,width,height);
278 }
279