BrowserView.js
[app.webkitpdf] / BrowserView.js
1 Gtk = imports.gi.Gtk;
2 GLib = imports.gi.GLib;
3 WebKit = imports.gi.WebKit;
4
5 TabbedBrowser = imports.TabbedBrowser;
6 BrowserSettings = imports.BrowserSettings;
7 BrowserTab = imports.BrowserTab;
8
9 File = imports.File.File;
10
11 base64 = imports.base64.base64;
12
13 BrowserView = new GType({
14     parent: WebKit.WebView.type,
15     name: "BrowserView",
16     init: function ()
17     {
18         // Private
19         
20         
21         var _t = this;
22         
23         var tab = BrowserTab;
24         var browsePage = false;
25         var maxQueue = 0;
26         var injected = {};
27         
28         var current_url = '';
29  
30         var update_title = function (web_view, web_frame, title)
31         {
32             
33             print("calling update title");
34             if(title.length > 25)
35                 title = title.slice(0,25) + "...";
36
37             tab.get_tab_label().label = title;
38         };
39         
40         
41         
42            
43         
44         var traversedom = function(doc, fn, sub ) {
45             //print("TRAVERSE DOM?");
46             sub = sub || 0;
47             
48             var ret = '<HTML>';
49             
50             var cb =  function(s) {
51                 //print("CB:" + s);
52                 ret+=s;
53             };
54             cb.fn = fn;
55             cb.sub = sub +1;
56             print(doc);
57             print(doc.head);
58             print (doc.body);
59             
60              //Roo.select('body > div',true).each(function(el) {
61             traverseDOMTree(cb, doc.head, 1);
62             traverseDOMTree(cb, doc.body, 1);
63            //print(ret);   
64             File.write(cb.fn.replace(/\.html$/, '')+ (sub ? ('.' + sub  ) : '') + '.html' , ret +'</HTML>');
65         
66         };
67          
68         
69         
70         var traverseDOMTree = function(cb, currentElement, depth) {
71             if (currentElement) {
72                 
73                 //if (currentElement.class_name.match(/roo-dynamic/)) {
74                 //    return;
75                 //}
76                 //print(currentElement.node_name);
77                 var j;
78                 var nodeName = currentElement.node_name;
79                 var tagName = currentElement.tag_name;
80                 
81                 if  (nodeName == '#text') {
82                     cb(currentElement.node_value);
83                     return;
84                 
85                 }
86                 if(nodeName == 'BR'){
87                     cb("<BR/>");
88                     return;
89                 }
90                
91                 if (nodeName == 'SCRIPT') {
92                      
93                     return;
94                 }
95                 //if (nodeName == 'STYLE') {  return; }
96                 var i = 0;
97               // Prints the node tagName, such as <A>, <IMG>, etc
98                 var outNodeName = nodeName;
99                 if (nodeName == 'IFRAME') {
100                     //outNodeName  = 'DIV';
101                 }
102                 if (tagName) {
103                     
104                     
105                     
106                     
107                     var attr = [];
108                     
109                     for(i = 0; i < currentElement.attributes.length;i++) {
110                         var aname = currentElement.attributes.item(i).name;
111                         //if (aname =='class' || aname == 'style') {
112                         //    continue;
113                         //}
114                         if (aname =='src' && tagName == 'IFRAME') {
115                             continue;
116                         }
117                         
118                         attr.push(aname + '="' + currentElement.attributes.item(i).value + '"' );
119                     }
120                     if (tagName == 'IFRAME') {
121                         attr.push('src="' + File.basename(cb.fn).replace(/\.html$/, '')+ '.' + cb.sub + '.html"' );
122                     }
123                     
124                     //if (nodeName == 'IFRAME') {
125                     //    attr.push('src="' + currentElement.attributes.item(i).value + embeded_file '"' );
126                     //}
127                     
128                     //var style = elClassToStyle(currentElement);
129                     //if (style.length) {
130                     //    attr.push('style="' + style + '"' );
131                     //}
132                     
133                     
134                     //if (depth > 1000 && (tagName == 'BODY' || tagName == 'HEAD' )) {
135                      //   cb("<DIV"+ ( attr.length ? (' ' + attr.join(' ') ) : '') + ">");
136                     //} else {
137                         cb("<"+outNodeName + ( attr.length ? (' ' + attr.join(' ') ) : '') + ">");
138                         
139                     //}
140                 } 
141                 else {
142                   cb("[unknown tag]");
143                 }
144                 
145                  if (nodeName == 'IFRAME') {
146                     
147                    
148                     traversedom(currentElement.content_document,  cb.fn,  cb.sub )
149                     cb.sub++;
150                     cb("</IFRAME>");
151                     return;
152                 }
153                 
154                 
155                 // Traverse the tree
156                 i = 0;
157                 var currentElementChild = currentElement.child_nodes.item(i);
158                 var allText = true;
159                 while (currentElementChild) {
160                     // Formatting code (indent the tree so it looks nice on the screen)
161                     
162                     if  (currentElementChild.node_name == '#text') {
163                        // if (currentElementChild.node_value.length) {
164                             cb(currentElementChild.node_value);
165                        // }
166                         
167                         i++;
168                         currentElementChild=currentElement.child_nodes.item(i);
169                         continue;
170                     }   
171                     allText = false;
172                     //cb("\n");
173                     //for (j = 0; j < depth; j++) {
174                       // &#166 is just a vertical line
175                     //  cb("  ");
176                     //}//               
177                     
178                         
179                     // Recursively traverse the tree structure of the child node
180                     traverseDOMTree(cb, currentElementChild, depth+1);
181                     i++;
182                     currentElementChild=currentElement.child_nodes.item(i);
183                 }
184                 if (!allText) {
185                     // The remaining code is mostly for formatting the tree
186                     //cb("\n");
187                     //for (j = 0; j < depth - 1; j++) {
188                       //cb("  ");
189                     //}     
190                 }
191                 if (tagName) {
192                    // if (depth > 1000 && (tagName == 'BODY' || tagName == 'HEAD' )) {
193                    //     cb("</DIV>");
194                    // } else {
195                         cb("</"+outNodeName+">");
196                    // }
197                     
198                 }
199             }
200         };
201         
202
203         var update_url = function (web_view, web_frame)
204         {
205             var toolbar = tab.get_toolbar();
206
207             toolbar.set_url(web_frame.get_uri());
208             toolbar.set_can_go_back(web_view.can_go_back());
209             toolbar.set_can_go_forward(web_view.can_go_forward());
210             
211             
212             
213             
214         };
215
216     
217       
218
219         var create_new_tab = function (web_view, web_frame, new_web_view)
220         {
221             new_web_view = new BrowserView();
222             new_web_view.signal.web_view_ready.connect(show_new_tab);
223             return new_web_view;
224         };
225
226         var show_new_tab = function (new_web_view)
227         {
228             TabbedBrowser.browser.new_tab("", new_web_view);
229
230             return false;
231         };
232
233         var hover_link = function (web_view, link, url)
234         {
235             tab.get_statusbar().set_status(url);
236         };
237          
238         /*
239         
240         this.add_inject = function(force)
241         {
242             
243             if (force || (typeof(injected[this.uri]) == 'undefined' )) {
244                 injected[this.uri] = 0;
245             }
246             if (injected[this.uri] > 2) {
247                 return;
248             }
249             injected[this.uri]++;
250             var fn = __script_path__ + "/inject.js";
251             if (File.exists(fn)) {
252 //                print("Adding inject");
253                 var newjs = File.read(__script_path__ + "/inject.js");
254                 TabbedBrowser.browser.current_tab().get_web_view().execute_script(
255                     newjs
256                     
257                 );
258             }
259             
260         }
261         */
262         var after_login = false;
263         
264         
265         var load_finished_called = false;
266         
267         
268         var do_print = function(web_frame) {
269             
270              
271             
272             var scr_a =  " var r = document.getElementsByTagName('link');" +
273                 "for (var i=0;i < r.length;i++) { " +
274                     "var a = r[i]; " +
275                     "if (  a.getAttribute('media') == '')  { continue; } " +
276                     "if (  a.getAttribute('media') == 'screen')  { "+
277                         "a.removeAttribute('media'); continue;" +
278                     "} " +
279                     //"a.parentNode.removeChild(a);" +
280                 "}";
281             var scr_b =  "var a = document.body.querySelectorAll('*'); "+
282                 "var dnodes=[]; "+
283                 "for(var i =i;i<a.length;i++) { "+
284                 "   var cs = window.getComputedStyle(a[i],null);"+
285                 "   if ('none' == cs.display) {"+
286                 "    dnodes.push(a[i]); "+
287                 "  }"+ 
288                 "}"+
289                 "console.log(dnodes.length);" +
290                 "dnodes.forEach(function(n) { "+
291                 "    try {  n.parentNode.removeChild(n);   } catch(e) { } "+
292                 "});";
293             
294             
295             //TabbedBrowser.browser.current_tab().get_web_view().execute_script(
296             //    scr_a
297             //);
298             //print(scr_b);
299             //TabbedBrowser.browser.current_tab().get_web_view().execute_script(
300             //    scr_b
301             //);
302             
303             if (current_url.match(/\.coconuts\.co\//) ) {
304                 TabbedBrowser.browser.current_tab().get_web_view().execute_script(
305                     File.read( __script_path__ + "/domains/coconuts.co.js")
306                 );
307                               
308             }
309             // motorme - requires a scroll to make content appear..
310             if (current_url.match(/\.motorme\.my\//) ) {
311                 TabbedBrowser.browser.current_tab().get_web_view().execute_script("window.scrollTo(0,500)"); 
312                               
313             }
314             
315             
316            
317             print("Delay:" + BrowserSettings.delay);
318          
319             GLib.timeout_add(GLib.PRIORITY_LOW, BrowserSettings.delay *1, function() {
320                  
321                 print("FETCHING");
322                 //print(web_frame);
323                 if (web_frame &&  BrowserSettings.export_filename_html  ) {
324                     var html = traversedom(web_frame.get_dom_document(), BrowserSettings.export_filename_html);
325                     //File.write(BrowserSettings.export_filename_html, html);
326                     
327                 } 
328                  
329                 if (!BrowserSettings.export_filename) {
330                     if (!BrowserSettings.export_filename_html) {
331                         return;
332                     }
333                     
334                     Seed.quit();
335                 }
336                 var mf = _t.get_main_frame();
337                  
338                 
339                 var ar = Gtk.PaperSize.get_paper_sizes();
340                 var psetup = new Gtk.PageSetup();
341                 for(var i = 0; i < ar.length; i++) {
342                     if (ar[i].get_name() =='iso_a2') {
343                         psetup.set_paper_size(ar[i]);
344                     }
345                 }
346                 
347                 var p = new Gtk.PrintOperation({ export_filename : BrowserSettings.export_filename });
348                 p.set_default_page_setup(psetup);
349                 mf.print_full(p, Gtk.PrintOperationAction.EXPORT);
350                 print("made image - exiting");
351                 
352                 Seed.quit();
353                 return true;
354             });
355         }
356         
357         
358         var weibo_added = false;
359         
360         var is_weibo = false;
361         
362         
363         var load_finished = function (webkit, web_frame, wb)
364         {
365             
366            
367             
368             if (!is_weibo) {
369                 do_print(web_frame);
370                 return;
371             }
372              
373              
374              print("load finished");
375              if (weibo_added) {
376                  
377                  if (after_login === true) {
378                      print("do print");
379                      do_print();
380                      return;
381                      
382                  }
383                  if (after_login === false) {
384                      return; // not here?
385                  }
386                  print("adding timeout?");
387                  //return;
388                 GLib.timeout_add(GLib.PRIORITY_LOW, 2000, function() {
389                     print("Redirecting after login?" + after_login);
390                     
391                     _t.browse(after_login);
392                     after_login  = true;
393                 });
394                 return;
395              }
396             
397             weibo_added = true;
398             TabbedBrowser.browser.current_tab().get_web_view().execute_script(
399                 File.read( __script_path__ + "/weibo.js") 
400             );
401             print("run_weibo(" + JSON.stringify( BrowserSettings.username ) + ", " + JSON.stringify(BrowserSettings.passwd) + ");");
402     
403             TabbedBrowser.browser.current_tab().get_web_view().execute_script(
404                     "run_weibo(" + JSON.stringify( BrowserSettings.username ) + ", " + JSON.stringify(BrowserSettings.passwd) + ");"
405             );
406             return;
407     
408             //    return;
409             print(after_login);
410             if (after_login !== false) {
411                 
412 //                return;
413                 // wait a bit then load the real page..
414                 GLib.timeout_add(GLib.PRIORITY_LOW, 500, function() {
415                     print("Redirecting after login?");
416                     _t.browse(after_login);
417                 });
418                 
419                 return;
420             }
421          
422             if (load_finished_called) {
423                 return ;
424             
425             }
426             load_finished_called = true;
427             
428           
429             
430 //            if(document.location.host=='weibo.com') {
431 //                // clear login dialog from weibo.
432 //                //check and hidden the login dialog and overlay .....
433 //                var els = document.querySelectorAll('div[node-type]');
434 //                var bbc = [];
435 //                for (i = 0; i < els.length; i++) {
436 //                    if (els[i].hasAttribute('node-type')) {
437 //                        if(els[i].getAttribute('node-type') == 'outer'){
438 //                            bbc.push(els[i]);
439 //                        }
440 //                    }
441 //                }
442 //                for (i = 0; i < bbc.length; i++) {// hide all the outer.....
443 //                    bbc[i].style.display = 'none';
444 //                }
445 //                
446 //                //try to login 
447 //                if(document.location.pathname == '/login.php'){
448 //                    
449 //                    // fills in the user name and password 
450 //                    var els = document.querySelectorAll('input[node-type]');
451 //                    
452 //                    for (i = 0; i < els.length; i++) {
453 //                        if (els[i].hasAttribute('node-type')) {
454 //                            if(els[i].getAttribute('node-type') == 'username'){
455 //                                els[i].value = BrowserSettings.username;
456 //                            }
457 //                            if(els[i].getAttribute('node-type') == 'password'){
458 //                                els[i].value = BrowserSettings.passwd;
459 //                            }
460 //                        }
461 //                    }
462 //                    
463 //                    
464 //                    // simulating click event to login ....
465 //                    var elss = document.querySelectorAll('a[node-type]');
466 //                    
467 //                    for (i = 0; i < elss.length; i++) {
468 //                        if (elss[i].hasAttribute('node-type')) {
469 //                            if(elss[i].getAttribute('node-type') == 'submitBtn'){
470 //                                elss[i].click();
471 //                            }
472 //                        }
473 //                    }
474 //                    
475 //                    
476 //                }
477 //                
478 //            }
479             
480             
481             // clear login dialog from weibo.
482 //            TabbedBrowser.browser.current_tab().get_web_view().execute_script(
483 //                " if (document.location.host=='weibo.com') { " +
484 //                " try {  " + 
485 //                " var a = document.getElementsByClassName('W_layer')[0]; " + 
486 //                " a.parentNode.removeChild(a.previousSibling); " + 
487 //                " a.parentNode.removeChild(a); " + 
488 //                " } catch(e) { }  } " );
489             
490             
491             return;
492             GLib.timeout_add(GLib.PRIORITY_LOW, BrowserSettings.delay, function() {
493                  
494                 var mf = _t.get_main_frame();
495                 
496                 var ar = Gtk.PaperSize.get_paper_sizes();
497                 var psetup = new Gtk.PageSetup();
498                 for(var i = 0; i < ar.length; i++) {
499                     if (ar[i].get_name() =='iso_a2') {
500                         psetup.set_paper_size(ar[i]);
501                     }
502                 }
503                 
504                 var p = new Gtk.PrintOperation({ export_filename : BrowserSettings.export_filename });
505                 p.set_default_page_setup(psetup);
506                 mf.print_full(p, Gtk.PrintOperationAction.EXPORT);
507                 print("made image - exiting");
508                 
509                 Seed.quit();
510                 return true;
511             });
512             
513             return;
514         };
515  
516  
517  
518         
519         var load_committed = function (web_view, web_frame)
520         {
521             print("load commited");
522             
523             update_url(web_view, web_frame);
524              
525             // call load finished after 20seconds??
526             // so even if it never complets we try and print the thing.
527             GLib.timeout_add(GLib.PRIORITY_LOW, 40000, function() {
528                 print("load commited - 3000 ms?");
529                 load_finished();
530             });
531             
532         };
533
534         var clicked_link = function (web_view, web_frame, request,
535                                      action, decision, window)
536         {
537             if(action.get_reason() == WebKit.WebNavigationReason.LINK_CLICKED &&
538                action.get_button() == 2)
539             {
540                 browser.new_tab(request.get_uri(), null);
541                 return true;
542             }
543
544             return false;
545         };
546
547         // Public
548         
549         
550         this.browse = function (url)
551         {
552             if(url.search("://") < 0)
553                 url = "http://" + url;
554             
555             current_url = url;
556             
557             print("BROWSE: " + url);
558             if (url.match(/\/weibo\.com\//) && after_login === false) {
559                 is_weibo = true;
560                 after_login = url;
561                 url = "http://weibo.com/login.php";
562             }
563             else  if (url.match(/\/weibo\.com\//) && after_login !== false) {
564                 after_login = false;
565             }
566             print("BROWSE -really: " + url);
567             this.open(url);
568         };
569
570         this.set_tab = function (new_tab)
571         {
572             tab = new_tab;
573         };
574
575         this.get_tab = function ()
576         {
577             return tab;
578         };
579
580     
581         // Implementation
582         //this.set_scroll_adjustments(null, null);
583         
584         //this.signal.title_changed.connect(update_title);
585         //this.signal.load_committed.connect(load_committed);
586         this.signal.load_finished.connect(load_finished);
587        
588         
589         // For some reason, this segfaults seed in the instance init closure handler
590         // Once that's fixed, uncommenting the next line will give middle-click-open-in-new tab
591         //this.signal.navigation_policy_decision_requested.connect(clicked_link);
592
593         //this.signal.hovering_over_link.connect(hover_link);
594
595         this.signal.create_web_view.connect(create_new_tab);
596         
597         
598          
599 //        print("ADDing console message sig handler");
600         
601         
602          
603         
604         this.toFilename = function(url)
605         {
606             url = url.replace(/^http[s]*:\/\//, '');
607             var p = url.split('/');
608             p.unshift(storedir+'/output');
609             for (var i =1 ;i < p.length; i++) {
610                 p[i] = encodeURIComponent(p[i]);
611             
612             }
613             p[p.length-1] = decodeURIComponent(p[p.length-1]);
614             ret = p.join('/');
615             var dir = File.dirname(ret);
616             File.mkdirall(dir);
617             return ret;
618             
619         }
620         this.checkdomain = function(comp)
621         {
622             var b = parseUri(this.uri);
623             var d = parseUri(comp);
624             return (d.host == b.host && d.protocol == b.protocol);
625             
626             
627         }
628         
629         this.dupeCheck = function(url)
630         {
631             
632            // order - return highest up the queue first..
633             if (File.exists(downloaddir +'/' + encodeURIComponent(url))) {
634                 return downloaddir +'/' + encodeURIComponent(url);
635             }
636              if (File.exists(parsedir +'/' + encodeURIComponent(url))) {
637                 return parsedir +'/' + encodeURIComponent(url);
638             }
639             if (File.exists(donedir +'/' + encodeURIComponent(url))) {
640                 return donedir +'/' + encodeURIComponent(url);
641             }
642             return  false;
643             
644             
645         }
646         this.moveToParse = function(url)
647         {
648             var old = this.dupeCheck(url);
649             var target =parsedir +'/' + encodeURIComponent(url);
650             if (old == target) {
651                 return;
652             }
653             File.write(target, old ? File.read(old) : '');
654             if (old) {
655                 File.remove(old);
656             }
657             
658         }
659         
660         this.moveToDownload= function(url)
661         {
662             var old = this.dupeCheck(url);
663             var target =downloaddir +'/' + encodeURIComponent(url);
664             if (old == target) {
665                 return;
666             }
667             File.write(target, old ? File.read(old) : '');
668             if (old) {
669                 File.remove(old);
670             }
671             
672         }
673         this.moveToDone= function(url)
674         {
675             var old = this.dupeCheck(url);
676             var target = donedir +'/' + encodeURIComponent(url);
677             if (old == target) {
678                 return;
679             }
680             File.write(target, old ? File.read(old) : '');
681             if (old) {
682                 File.remove(old);
683             }
684             
685         }
686         
687     }
688 });
689
690 function parseUri (str) {
691         var     o   = parseUri.options,
692                 m   = o.parser[o.strictMode ? "strict" : "loose"].exec(str),
693                 uri = {},
694                 i   = 14;
695
696         while (i--) uri[o.key[i]] = m[i] || "";
697
698         uri[o.q.name] = {};
699         uri[o.key[12]].replace(o.q.parser, function ($0, $1, $2) {
700                 if ($1) uri[o.q.name][$1] = $2;
701         });
702
703         return uri;
704 };
705
706 parseUri.options = {
707         strictMode: false,
708         key: ["source","protocol","authority","userInfo","user","password","host","port","relative","path","directory","file","query","anchor"],
709         q:   {
710                 name:   "queryKey",
711                 parser: /(?:^|&)([^&=]*)=?([^&]*)/g
712         },
713         parser: {
714                 strict: /^(?:([^:\/?#]+):)?(?:\/\/((?:(([^:@]*)(?::([^:@]*))?)?@)?([^:\/?#]*)(?::(\d*))?))?((((?:[^?#\/]*\/)*)([^?#]*))(?:\?([^#]*))?(?:#(.*))?)/,
715                 loose:  /^(?:(?![^:@]+:[^:@\/]*@)([^:\/?#.]+):)?(?:\/\/)?((?:(([^:@]*)(?::([^:@]*))?)?@)?([^:\/?#]*)(?::(\d*))?)(((\/(?:[^?#](?![^?#\/]*\.[^?#\/.]+(?:[?#]|$)))*\/?)?([^?#\/]*))(?:\?([^#]*))?(?:#(.*))?)/
716         }
717 };