source: package_branches/invirt-web/cherrypy/code/static/ajaxterm/ajaxterm.js @ 2455

Last change on this file since 2455 was 2454, checked in by quentin, 15 years ago

Use browser-based dupe suppression, so multiple clients can connect to the same terminal and not miss updates

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