lib-js-terminal-termlib-socket.js / js
/* termlib_socket.js - termlib.js Socket Extension v.1.02 applies to the termlib.js license (cf: <http://www.masswerk.at/termlib/>) (c) Norbert Landsteiner 2003-2007 mass:werk - media environments <http://www.masswerk.at> load termlib.js first! Syntax is JS 1.5 or higher (no NS4 compatibility) # Synopsis: Integrates async XMLHttpRequests (AJAX/JSON) tightly into termlib.js # Example: myTerm = new Terminal( { handler: myTermHandler } ); myTerm.open(); function myTermHandler() { this.newLine(); if (this.lineBuffer == 'get file') { myTerm.send( { url: 'myservice', data: { book: 'theBook', chapter: 7, page: 45 }, callback: myCallback } ); return; } else { // ... } this.prompt(); } function myCallback() { if (this.socket.success) { this.write(this.socket.responseText); } else { this.write('OOPS: ' + this.socket.status + ' ' + this.socket.statusText); if (this.socket.errno) { this.newLine(); this.write('Error: ' + this.socket.errstring); } } this.prompt(); } # Documentation: for usage and description see readme.txt chapter 13: <http://www.masswerk.at/termlib/readme.txt> or refer to the sample page: <http://www.masswerk.at/termlib/sample_socket.html> # Version History: 2007-03: v. 1.01 2007-04: v. 1.02 just a little clean up */ if (window.Terminal && typeof window.Terminal == 'function') { Terminal.prototype._HttpSocket = function() { var req=null; if (window.XMLHttpRequest) { try { req=new XMLHttpRequest(); } catch(e) {} } else if (window.ActiveXObject) { var prtcls=this._msXMLHttpObjects; for (var i=0; i<prtcls.length; i++) { try { req=new ActiveXObject(prtcls[i]); if (req) { // shorten proto list to working element if (prtcls.length>1) this.prototype._msXMLHttpObjects= [ prtcls[i] ]; break; } } catch(e) {} } } this.request=req; this.url; this.data=null; this.query=''; this.timeoutTimer=null; this.localMode=Boolean(window.location.href.search(/^file:/i)==0); this.error=0; } Terminal.prototype._HttpSocket.prototype = { version: '1.02', // config useXMLEncoding: false, // use ";" as separator if true, "&" else defaulTimeout: 10000, // request timeout in ticks (milliseconds) defaultMethod: 'GET', forceNewline: true, // translate line-breaks in responseText to newlines // static const errno: { OK: 0, NOTIMPLEMENTED: 1, FATALERROR: 2, TIMEOUT: 3, NETWORKERROR: 4, LOCALFILEERROR: 5 }, errstring: [ '', 'XMLHttpRequest not implemented.', 'Could not open XMLHttpRequest.', 'The connection timed out.', 'Network error.', 'The requested local document was not found.' ], // private static data _msXMLHttpObjects: [ 'Msxml2.XMLHTTP', 'Microsoft.XMLHTTP', 'Msxml2.XMLHTTP.5.0', 'Msxml2.XMLHTTP.4.0', 'Msxml2.XMLHTTP.3.0' ], // internal methods serializeData: function() { this.query=this.serialize(this.data); }, serialize: function(data) { var v=''; if( data != null ) { switch (typeof data) { case 'object': var d=[]; if (data instanceof Array) { // array for (var i=0; i<data.length; i++) { d.push(this.serialize(data[i])); } v= d.join(','); break; } for (var i in data) { switch (typeof data[i]) { case 'object': d.push(encodeURIComponent(i)+'='+this.serialize(data[i])); break; default: d.push(encodeURIComponent(i)+'='+encodeURIComponent(data[i])); break; } } v= (this.useXMLEncoding)? d.join(';') : d.join('&'); break; case 'number': v=String(data); break; case 'string': v=encodeURIComponent(data); break; case 'boolean': v=(data)? '1':'0'; break; } } return v; }, toCamelCase: function(s) { if (typeof s!='string') s=String(s); var a=s.toLowerCase().split('-'); var cc=a[0]; for (var i=1; i<a.length; i++) { p=a[i]; if (p.length) cc+=p.charAt(0).toUpperCase()+p.substring(1); } return cc; }, callbackHandler: function() { if (this.termRef.closed) return; var r=this.request; if (this.error==0 && r.readyState!=4) return; if (this.timeoutTimer) { clearTimeout (this.timeoutTimer); this.timeoutTimer = null; } var success=false; var failed=true; var response={ headers: {} }; if (this.localMode) { if (this.error && this.error<this.errno.NETWORKERROR) { response.status=0; response.statusText='Connection Error'; response.responseText=''; response.responseXML=null; } else if (this.error || r.responseText==null) { failed=false; response.status=404; response.statusText='Not Found'; response.responseText='The document '+this.url+' was not found on this file system.'; response.responseXML=null; this.error=this.errno.LOCALFILEERROR; } else { success=true; failed=false; response.status=200; response.statusText='OK'; response.responseText=r.responseText; response.responseXML=r.responseXML; } } else { try { if (!this.error) { if (typeof r == 'object' && r.status != undefined) { failed=false; if ((r.status >= 200) && (r.status < 300)) { success=true; } else if (r.status >= 12000) { // MSIE network error failed=true; this.error=this.errno.NETWORKERROR; } } } } catch(e) {} if (!failed) { response.status=r.status; response.statusText= (r.status==404)? 'Not Found':r.statusText; // force correct header response.responseText=r.responseText; response.responseXML=r.responseXML; if (this.getHeaders) { if (this.getHeaders instanceof Array) { for (var i=0; i<this.getHeaders.length; i++) { var h=this.getHeaders[i]; try { response.headers[this.toCamelCase(h)]=r.getResponseHeader(h); } catch(e) {} } } else { for (var h in this.getHeaders) { try { response.headers[this.toCamelCase(h)]=r.getResponseHeader(h); } catch(e) {} } } } } else { response.status=0; response.statusText='Connection Error'; response.responseText=''; response.responseXML=null; } } if (this.forceNewline) response.responseText=response.responseText.replace(/\r\n?/g, '\n'); response.url=this.url; response.data=this.data; response.query=this.query; response.method=this.method; response.success=success; response.errno=this.error; response.errstring=this.errstring[this.error]; var term=this.termRef; term.socket=response; if (this.callback) { if (typeof this.callback=='function') { this.callback.apply(term); } else if (window[this.callback] && typeof window[this.callback]=='function') { window[this.callback].apply(term); } else { term._defaultServerCallback(); } } else { term._defaultServerCallback(); } delete term.socket; this.request=null; this.callback=null; }, timeoutHandler: function() { this.error = this.errno.TIMEOUT; try { this.request.abort(); } catch(e) {} if (!this.localMode) this.callbackHandler(); } } Terminal.prototype.send = function( opts ) { var soc = new this._HttpSocket(); if (opts) { if (typeof opts.method == 'string') { switch (opts.method.toLowerCase()) { case 'post': soc.method='POST'; break; case 'get': soc.method='GET'; break; default: soc.method=soc.defaultMethod.toUpperCase(); } } else { soc.method=soc.defaultMethod; } if (opts.postbody != undefined) { soc.method='POST'; soc.query=opts.postbody; soc.data=opts.data; } else if (opts.data != undefined) { soc.data=opts.data; soc.serializeData(); } if (opts.url) soc.url=opts.url; if (opts.getHeaders && (typeof opts.getHeaders=='object')) { soc.getHeaders=opts.getHeaders; } } else { opts = {} soc.method=soc.defaultMethod; } var uri=soc.url; if (soc.method=='GET') { if (soc.query) { uri+= (uri.indexOf('?')<0)? '?'+soc.query : (soc.useXMLEncoding)? ';'+soc.query : '&'+soc.query; } if (!soc.localMode) { // add a random value to the query string (force a request) var uniqueparam= '_termlib_reqid=' +new Date().getTime()+'_'+Math.floor(Math.random()*100000); uri+= (uri.indexOf('?')<0)? '?'+uniqueparam : (soc.useXMLEncoding)? ';'+uniqueparam : '&'+uniqueparam; } } soc.callback=opts.callback; soc.termRef=this; if (!soc.request) { soc.error = soc.errno.NOTIMPLEMENTED; soc.callbackHandler(); return; } else { try { if (opts.userid!=undefined) { if (opts.password!=undefined) { soc.request.open(soc.method, uri, true, opts.userid, opts.password); } else { soc.request.open(soc.method, uri, true, opts.userid); } } else { soc.request.open(soc.method, uri, true); } } catch(e) { soc.error = soc.errno.FATALERROR; soc.callbackHandler(); return; } var body=null; if (soc.method == 'POST') { try { soc.request.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded'); } catch(e) {} body=soc.query; } if (opts.headers && typeof opts.headers == 'objects') { for (var i in opts.headers) { try { soc.request.setRequestHeader(i, opts.headers[i]); } catch(e) {} } } if (opts.mimetype && soc.request.overrideMimeType) { try { soc.request.overrideMimeType(opts.mimetype); // force "Connection: close" (Bugzilla #246651) soc.request.setRequestHeader('Connection', 'close'); } catch(e) {} } var timeoutDelay=(opts.timeout && typeof opts.timeout=='number')? opts.tiomeout : soc.defaulTimeout; soc.request.onreadystatechange=function() { soc.callbackHandler(); }; try { soc.request.send(body); } catch(e) { if (soc.localMode) { soc.request.onreadystatechange=null; soc.request.abort(); soc.error = soc.errno.LOCALFILEERROR; } else { soc.request.onreadystatechange=null; try { soc.request.abort(); } catch(e2) {} soc.error = soc.errno.NETWORKERROR; } soc.callbackHandler(); return true; } soc.timeoutTimer = setTimeout(function() { soc.timeoutHandler() }, timeoutDelay); } } Terminal.prototype._defaultServerCallback = function() { if (this.socket.success) { // output im more-mode this.write('Server Response:\ %n'+this.socket.responseText, true); } else { var s='Request failed: '+this.socket.status+' '+this.socket.statusText; if (this.socket.errno) s+='\ %n'+this.socket.errstring; this.write(s); this.prompt(); } } } // eof
(C) Æliens 04/09/2009
You may not copy or print any of this material without explicit permission of the author or the publisher. In case of other copyright issues, contact the author.