a removeChild block opera on iframe stream, removed
[brisk.git] / web / xynt-streaming.js
1 // old targetpage == page and moved into start method
2
3 //
4 // CLASS transport_xhr
5 //
6 function transport_xhr(doc, xynt_streaming, page)
7 {
8     this.doc = doc;
9     this.xynt_streaming = xynt_streaming;
10     this.xhr = createXMLHttpRequest();
11     this.xhr.open('GET', page);
12
13     var self = this;
14     this.xhr.onreadystatechange = function () { self.xhr_cb(); };
15     this.xhr.send(null);
16
17     this.stopped = false;
18 }
19
20 transport_xhr.prototype = {
21     doc: null,
22     xynt_streaming: "ready",
23     xhr: null,
24     stopped: true,
25
26     ctx_old: "",
27     ctx_old_len: 0,
28     ctx_new: null,
29
30     // script_clean: 0,
31
32     destroy: function () { /* public */
33         if (this.xhr != null) {
34             this.xhr_abort();
35         }
36         delete this.xhr;
37     },
38
39     xhr_cb: function () {
40         var ret;
41
42         if (this.xhr.readyState == 4) {
43             // console.log("SS: "+safestatus(xhr));
44
45             // NOTE: delay management later
46             // try {
47             //     if ((ret = safestatus(this.xhr)) == 200) {
48             //         this.delay = 0;
49             //         // console.log("del a null "+this.delayed);
50             //     } else if (ret != -1) {
51             //         this.delay = 5000;
52             //         this.hbit('X');
53             //         // alert('There was a problem with the request.' + ret);
54             //     }
55             // } catch(b) {};
56
57             // this.delayed = null;
58             this.stopped = true;
59         }
60     },
61
62     xhr_abort: function() {
63         if (this.xhr != null) {
64             this.xhr.abort();
65         }
66     },
67
68     xstr_is_init: function () { /* public */
69         try {
70             if (this.xhr.responseText != null) {
71                 this.ctx_new = this.xhr.responseText;
72             }
73         }
74         catch (e) {
75         }
76
77         return (this.ctx_new != null);
78     },
79
80     /* only after a successfull is_initialized call */
81     xstr_is_ready: function () { /* public */
82         return (this.xynt_streaming == "ready");
83     },
84
85     xstr_set: function () { /* public */
86         // already set
87     },
88
89     ctx_new_is_set: function () { /* public */
90         return (this.ctx_new != null);
91     },
92
93     ctx_new_curlen_get: function () { /* public */
94         return (this.ctx_new.length);
95     },
96
97     ctx_new_getchar: function(idx) { /* public */
98     },
99
100     ctx_old_len_is_set: function () { /* public */
101         return (true);
102     },
103
104     ctx_old_len_get: function () { /* public */
105         return (this.ctx_old_len);
106     },
107
108     ctx_old_len_set: function (len) { /* public */
109         this.ctx_old_len = len;
110     },
111
112     ctx_old_len_add: function (len) { /* public */
113         this.ctx_old_len += len;
114     },
115
116     new_part: function () { /* public */
117         return (this.ctx_new.substr(this.ctx_old_len));
118     },
119
120     scrcls_set: function (step) { /* public */
121         // this.script_clean = step;
122     },
123
124     postproc: function () {
125         if (this.stopped && !this.xstr_is_ready()) {
126             this.xynt_streaming.reload();
127         }
128     }
129 }
130
131 //
132 // CLASS transport_htmlfile
133 //
134 function transport_htmlfile(doc, xynt_streaming, page)
135 {
136     this.doc = doc;
137     this.xynt_streaming = xynt_streaming;
138     this.transfdoc = new ActiveXObject("htmlfile");
139     this.transfdoc.open();
140     /*this.transfdoc.write("<html><head><script>");
141     this.transfdoc.write("document.domain=\""+(doc.domain)+"\";");
142     this.transfdoc.write("</"+"script></"+"head>"); */
143     this.transfdoc.write("<html><body><iframe id='iframe'></iframe></body></html>");
144     this.transfdoc.close();
145
146     this.ifra = this.transfdoc.getElementById("iframe");
147     this.ifra.contentWindow.location.href = page;
148 }
149
150 transport_htmlfile.prototype = {
151     doc: null,
152     xynt_streaming: null,
153     ifra: null,
154     tradoc: null,
155
156     destroy: function () { /* public */
157         if (this.ifra != null) {
158         //     this.doc.body.removeChild(this.ifra);
159         //     delete this.ifra;
160              this.ifra = null;
161         }
162
163         if (this.transfdoc) {
164             delete this.transfdoc;
165             this.transfdoc = null;
166         }
167     },
168
169     xstr_is_init: function () { /* public */
170         return (typeof(this.ifra.contentWindow.xynt_streaming) != 'undefined');
171     },
172
173     /* only after a successfull is_initialized call */
174     xstr_set: function () { /* public */
175         if (this.ifra.contentWindow.xynt_streaming == "ready") {
176             this.ifra.contentWindow.xynt_streaming = this.xynt_streaming;
177             return (true);
178         }
179         else if (this.ifra.contentWindow.xynt_streaming == this.xynt_streaming) {
180             return (true);
181         }
182         else {
183             return (false);
184         }
185     },
186
187     ctx_new_is_set: function () { /* public */
188         return (typeof(this.ifra.contentWindow.ctx_new) != 'undefined');
189     },
190
191     ctx_new_curlen_get: function () { /* public */
192         return (this.ifra.contentWindow.ctx_new.length);
193     },
194
195     ctx_new_getchar: function(idx) { /* public */
196     },
197
198     ctx_old_len_is_set: function () { /* public */
199         return (typeof(this.ifra.contentWindow.ctx_old_len) != 'undefined');
200     },
201
202     ctx_old_len_get: function () { /* public */
203         return (this.ifra.contentWindow.ctx_old_len);
204     },
205
206     ctx_old_len_set: function (len) { /* public */
207         this.ifra.contentWindow.ctx_old_len = len;
208     },
209
210     ctx_old_len_add: function (len) { /* public */
211         this.ifra.contentWindow.ctx_old_len += len;
212     },
213
214     new_part: function () { /* public */
215         return (this.ifra.contentWindow.ctx_new.substr(this.ifra.contentWindow.ctx_old_len));
216     },
217
218     scrcls_set: function (step) { /* public */
219         this.ifra.contentWindow.script_clean = step;
220     },
221
222     postproc: function () {
223     }
224 }
225
226
227
228 //
229 // CLASS transport_iframe
230 //
231 function transport_iframe(doc, xynt_streaming, page)
232 {
233     this.doc = doc;
234     this.xynt_streaming = xynt_streaming;
235     this.ifra = doc.createElement("iframe");
236     this.ifra.style.visibility = "hidden";
237     doc.body.appendChild(this.ifra);
238     this.ifra.contentWindow.location.href = page;
239 }
240
241 transport_iframe.prototype = {
242     doc: null,
243     xynt_streaming: null,
244     ifra: null,
245
246     destroy: function () { /* public */
247         try {
248             if (this.ifra != null) {
249                 // FIXME: with opera on win this remove child crash js so is
250                 //        commented
251                 // this.doc.body.removeChild(this.ifra);
252                 delete this.ifra;
253                 this.ifra = null;
254             }
255         } catch (b) {
256             alert("catched");
257         }
258     },
259
260     xstr_is_init: function () { /* public */
261         return (typeof(this.ifra.contentWindow.xynt_streaming) != 'undefined');
262     },
263
264     /* only after a successfull is_initialized call */
265     xstr_is_ready: function () { /* public */
266         return (this.ifra.contentWindow.xynt_streaming == "ready");
267     },
268
269     /* only after a successfull is_initialized call */
270     xstr_set: function () { /* public */
271         if (this.ifra.contentWindow.xynt_streaming == "ready") {
272             this.ifra.contentWindow.xynt_streaming = this.xynt_streaming;
273             return (true);
274         }
275         else if (this.ifra.contentWindow.xynt_streaming == this.xynt_streaming) {
276             return (true);
277         }
278         else {
279             return (false);
280         }
281     },
282
283
284     /* only after a successfull is_ready call to be sure the accessibility of the var */
285     xstr_set_old: function (xynt_streaming) { /* public */
286         this.ifra.contentWindow.xynt_streaming = xynt_streaming;
287     },
288
289     ctx_new_is_set: function () { /* public */
290         return (typeof(this.ifra.contentWindow.ctx_new) != 'undefined');
291     },
292
293     ctx_new_curlen_get: function () { /* public */
294         return (this.ifra.contentWindow.ctx_new.length);
295     },
296
297     ctx_new_getchar: function(idx) { /* public */
298     },
299
300     ctx_old_len_is_set: function () { /* public */
301         return (typeof(this.ifra.contentWindow.ctx_old_len) != 'undefined');
302     },
303
304     ctx_old_len_get: function () { /* public */
305         return (this.ifra.contentWindow.ctx_old_len);
306     },
307
308     ctx_old_len_set: function (len) { /* public */
309         this.ifra.contentWindow.ctx_old_len = len;
310     },
311
312     ctx_old_len_add: function (len) { /* public */
313         this.ifra.contentWindow.ctx_old_len += len;
314     },
315
316     new_part: function () { /* public */
317         return (this.ifra.contentWindow.ctx_new.substr(this.ifra.contentWindow.ctx_old_len));
318     },
319
320     scrcls_set: function (step) { /* public */
321         this.ifra.contentWindow.script_clean = step;
322     },
323
324     postproc: function () {
325     }
326 }
327
328 function xynt_streaming(win, transp_type, console, gst, from, cookiename, sess, sandbox, page, cmdproc)
329 {
330     this.win = win;
331     this.transp_type = transp_type;
332     this.console = console;
333     this.gst = gst;
334     this.from = from;
335     this.cookiename = cookiename;
336     this.sess = sess;
337     this.sandbox = sandbox;
338     this.page = page;
339     this.cmdproc = cmdproc;
340     // this.cmdproc = function(com){/* console.log("COM: "+com); */ eval(com);}
341
342     this.doc = win.document;
343     this.keepalive_old = -1;
344     this.keepalive_new = -1;
345 }
346
347 xynt_streaming.prototype = {
348     win:               null,
349     transp_type:       null,
350     transp:            null,
351     console:           null,
352     gst:               null,
353     from:              null,
354     cookiename:        null,
355     sess:              null,
356     sandbox:           null,
357     page:              null,
358     cmdproc:           null,
359
360     doc:               null,
361     cookiepath: "/brisk/",
362     watchdog_hdl:      null,
363     hbit:              null,
364     keepalive_old:    -1,
365     keepalive_new:    -1,
366     keepalives_equal:  0,
367     /* NOTE: right watch_timeout value to 100, for devel reasons use 1000 or more */
368     /* restart after  3 * 40 * 100 millisec if server ping is missing => 12secs */
369     keepalives_eq_max: 3,
370     watchdog_checktm:  40,
371     // FIXME watchdog_timeout:  100,
372     watchdog_timeout:  100,
373     watchdog_ct:       0,
374     watchable:         false,
375     restart_n:         0,
376     comm_match:        /_*@BEGIN@(.*?)@END@/g, 
377     comm_clean:        /_*@BEGIN@(.*?)@END@/,
378     stream:            "",
379     the_end:           false,
380
381     start: function() { /* public */
382         if (this.the_end) 
383             return;
384
385         createCookie(this.cookiename, sess, 24*365, this.cookiepath);
386         // alert("start");
387         this.log("xynt_streaming:start restart: "+this.restart_n);
388         this.keepalives_equal = 0;
389
390         // page arrangement
391         this.page = url_complete(this.win.location.href, this.page);
392         // stat, subst, this.gst.st
393
394         this.page = url_append_args(this.page, "sess", this.sess, "stat", stat, "subst", subst, "step", this.gst.st, "from", this.from);
395         this.log(this.page);
396
397         // transport instantiation
398         if (this.transp_type == "xhr") {
399             this.page = url_append_args(this.page, "transp", "xhr");
400             this.transp = new transport_xhr(this.doc, this, this.page);
401         }
402         else if (this.transp_type == "iframe") {
403             this.page = url_append_args(this.page, "transp", "iframe");
404             this.transp = new transport_iframe(this.doc, this, this.page);
405         }
406         else if (this.transp_type == "htmlfile") {
407             this.page = url_append_args(this.page, "transp", "htmlfile");
408             this.transp = new transport_htmlfile(this.doc, this, this.page);
409         }
410         else
411             return;
412
413         // watchdog setting
414         this.watchdog_ct  = 0;
415         if (!this.the_end) {
416             this.watchdog_hdl = setTimeout(function(obj) { obj.log("tout1"); obj.watchdog(); }, this.watchdog_timeout, this);
417         }
418     },
419
420     stop: function() {
421         this.the_end = true;
422         this.abort();
423     },
424
425     hbit_set: function (hbit) {
426         this.hbit = hbit;
427     },
428
429     watchdog: function () {
430         // alert("watchdog");
431         var i, again;
432         var comm_newpart, comm_len, comm_arr;
433         var ctx_new_len;
434
435         if (this.sandbox != null) {
436             // from old: var zug = "POLL sess = "+sess+" stat = "+stat+" subst = "+subst+" step = "+this.gst.st+" step_loc = "+this.gst.st_loc+" step_loc_new = "+this.gst.st_loc_new+" STOP: "+this.stopped;
437             var zug = "WATCHDOG  sess = ["+this.sess+"]  step = "+this.gst.st+" step_loc = "+this.gst.st_loc+" step_loc_new = "+this.gst.st_loc_new;          
438             if (zug != this.sandbox.innerHTML)
439                 this.sandbox.innerHTML = zug;
440         }
441
442         // WATCHDOGING THE CONNECTION
443         this.log("hs::watchdog: start, cur equal times: "+this.keepalives_equal);
444         if (!this.watchable) {
445             do {
446                 try{
447                     // if (typeof(this.ifra.contentWindow.xynt_streaming) == 'undefined')
448                     if (!this.transp.xstr_is_init()) {
449                         this.log("hs::watchdog: xstr_is_init = false");
450                         break;
451                     }
452                 }
453                 catch(b) {
454                     this.log("hs::watchdog: exception");
455                     break;
456                 }
457
458                 /*
459                   on IE7 the the window frame scope is cleaned after the href is set, so we wait 
460                   for a well know variable value before assign this object value to it (OO is a passion)
461                 */
462                 // if (this.ifra.contentWindow.xynt_streaming == "ready") {
463                 if (this.transp.xstr_set()) {
464                     // this.ifra.contentWindow.xynt_streaming = this;
465                     this.watchable = true;
466                     this.watchdog_ct = 0;
467                     this.log("hs::watchdog: watchable = yes");
468                 }
469             } while (false);
470         }
471         if ( (this.watchdog_ct % this.watchdog_checktm) == 0) {
472             this.log("hs::watchdog: this.keepalive_old: "+this.keepalive_old+" this.keepalive_new: "+this.keepalive_new);
473             if (this.keepalive_old == this.keepalive_new) {
474                 this.keepalives_equal++;
475             }
476             else {
477                 this.keepalive_old = this.keepalive_new;
478                 this.keepalives_equal = 0;
479             }
480             
481             if (this.keepalives_equal > this.keepalives_eq_max) {
482                 this.log("hs::watchdog: MAX ACHIEVED "+this.keepalives_equal);
483                 this.reload();
484                 // alert("watchdog return reload");
485                 return;
486             }
487         }
488
489         // PICK COMMANDS FROM STREAM
490         do {
491             // alert("do--while begin ["+again+"]");
492             // CHECK: maybe again here isn't needed 
493             again = 0;
494             try {
495                 /* if (typeof(this.ifra.contentWindow.ctx_new)     == 'undefined' ||
496                    typeof(this.ifra.contentWindow.ctx_old_len) == 'undefined') */
497                 if (!this.transp.ctx_new_is_set() || !this.transp.ctx_old_len_is_set())
498                     break;
499             }
500             catch(b) {
501                 break;
502             }
503
504             // ctx_new_len = this.ifra.contentWindow.ctx_new.length;
505             ctx_new_len = this.transp.ctx_new_curlen_get();
506             // if (ctx_new_len <= this.ifra.contentWindow.ctx_old_len) {
507             if (ctx_new_len <= this.transp.ctx_old_len_get()) {
508                 break;
509             }
510             this.log("new: "+ ctx_new_len + "  old: "+this.transp.ctx_old_len_get());
511             this.keepalive_new++;
512             // alert("pre-loop 1");
513             for (i = this.transp.ctx_old_len_get() ; i < ctx_new_len ; i++) {
514                 // if (this.ifra.contentWindow.ctx_new.charAt(i) != '_') {
515                 if (this.transp.ctx_new_getchar(i) != '_') {
516                     // this.log("ctx_new.char(i) != '_' ["+this.ifra.contentWindow.ctx_new.charAt(i)+"]");
517                     break;
518                 }
519                 // else {
520                 //     this.log("ctx_new.charAt(i) == '_'");
521                 // }
522             }
523             // this.ifra.contentWindow.ctx_old_len = i;
524             this.transp.ctx_old_len_set(i);
525             if (i == ctx_new_len) {
526                 this.log("old_len == i");
527                 break;
528             }
529             else {
530                 this.log("old_len != i: "+i);
531             }
532             // alert("do--while middle ["+this.ifra.contentWindow.ctx_old_len+"]");
533
534             comm_newpart = this.transp.new_part();
535             this.log("COM_NEWPART: ["+comm_newpart+"]");
536             comm_len = 0;
537             comm_arr = comm_newpart.match(this.comm_match);
538
539             // alert("do--while middle2 ["+again+"]");
540             if (comm_arr) {
541                 var comm_arr_len = comm_arr.length;
542                 for (i = 0 ; i < comm_arr_len ; i++) {
543                     var temp = comm_arr[i].replace(this.comm_clean,"$1").split("|");
544                     this.gst.comms = this.gst.comms.concat(temp);
545                     comm_len += comm_arr[i].length;
546                 }
547                 again = 1;
548             }
549             // this.ifra.contentWindow.ctx_old_len += comm_len;
550             this.transp.ctx_old_len_add(comm_len);
551             // this.ifra.contentWindow.script_clean = this.gst.st;
552             this.transp.scrcls_set(this.gst.st);
553             // alert("do--while end ["+again+"]");
554         } while (again);
555
556         // alert("post while");
557         // EXECUTION OF STREAM COMMANDS
558         do {
559             again = 0;
560             //MOP ?? xhrrestart = 0;
561             if (this.gst.st_loc < this.gst.st_loc_new) {
562                 // there is some slow actions running
563                 break;
564             }
565             else if (this.gst.comms.length > 0) {
566                 var singlecomm;
567                 
568                 singlecomm = this.gst.comms.shift();
569                 // alert("EXE"+gugu);
570                 // $("xhrdeltalog").innerHTML = "EVALL: "+singlecomm.replace("<", "&lt;", "g"); +"<br>";
571                 //xx this.hbit("+");
572
573                 // alert("SINGLE: ["+singlecomm+"]");
574                 this.cmdproc(singlecomm);
575                 again = 1;
576             }
577         } while (again);
578         this.watchdog_ct++;
579         if (!this.the_end) {
580             this.transp.postproc();
581             this.watchdog_hdl = setTimeout(function(obj) { /* obj.log("tout2"); */ obj.watchdog(); }, this.watchdog_timeout, this);
582         }
583         // alert("watchdog return normal");
584
585         return;
586     },
587
588     //
589     // moved to xynt-streaming-ifra as push()
590     //
591     // keepalive: function (s) {
592     //     this.log("hs::keepalive");
593     //     if (s != null) {
594     //         this.log(s);
595     //         this.ifra.contentWindow.ctx_new += "@BEGIN@"+s+"@END@";
596     //     }
597     //     else {
598     //         this.ifra.contentWindow.ctx_new += "_";
599     //     }
600     //     // this.keepalive_new++;
601     // },
602
603     abort: function () { /* public */
604         // this.log("PATH: "+this.ifra.contentWindow.location.protocol + "://" + this.ifra.contentWindow.location.host + "/" + this.ifra.contentWindow.location.pathname);
605
606         this.gst.abort();
607         if (this.watchdog_hdl != null) {
608             clearTimeout(this.watchdog_hdl);
609             this.watchdog_hdl = null;
610         }
611
612         this.restart_n++;
613         this.log("hs::reload");
614         this.watchable = false;
615         if (this.transp != null) {
616             this.transp.destroy();
617             delete this.transp;
618             this.transp = null;
619         }
620     },
621
622     reload: function () {
623         this.abort();
624         this.start(null);
625     },
626
627     log: function (s) {
628         if (this.console != null) {
629             return (this.console.log(s));
630         }
631     }
632 }