Rietveld Code Review Tool
Help | Bug tracker | Discussion group | Source code

Side by Side Diff: safari/ext/background.js

Issue 6346177440120832: Added abstraction for frames, to fix domain-based rules, whitelisting and ad counter on Safari (Closed)
Patch Set: Rebased and addressed comments Created Jan. 19, 2014, 10:40 a.m.
Left:
Right:
Use n/p to move between diff chunks; N/P to move between comments.
Jump to:
View unified diff | Download patch
OLDNEW
1 /* 1 /*
2 * This file is part of Adblock Plus <http://adblockplus.org/>, 2 * This file is part of Adblock Plus <http://adblockplus.org/>,
3 * Copyright (C) 2006-2013 Eyeo GmbH 3 * Copyright (C) 2006-2013 Eyeo GmbH
4 * 4 *
5 * Adblock Plus is free software: you can redistribute it and/or modify 5 * Adblock Plus is free software: you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License version 3 as 6 * it under the terms of the GNU General Public License version 3 as
7 * published by the Free Software Foundation. 7 * published by the Free Software Foundation.
8 * 8 *
9 * Adblock Plus is distributed in the hope that it will be useful, 9 * Adblock Plus is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of 10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details. 12 * GNU General Public License for more details.
13 * 13 *
14 * You should have received a copy of the GNU General Public License 14 * You should have received a copy of the GNU General Public License
15 * along with Adblock Plus. If not, see <http://www.gnu.org/licenses/>. 15 * along with Adblock Plus. If not, see <http://www.gnu.org/licenses/>.
16 */ 16 */
17 17
18 (function() 18 (function()
19 { 19 {
20 /* Tabs */ 20 /* Events */
21 21
22 var TabEventTarget = function() 22 var TabEventTarget = function()
23 { 23 {
24 WrappedEventTarget.apply(this, arguments); 24 WrappedEventTarget.apply(this, arguments);
25 }; 25 };
26 TabEventTarget.prototype = { 26 TabEventTarget.prototype = {
27 __proto__: WrappedEventTarget.prototype, 27 __proto__: WrappedEventTarget.prototype,
28 _wrapListener: function(listener) 28 _wrapListener: function(listener)
29 { 29 {
30 return function(event) 30 return function(event)
(...skipping 13 matching lines...) Expand all
44 _wrapListener: function(listener) 44 _wrapListener: function(listener)
45 { 45 {
46 return function (event) 46 return function (event)
47 { 47 {
48 if (event.name == "loading") 48 if (event.name == "loading")
49 listener(new Tab(event.target)); 49 listener(new Tab(event.target));
50 }; 50 };
51 } 51 }
52 }; 52 };
53 53
54 var BackgroundMessageEventTarget = function()
55 {
56 MessageEventTarget.call(this, safari.application);
57 };
58 BackgroundMessageEventTarget.prototype = {
59 __proto__: MessageEventTarget.prototype,
60 _getResponseDispatcher: function(event)
61 {
62 return event.target.page;
63 },
64 _getSenderDetails: function(event)
65 {
66 return {
67 tab: new Tab(event.target),
68 frame: new Frame(
69 event.message.documentUrl,
70 event.message.isTopLevel,
71 event.target
72 )
73 };
74 }
75 };
76
77
78 /* Tabs */
79
54 Tab = function(tab) 80 Tab = function(tab)
55 { 81 {
56 this._tab = tab; 82 this._tab = tab;
57 83
58 this._eventTarget = tab;
59 this._messageDispatcher = tab.page;
60
61 this.browserAction = new BrowserAction(this); 84 this.browserAction = new BrowserAction(this);
62 85
63 this.onLoading = new LoadingTabEventTarget(tab); 86 this.onLoading = new LoadingTabEventTarget(tab);
87 this.onBeforeNavigate = new TabEventTarget(tab, "beforeNavigate", false);
64 this.onCompleted = new TabEventTarget(tab, "navigate", false); 88 this.onCompleted = new TabEventTarget(tab, "navigate", false);
65 this.onActivated = new TabEventTarget(tab, "activate", false); 89 this.onActivated = new TabEventTarget(tab, "activate", false);
66 this.onRemoved = new TabEventTarget(tab, "close", false); 90 this.onRemoved = new TabEventTarget(tab, "close", false);
67 }; 91 };
68 Tab.prototype = { 92 Tab.prototype = {
69 get url() 93 get url()
70 { 94 {
71 return this._tab.url; 95 return this._tab.url;
72 }, 96 },
73 close: function() 97 close: function()
74 { 98 {
75 this._tab.close(); 99 this._tab.close();
76 }, 100 },
77 activate: function() 101 activate: function()
78 { 102 {
79 this._tab.activate(); 103 this._tab.activate();
80 }, 104 },
81 sendMessage: sendMessage 105 sendMessage: function(message, responseCallback)
106 {
107 _sendMessage(
108 message, responseCallback,
109 this._tab.page, this._tab
110 );
111 }
82 }; 112 };
83 113
84 TabMap = function() 114 TabMap = function(deleteTabOnBeforeNavigate)
85 { 115 {
86 this._tabs = []; 116 this._tabs = [];
87 this._values = []; 117 this._values = [];
88 118
89 this._onClosed = this._onClosed.bind(this); 119 this._deleteOnEvent = this._deleteOnEvent.bind(this);
120 this._deleteTabOnBeforeNavigate = deleteTabOnBeforeNavigate;
90 }; 121 };
91 TabMap.prototype = 122 TabMap.prototype =
92 { 123 {
93 get: function(tab) { 124 get: function(tab) {
94 var idx; 125 var idx;
95 126
96 if (!tab || (idx = this._tabs.indexOf(tab._tab)) == -1) 127 if (!tab || (idx = this._tabs.indexOf(tab._tab)) == -1)
97 return null; 128 return null;
98 129
99 return this._values[idx]; 130 return this._values[idx];
100 }, 131 },
101 set: function(tab, value) 132 set: function(tab, value)
102 { 133 {
103 var idx = this._tabs.indexOf(tab._tab); 134 var idx = this._tabs.indexOf(tab._tab);
104 135
105 if (idx != -1) 136 if (idx != -1)
106 this._values[idx] = value; 137 this._values[idx] = value;
107 else 138 else
108 { 139 {
109 this._tabs.push(tab._tab); 140 this._tabs.push(tab._tab);
110 this._values.push(value); 141 this._values.push(value);
111 142
112 tab._tab.addEventListener("close", this._onClosed, false); 143 tab._tab.addEventListener("close", this._deleteOnEvent, false);
144 if (this._deleteTabOnBeforeNavigate)
145 tab._tab.addEventListener("beforeNavigate", this._deleteOnEvent, false );
113 } 146 }
114 }, 147 },
115 has: function(tab) 148 has: function(tab)
116 { 149 {
117 return this._tabs.indexOf(tab._tab) != -1; 150 return this._tabs.indexOf(tab._tab) != -1;
118 }, 151 },
119 clear: function() 152 clear: function()
120 { 153 {
121 while (this._tabs.length > 0) 154 while (this._tabs.length > 0)
122 this._delete(this._tabs[0]); 155 this._delete(this._tabs[0]);
123 }, 156 },
124 _delete: function(tab) 157 _delete: function(tab)
125 { 158 {
126 var idx = this._tabs.indexOf(tab); 159 var idx = this._tabs.indexOf(tab);
127 160
128 if (idx != -1) 161 if (idx != -1)
129 { 162 {
130 this._tabs.splice(idx, 1); 163 this._tabs.splice(idx, 1);
131 this._values.splice(idx, 1); 164 this._values.splice(idx, 1);
132 165
133 tab.removeEventListener("close", this._onClosed, false); 166 tab.removeEventListener("close", this._deleteOnEvent, false);
167 tab.removeEventListener("beforeNavigate", this._deleteOnEvent, false);
134 } 168 }
135 }, 169 },
136 _onClosed: function(event) 170 _deleteOnEvent: function(event)
137 { 171 {
138 this._delete(event.target); 172 // delay so that other event handlers can still look this tab up
173 setTimeout(this._delete.bind(this, event.target), 0);
139 } 174 }
140 }; 175 };
141 TabMap.prototype["delete"] = function(tab) 176 TabMap.prototype["delete"] = function(tab)
142 { 177 {
143 this._delete(tab._tab); 178 this._delete(tab._tab);
144 }; 179 };
145 180
146 ext.tabs = { 181 ext.tabs = {
147 onLoading: new LoadingTabEventTarget(safari.application), 182 onLoading: new LoadingTabEventTarget(safari.application),
183 onBeforeNavigate: new TabEventTarget(safari.application, "beforeNavigate", t rue),
148 onCompleted: new TabEventTarget(safari.application, "navigate", true), 184 onCompleted: new TabEventTarget(safari.application, "navigate", true),
149 onActivated: new TabEventTarget(safari.application, "activate", true), 185 onActivated: new TabEventTarget(safari.application, "activate", true),
150 onRemoved: new TabEventTarget(safari.application, "close", true) 186 onRemoved: new TabEventTarget(safari.application, "close", true)
151 }; 187 };
152 188
153 189
154 /* Browser actions */ 190 /* Browser actions */
155 191
156 var toolbarItemProperties = {}; 192 var toolbarItemProperties = {};
157 193
(...skipping 103 matching lines...) Expand 10 before | Expand all | Expand 10 after
261 { 297 {
262 var tab = this._win.openTab(); 298 var tab = this._win.openTab();
263 tab.url = url; 299 tab.url = url;
264 300
265 if (callback) 301 if (callback)
266 callback(new Tab(tab)); 302 callback(new Tab(tab));
267 } 303 }
268 }; 304 };
269 305
270 306
307 /* Frames */
308
309 Frame = function(url, isTopLevel, tab)
310 {
311 this.url = url;
312
313 // there is no way to discover frames with Safari's API.
314 // so if this isn't the top level frame, assume that the parent is.
315 // this is the best we can do for Safari. :(
316 if (!isTopLevel)
317 this.parent = new Frame(tab.url, true);
318 else
319 this.parent = null;
320 };
321
322
271 /* Background page proxy */ 323 /* Background page proxy */
272 324
273 var proxy = { 325 var proxy = {
274 tabs: [], 326 tabs: [],
275 objects: [], 327 objects: [],
276 328
277 registerObject: function(obj, objects) 329 registerObject: function(obj, objects)
278 { 330 {
279 var objectId = objects.indexOf(obj); 331 var objectId = objects.indexOf(obj);
280 332
(...skipping 210 matching lines...) Expand 10 before | Expand all | Expand 10 after
491 } 543 }
492 } 544 }
493 }; 545 };
494 546
495 547
496 /* Web request blocking */ 548 /* Web request blocking */
497 549
498 ext.webRequest = { 550 ext.webRequest = {
499 onBeforeRequest: { 551 onBeforeRequest: {
500 _listeners: [], 552 _listeners: [],
501 _urlPatterns: [],
502 553
503 _handleMessage: function(message, tab) 554 _handleMessage: function(message, rawTab)
504 { 555 {
505 tab = new Tab(tab); 556 var tab = new Tab(rawTab);
557 var frame = new Frame(message.documentUrl, message.isTopLevel, rawTab);
506 558
507 for (var i = 0; i < this._listeners.length; i++) 559 for (var i = 0; i < this._listeners.length; i++)
508 { 560 {
509 var regex = this._urlPatterns[i]; 561 if (this._listeners[i](message.url, message.type, tab, frame) === fals e)
510
511 if ((!regex || regex.test(message.url)) && this._listeners[i](message. url, message.type, tab, 0, -1) === false)
512 return false; 562 return false;
513 } 563 }
514 564
515 return true; 565 return true;
516 }, 566 },
517 addListener: function(listener, urls) 567 addListener: function(listener)
518 { 568 {
519 var regex;
520
521 if (urls)
522 regex = new RegExp("^(?:" + urls.map(function(url)
523 {
524 return url.split("*").map(function(s)
525 {
526 return s.replace(/([.?+^$[\]\\(){}|-])/g, "\\$1");
527 }).join(".*");
528 }).join("|") + ")($|[?#])");
529
530 this._listeners.push(listener); 569 this._listeners.push(listener);
531 this._urlPatterns.push(regex);
532 }, 570 },
533 removeListener: function(listener) 571 removeListener: function(listener)
534 { 572 {
535 var idx = this._listeners.indexOf(listener); 573 var idx = this._listeners.indexOf(listener);
536
537 if (idx != -1) 574 if (idx != -1)
538 {
539 this._listeners.splice(idx, 1); 575 this._listeners.splice(idx, 1);
540 this._urlPatterns.splice(idx, 1);
541 }
542 } 576 }
543 }, 577 },
544 handlerBehaviorChanged: function() {} 578 handlerBehaviorChanged: function() {}
545 }; 579 };
546 580
547 581
548 /* Synchronous messaging */ 582 /* Synchronous messaging */
549 583
550 safari.application.addEventListener("message", function(event) 584 safari.application.addEventListener("message", function(event)
551 { 585 {
(...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after
584 } 618 }
585 }; 619 };
586 620
587 ext.backgroundPage = { 621 ext.backgroundPage = {
588 getWindow: function() 622 getWindow: function()
589 { 623 {
590 return safari.extension.globalPage.contentWindow; 624 return safari.extension.globalPage.contentWindow;
591 } 625 }
592 }; 626 };
593 627
594 ext.onMessage = new MessageEventTarget(safari.application); 628 ext.onMessage = new BackgroundMessageEventTarget();
595 629
596 var contextMenu = []; 630 var contextMenu = [];
597 var isContextMenuHidden = false; 631 var isContextMenuHidden = false;
598 ext.contextMenus = { 632 ext.contextMenus = {
599 addMenuItem: function(title, contexts, onclick) 633 addMenuItem: function(title, contexts, onclick)
600 { 634 {
601 contextMenu.push({ 635 contextMenu.push({
602 id: "block-element", 636 id: "block-element",
603 title: title, 637 title: title,
604 item: null, 638 item: null,
(...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after
647 for (var i = 0; i < contextMenu.length; i++) 681 for (var i = 0; i < contextMenu.length; i++)
648 { 682 {
649 if (contextMenu[i].id == event.command) 683 if (contextMenu[i].id == event.command)
650 { 684 {
651 contextMenu[i].onclick(event.userInfo.srcUrl, new Tab(safari.application .activeBrowserWindow.activeTab)); 685 contextMenu[i].onclick(event.userInfo.srcUrl, new Tab(safari.application .activeBrowserWindow.activeTab));
652 break; 686 break;
653 } 687 }
654 } 688 }
655 }, false); 689 }, false);
656 })(); 690 })();
OLDNEW
« chrome/ext/background.js ('K') | « popupBlocker.js ('k') | safari/ext/common.js » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld