initial commit
[namibia] / public / js / vendor / ape-source / Transport / Transport.XHRStreaming.js
1 Request.XHRStreaming = new Class({
2
3         Extends: Request,
4
5         lastTextLength: 0,
6         read: 0, //Contain the amout of data read
7
8         send: function(options) {
9                 //mootools set onreadystatechange after xhr.open. In webkit, this cause readyState 1 to be never fired
10                 if (Browser.Engine.webkit) this.xhr.onreadystatechange = this.onStateChange.bind(this);
11                 return this.parent(options);
12         },
13
14         onStateChange: function() {
15                 if (this.xhr.readyState == 1) this.dataSent = true;
16                 else if (this.xhr.readyState == 3) this.progress(this.xhr.responseText, this.xhr.responseXML);
17                 this.parent();
18         },
19
20         onProgress: function(){
21                 this.fireEvent('progress', arguments);
22         },
23
24         progress: function(text, xml){
25                 var length = text.length;
26                 this.read += length;
27                 text = text.substr(this.lastTextLength);
28                 this.lastTextLength = length;
29                 this.onProgress(this.processScripts(text), xml);
30         }
31 });
32 APE.Transport.XHRStreaming = new Class({
33         
34         maxRequestSize: 100000,
35
36         Implements: APE.Request.SSE,
37
38         initialize: function(ape){ 
39                 this.ape = ape;
40                 this.requestFailObserver = [];
41
42                 //If browser support servent sent event, switch to SSE / XHR transport 
43                 if (this.SSESupport) this.ape.options.transport = 4;
44
45                 this.streamInfo = {
46                         timeoutObserver: null,
47                         cleanClose: false,
48                         forceClose: false,
49                         callback: null
50                 }
51         },
52
53         send: function(queryString, options) {
54                 if (this.SSESupport && !this.eventSource) {
55                         this.initSSE(queryString, options, this.readSSE.bind(this));
56                         if (options.requestCallback) this.streamInfo.callback = options.requestCallback;
57                 } else {
58                         if ((!this.streamRequest || !this.streamRequest.running) && !this.eventSource) { //Only one XHRstreaming request is allowed
59                                 this.buffer = '';
60                                 this.request = this.doRequest(queryString, options);
61
62                                 if (options.requestCallback) this.streamInfo.callback = options.requestCallback;
63                         } else { //Simple XHR request
64                                 var request = new Request({
65                                         url: this.ape.serverUri,
66                                         onFailure: this.ape.requestFail.bind(this.ape, [-2, this]),
67                                         onComplete: function(resp) {
68                                                 $clear(this.requestFailObserver.shift());
69                                                 this.request.dataSent = true;//In the case of XHRStreaming. Request are imediatly close.
70                                                 this.ape.parseResponse(resp, options.callback);
71                                         }.bind(this)
72                                 }).send(queryString);
73                                 this.request = request;
74
75                                 //set up an observer to detect request timeout
76                                 this.requestFailObserver.push(this.ape.requestFail.delay(this.ape.options.pollTime + 10000, this.ape, [1, request]));
77
78                         }
79
80                         return this.request;
81                 }
82         },
83
84         doRequest: function(queryString, options) {
85                 this.streamInfo.forceClose = false;
86
87                 var request = new Request.XHRStreaming({
88                         url: this.ape.serverUri,
89                         onProgress: this.readFragment.bindWithEvent(this),
90                         onFailure: this.ape.requestFail.bind(this.ape, [-2, this]),
91                         onComplete: function(resp) {
92                                 $clear(this.streamInfo.timeoutObserver);
93                                 if (this.ape.status > 0) {
94                                         if (this.streamInfo.cleanClose) this.ape.check();
95                                         else this.newStream();
96                                         this.streamInfo.cleanClose = false;
97                                 }
98                         }.bind(this)
99                 }).send(queryString);
100                 
101                 request.id = $time();
102                 this.streamRequest = request;
103                 
104                 //this should no longer exist
105                 //this.streamInfo.timeoutObserver = (function() {
106                 //      this.streamInfo.forceClose = true;
107                 //      //try to imediatly close stream
108                 //      if (this.checkStream()) this.newStream();
109                 //}).delay(1000*60, this);
110
111                 return request;
112         },
113
114         readSSE: function(data) {
115                 this.ape.parseResponse(data, this.streamInfo.callback);
116                 this.streamInfo.callback = null;
117         },
118
119         readFragment: function(text){
120                 this.streamInfo.canClose = false;
121
122                 if (text == '') {
123
124                         this.streamInfo.canClose = true;
125                         this.streamInfo.cleanClose = true;
126                         this.ape.parseResponse(text, this.streamInfo.callback);
127
128                         this.streamInfo.callback = null;
129                 } else {
130                         text = this.buffer + text;
131                         var group = text.split("\n\n");
132                         var length = group.length;
133                         
134                         // If group.length is gretter than 1 the fragment received complete last RAW or contains more than one RAW
135                         if (group.length > 1) {         
136                                 //Clear buffer
137                                 this.buffer = '';
138                                 
139                                 for (var i = 0; i < length-1; i++) { 
140                                         this.ape.parseResponse(group[i], this.streamInfo.callback);
141                                 }
142
143                                 if (group[length-1] !== '') { //Last group complete last received raw but it's not finish
144                                         this.buffer += group[length-1];
145                                 } else { //Received fragment is complete
146                                         this.streamInfo.canClose = true;
147                                         if (this.checkStream()) this.newStream();
148                                 }
149
150                                 //Delete callback
151                                 this.streamInfo.callback = null;
152                         } else {//Fragement received is a part of a raw 
153                                 this.buffer = text; 
154                         }
155                 }
156         },
157         
158         running: function() {
159                 return (this.streamRequest && this.streamRequest.running) ? true : this.eventSource ? true : false;
160         },      
161
162         checkStream: function() {
163                 return (this.streamInfo.forceClose && this.streamInfo.canClose) || (this.streamRequest && this.streamRequest.read >= this.maxRequestSize && this.streamInfo.canClose);
164         },
165
166         newStream: function() {
167 //              this.ape.request.send('CLOSE');//This will close the stream request
168                 $clear(this.streamInfo.timeoutObserver);
169                 this.streamRequest.cancel();
170                 this.ape.check();
171         },
172
173         cancel: function(){
174                 if (this.request) this.request.cancel();
175
176                 $clear(this.streamInfo.timeoutObserver);
177                 $clear(this.requestFailObserver.shift());
178         }
179 });
180 APE.Transport.XHRStreaming.browserSupport = function() {
181         if (Browser.Features.xhr && (Browser.Engine.webkit || Browser.Engine.gecko)) {
182                 return true;
183                 /* Not yet 
184                 if (Browser.Engine.presto && ((typeof window.addEventStream) == 'function')) return true;
185                 else if (window.XDomainRequest) return true;
186                 else return Browser.Engine.trident ? 0 : true;
187                 */
188         } else if (Browser.Features.xhr) return 0;//No XHRStreaming support switch to long polling
189         else return 2;//No XHR Support, switch to JSONP
190 }
191