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