github.com/insionng/yougam@v0.0.0-20170714101924-2bc18d833463/themes/wind/static/libs/sockjs-client-1.1.0/lib/transport/receiver/jsonp.js (about) 1 'use strict'; 2 3 var utils = require('../../utils/iframe') 4 , random = require('../../utils/random') 5 , browser = require('../../utils/browser') 6 , urlUtils = require('../../utils/url') 7 , inherits = require('inherits') 8 , EventEmitter = require('events').EventEmitter 9 ; 10 11 var debug = function() {}; 12 if (process.env.NODE_ENV !== 'production') { 13 debug = require('debug')('sockjs-client:receiver:jsonp'); 14 } 15 16 function JsonpReceiver(url) { 17 debug(url); 18 var self = this; 19 EventEmitter.call(this); 20 21 utils.polluteGlobalNamespace(); 22 23 this.id = 'a' + random.string(6); 24 var urlWithId = urlUtils.addQuery(url, 'c=' + encodeURIComponent(utils.WPrefix + '.' + this.id)); 25 26 global[utils.WPrefix][this.id] = this._callback.bind(this); 27 this._createScript(urlWithId); 28 29 // Fallback mostly for Konqueror - stupid timer, 35 seconds shall be plenty. 30 this.timeoutId = setTimeout(function() { 31 debug('timeout'); 32 self._abort(new Error('JSONP script loaded abnormally (timeout)')); 33 }, JsonpReceiver.timeout); 34 } 35 36 inherits(JsonpReceiver, EventEmitter); 37 38 JsonpReceiver.prototype.abort = function() { 39 debug('abort'); 40 if (global[utils.WPrefix][this.id]) { 41 var err = new Error('JSONP user aborted read'); 42 err.code = 1000; 43 this._abort(err); 44 } 45 }; 46 47 JsonpReceiver.timeout = 35000; 48 JsonpReceiver.scriptErrorTimeout = 1000; 49 50 JsonpReceiver.prototype._callback = function(data) { 51 debug('_callback', data); 52 this._cleanup(); 53 54 if (this.aborting) { 55 return; 56 } 57 58 if (data) { 59 debug('message', data); 60 this.emit('message', data); 61 } 62 this.emit('close', null, 'network'); 63 this.removeAllListeners(); 64 }; 65 66 JsonpReceiver.prototype._abort = function(err) { 67 debug('_abort', err); 68 this._cleanup(); 69 this.aborting = true; 70 this.emit('close', err.code, err.message); 71 this.removeAllListeners(); 72 }; 73 74 JsonpReceiver.prototype._cleanup = function() { 75 debug('_cleanup'); 76 clearTimeout(this.timeoutId); 77 if (this.script2) { 78 this.script2.parentNode.removeChild(this.script2); 79 this.script2 = null; 80 } 81 if (this.script) { 82 var script = this.script; 83 // Unfortunately, you can't really abort script loading of 84 // the script. 85 script.parentNode.removeChild(script); 86 script.onreadystatechange = script.onerror = 87 script.onload = script.onclick = null; 88 this.script = null; 89 } 90 delete global[utils.WPrefix][this.id]; 91 }; 92 93 JsonpReceiver.prototype._scriptError = function() { 94 debug('_scriptError'); 95 var self = this; 96 if (this.errorTimer) { 97 return; 98 } 99 100 this.errorTimer = setTimeout(function() { 101 if (!self.loadedOkay) { 102 self._abort(new Error('JSONP script loaded abnormally (onerror)')); 103 } 104 }, JsonpReceiver.scriptErrorTimeout); 105 }; 106 107 JsonpReceiver.prototype._createScript = function(url) { 108 debug('_createScript', url); 109 var self = this; 110 var script = this.script = global.document.createElement('script'); 111 var script2; // Opera synchronous load trick. 112 113 script.id = 'a' + random.string(8); 114 script.src = url; 115 script.type = 'text/javascript'; 116 script.charset = 'UTF-8'; 117 script.onerror = this._scriptError.bind(this); 118 script.onload = function() { 119 debug('onload'); 120 self._abort(new Error('JSONP script loaded abnormally (onload)')); 121 }; 122 123 // IE9 fires 'error' event after onreadystatechange or before, in random order. 124 // Use loadedOkay to determine if actually errored 125 script.onreadystatechange = function() { 126 debug('onreadystatechange', script.readyState); 127 if (/loaded|closed/.test(script.readyState)) { 128 if (script && script.htmlFor && script.onclick) { 129 self.loadedOkay = true; 130 try { 131 // In IE, actually execute the script. 132 script.onclick(); 133 } catch (x) { 134 // intentionally empty 135 } 136 } 137 if (script) { 138 self._abort(new Error('JSONP script loaded abnormally (onreadystatechange)')); 139 } 140 } 141 }; 142 // IE: event/htmlFor/onclick trick. 143 // One can't rely on proper order for onreadystatechange. In order to 144 // make sure, set a 'htmlFor' and 'event' properties, so that 145 // script code will be installed as 'onclick' handler for the 146 // script object. Later, onreadystatechange, manually execute this 147 // code. FF and Chrome doesn't work with 'event' and 'htmlFor' 148 // set. For reference see: 149 // http://jaubourg.net/2010/07/loading-script-as-onclick-handler-of.html 150 // Also, read on that about script ordering: 151 // http://wiki.whatwg.org/wiki/Dynamic_Script_Execution_Order 152 if (typeof script.async === 'undefined' && global.document.attachEvent) { 153 // According to mozilla docs, in recent browsers script.async defaults 154 // to 'true', so we may use it to detect a good browser: 155 // https://developer.mozilla.org/en/HTML/Element/script 156 if (!browser.isOpera()) { 157 // Naively assume we're in IE 158 try { 159 script.htmlFor = script.id; 160 script.event = 'onclick'; 161 } catch (x) { 162 // intentionally empty 163 } 164 script.async = true; 165 } else { 166 // Opera, second sync script hack 167 script2 = this.script2 = global.document.createElement('script'); 168 script2.text = "try{var a = document.getElementById('" + script.id + "'); if(a)a.onerror();}catch(x){};"; 169 script.async = script2.async = false; 170 } 171 } 172 if (typeof script.async !== 'undefined') { 173 script.async = true; 174 } 175 176 var head = global.document.getElementsByTagName('head')[0]; 177 head.insertBefore(script, head.firstChild); 178 if (script2) { 179 head.insertBefore(script2, head.firstChild); 180 } 181 }; 182 183 module.exports = JsonpReceiver;