source: trip-planner-front/node_modules/sockjs-client/lib/transport/receiver/jsonp.js@ ceaed42

Last change on this file since ceaed42 was 6a3a178, checked in by Ema <ema_spirova@…>, 3 years ago

initial commit

  • Property mode set to 100644
File size: 5.4 KB
Line 
1'use strict';
2
3var 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
11var debug = function() {};
12if (process.env.NODE_ENV !== 'production') {
13 debug = require('debug')('sockjs-client:receiver:jsonp');
14}
15
16function 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
36inherits(JsonpReceiver, EventEmitter);
37
38JsonpReceiver.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
47JsonpReceiver.timeout = 35000;
48JsonpReceiver.scriptErrorTimeout = 1000;
49
50JsonpReceiver.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
66JsonpReceiver.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
74JsonpReceiver.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
93JsonpReceiver.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
107JsonpReceiver.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
183module.exports = JsonpReceiver;
Note: See TracBrowser for help on using the repository browser.