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