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