Left: | ||
Right: |
OLD | NEW |
---|---|
1 /* | 1 /* |
2 * This file is part of Adblock Plus <https://adblockplus.org/>, | 2 * This file is part of Adblock Plus <https://adblockplus.org/>, |
3 * Copyright (C) 2006-2015 Eyeo GmbH | 3 * Copyright (C) 2006-2015 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 /* Pages */ | 20 /* Context menus */ |
21 | 21 |
22 var pages = Object.create(null); | 22 var contextMenuItems = new ext.PageMap(); |
23 var pageCounter = 0; | |
24 | 23 |
25 var Page = function(id, tab, url) | 24 var ContextMenus = function(page) |
26 { | 25 { |
27 this._id = id; | 26 this._page = page; |
28 this._tab = tab; | 27 }; |
29 this._frames = [{url: new URL(url), parent: null}]; | 28 ContextMenus.prototype = { |
29 create: function(item) | |
30 { | |
31 var items = contextMenuItems.get(this._page); | |
32 if (!items) | |
33 contextMenuItems.set(this._page, items = []); | |
30 | 34 |
31 if (tab.page) | 35 items.push(item); |
32 this._messageProxy = new ext._MessageProxy(tab.page); | 36 }, |
33 else | 37 removeAll: function() |
34 // while the new tab page is shown on Safari 7, the 'page' property | |
35 // of the tab is undefined, and we can't send messages to that page | |
36 this._messageProxy = { | |
37 handleRequest: function() {}, | |
38 handleResponse: function() {}, | |
39 sendMessage: function() {} | |
40 }; | |
41 | |
42 this.browserAction = new BrowserAction(this); | |
43 this.contextMenus = new ContextMenus(this); | |
44 }; | |
45 Page.prototype = { | |
46 get url() | |
47 { | 38 { |
48 return this._frames[0].url; | 39 contextMenuItems.delete(this._page); |
49 }, | |
50 sendMessage: function(message, responseCallback) | |
51 { | |
52 this._messageProxy.sendMessage(message, responseCallback, {pageId: this._i d}); | |
53 } | 40 } |
54 }; | 41 }; |
55 | 42 |
56 ext._getPage = function(id) | 43 safari.application.addEventListener("contextmenu", function(event) |
57 { | 44 { |
58 return pages[id]; | 45 if (!event.userInfo) |
59 }; | |
60 | |
61 var isPageActive = function(page) | |
62 { | |
63 var tab = page._tab; | |
64 var win = tab.browserWindow; | |
65 return win && tab == win.activeTab && page == tab._visiblePage; | |
66 }; | |
67 | |
68 var forgetPage = function(id) | |
69 { | |
70 ext._removeFromAllPageMaps(id); | |
71 | |
72 delete pages[id]._tab._pages[id]; | |
73 delete pages[id]; | |
74 }; | |
75 | |
76 var replacePage = function(page) | |
77 { | |
78 var tab = page._tab; | |
79 tab._visiblePage = page; | |
80 | |
81 for (var id in tab._pages) | |
82 { | |
83 if (id != page._id) | |
84 forgetPage(id); | |
85 } | |
86 | |
87 if (isPageActive(page)) | |
88 updateToolbarItemForPage(page, tab.browserWindow); | |
89 }; | |
90 | |
91 ext.pages = { | |
92 open: function(url, callback) | |
93 { | |
94 var tab = safari.application.activeBrowserWindow.openTab(); | |
95 tab.url = url; | |
96 | |
97 if (callback) | |
98 { | |
99 var onLoading = function(page) | |
100 { | |
101 if (page._tab == tab) | |
102 { | |
103 ext.pages.onLoading.removeListener(onLoading); | |
104 callback(page); | |
105 } | |
106 }; | |
107 ext.pages.onLoading.addListener(onLoading); | |
108 } | |
109 }, | |
110 query: function(info, callback) | |
111 { | |
112 var matchedPages = []; | |
113 | |
114 for (var id in pages) | |
115 { | |
116 var page = pages[id]; | |
117 var win = page._tab.browserWindow; | |
118 | |
119 if ("active" in info && info.active != isPageActive(page)) | |
120 continue; | |
121 if ("lastFocusedWindow" in info && info.lastFocusedWindow != (win == saf ari.application.activeBrowserWindow)) | |
122 continue; | |
123 | |
124 matchedPages.push(page); | |
125 }; | |
126 | |
127 callback(matchedPages); | |
128 }, | |
129 onLoading: new ext._EventTarget() | |
130 }; | |
131 | |
132 safari.application.addEventListener("close", function(event) | |
133 { | |
134 // this event is dispatched on closing windows and tabs. However when a | |
135 // window is closed, it is first dispatched on each tab in the window and | |
136 // then on the window itself. But we are only interested in closed tabs. | |
137 if (!(event.target instanceof SafariBrowserTab)) | |
138 return; | 46 return; |
139 | 47 |
140 // when a tab is closed, forget the previous page associated with that | 48 var pageId = event.userInfo.pageId; |
141 // tab. Note that it wouldn't be sufficient do that when the old page | 49 if (!pageId) |
142 // is unloading, because Safari dispatches window.onunload only when | 50 return; |
143 // reloading the page or following links, but not when closing the tab. | 51 |
144 for (var id in event.target._pages) | 52 var page = pages[event.userInfo.pageId]; |
145 forgetPage(id); | 53 var items = contextMenuItems.get(page); |
146 }, true); | 54 if (!items) |
55 return; | |
56 | |
57 var context = event.userInfo.tagName; | |
58 if (context == "img") | |
59 context = "image"; | |
60 | |
61 for (var i = 0; i < items.length; i++) | |
62 { | |
63 // Supported contexts are: all, audio, image, video | |
64 var menuItem = items[i]; | |
65 if (menuItem.contexts.indexOf("all") == -1 && menuItem.contexts.indexOf(co ntext) == -1) | |
66 continue; | |
67 | |
68 event.contextMenu.appendContextMenuItem(i, menuItem.title); | |
69 } | |
70 }); | |
71 | |
72 safari.application.addEventListener("command", function(event) | |
73 { | |
74 var page = pages[event.userInfo.pageId]; | |
75 var items = contextMenuItems.get(page); | |
76 | |
77 items[event.command].onclick(page); | |
78 }); | |
147 | 79 |
148 | 80 |
149 /* Browser actions */ | 81 /* Browser actions */ |
150 | 82 |
151 var toolbarItemProperties = {}; | 83 var toolbarItemProperties = {}; |
152 | 84 |
153 var getToolbarItemForWindow = function(win) | 85 var getToolbarItemForWindow = function(win) |
154 { | 86 { |
155 for (var i = 0; i < safari.extension.toolbarItems.length; i++) | 87 for (var i = 0; i < safari.extension.toolbarItems.length; i++) |
156 { | 88 { |
(...skipping 66 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
223 return; | 155 return; |
224 | 156 |
225 // update the toolbar item for the page visible in the tab that just | 157 // update the toolbar item for the page visible in the tab that just |
226 // became active. If we can't find that page (e.g. when a page was | 158 // became active. If we can't find that page (e.g. when a page was |
227 // opened in a new tab, and our content script didn't run yet), the | 159 // opened in a new tab, and our content script didn't run yet), the |
228 // toolbar item of the window, is reset to its intial configuration. | 160 // toolbar item of the window, is reset to its intial configuration. |
229 updateToolbarItemForPage(event.target._visiblePage, event.target.browserWind ow); | 161 updateToolbarItemForPage(event.target._visiblePage, event.target.browserWind ow); |
230 }, true); | 162 }, true); |
231 | 163 |
232 | 164 |
233 /* Context menus */ | 165 /* Pages */ |
234 | 166 |
235 var contextMenuItems = new ext.PageMap(); | 167 var pages = Object.create(null); |
168 var pageCounter = 0; | |
236 | 169 |
237 var ContextMenus = function(page) | 170 var Page = function(id, tab, url) |
238 { | 171 { |
239 this._page = page; | 172 this._id = id; |
173 this._tab = tab; | |
174 this._frames = [{url: new URL(url), parent: null}]; | |
175 | |
176 if (tab.page) | |
177 this._messageProxy = new ext._MessageProxy(tab.page); | |
178 else | |
179 // while the new tab page is shown on Safari 7, the 'page' property | |
180 // of the tab is undefined, and we can't send messages to that page | |
181 this._messageProxy = { | |
182 handleRequest: function() {}, | |
183 handleResponse: function() {}, | |
184 sendMessage: function() {} | |
185 }; | |
186 | |
187 this.browserAction = new BrowserAction(this); | |
188 this.contextMenus = new ContextMenus(this); | |
240 }; | 189 }; |
241 ContextMenus.prototype = { | 190 Page.prototype = { |
242 create: function(item) | 191 get url() |
243 { | 192 { |
244 var items = contextMenuItems.get(this._page); | 193 return this._frames[0].url; |
245 if (!items) | |
246 contextMenuItems.set(this._page, items = []); | |
247 | |
248 items.push(item); | |
249 }, | 194 }, |
250 removeAll: function() | 195 sendMessage: function(message, responseCallback) |
251 { | 196 { |
252 contextMenuItems.delete(this._page); | 197 this._messageProxy.sendMessage(message, responseCallback, {pageId: this._i d}); |
253 } | 198 } |
254 }; | 199 }; |
255 | 200 |
256 safari.application.addEventListener("contextmenu", function(event) | 201 ext._getPage = function(id) |
257 { | 202 { |
258 if (!event.userInfo) | 203 return pages[id]; |
204 }; | |
205 | |
206 var isPageActive = function(page) | |
207 { | |
208 var tab = page._tab; | |
209 var win = tab.browserWindow; | |
210 return win && tab == win.activeTab && page == tab._visiblePage; | |
211 }; | |
212 | |
213 var forgetPage = function(id) | |
214 { | |
215 ext._removeFromAllPageMaps(id); | |
216 | |
217 delete pages[id]._tab._pages[id]; | |
218 delete pages[id]; | |
219 }; | |
220 | |
221 var replacePage = function(page) | |
222 { | |
223 var tab = page._tab; | |
224 tab._visiblePage = page; | |
225 | |
226 for (var id in tab._pages) | |
227 { | |
228 if (id != page._id) | |
229 forgetPage(id); | |
230 } | |
231 | |
232 if (isPageActive(page)) | |
233 updateToolbarItemForPage(page, tab.browserWindow); | |
234 }; | |
235 | |
236 var addPage = function(tab, url, prerendered) | |
Sebastian Noack
2015/03/03 19:51:34
This function is new.
| |
237 { | |
238 var pageId = ++pageCounter; | |
239 | |
240 if (!('_pages' in tab)) | |
241 tab._pages = Object.create(null); | |
242 | |
243 var page = new Page(pageId, tab, url); | |
244 pages[pageId] = tab._pages[pageId] = page; | |
245 | |
kzar
2015/03/04 10:46:57
Seems a shame you stripped out the useful comment
Sebastian Noack
2015/03/04 11:04:35
I've re-added that comment. Also added some more c
| |
246 if (!prerendered) | |
247 replacePage(page); | |
248 | |
249 return pageId; | |
250 }; | |
251 | |
252 ext.pages = { | |
253 open: function(url, callback) | |
254 { | |
255 var tab = safari.application.activeBrowserWindow.openTab(); | |
256 tab.url = url; | |
257 | |
258 if (callback) | |
259 { | |
260 var onLoading = function(page) | |
261 { | |
262 if (page._tab == tab) | |
263 { | |
264 ext.pages.onLoading.removeListener(onLoading); | |
265 callback(page); | |
266 } | |
267 }; | |
268 ext.pages.onLoading.addListener(onLoading); | |
269 } | |
270 }, | |
271 query: function(info, callback) | |
272 { | |
273 var matchedPages = []; | |
274 | |
275 for (var id in pages) | |
276 { | |
277 var page = pages[id]; | |
278 var win = page._tab.browserWindow; | |
279 | |
280 if ("active" in info && info.active != isPageActive(page)) | |
281 continue; | |
282 if ("lastFocusedWindow" in info && info.lastFocusedWindow != (win == saf ari.application.activeBrowserWindow)) | |
283 continue; | |
284 | |
285 matchedPages.push(page); | |
286 }; | |
287 | |
288 callback(matchedPages); | |
289 }, | |
290 onLoading: new ext._EventTarget() | |
291 }; | |
292 | |
293 safari.application.addEventListener("close", function(event) | |
294 { | |
295 // this event is dispatched on closing windows and tabs. However when a | |
296 // window is closed, it is first dispatched on each tab in the window and | |
297 // then on the window itself. But we are only interested in closed tabs. | |
298 if (!(event.target instanceof SafariBrowserTab)) | |
259 return; | 299 return; |
260 | 300 |
261 var pageId = event.userInfo.pageId; | 301 // when a tab is closed, forget the previous page associated with that |
262 if (!pageId) | 302 // tab. Note that it wouldn't be sufficient do that when the old page |
263 return; | 303 // is unloading, because Safari dispatches window.onunload only when |
304 // reloading the page or following links, but not when closing the tab. | |
305 for (var id in event.target._pages) | |
306 forgetPage(id); | |
307 }, true); | |
264 | 308 |
265 var page = pages[event.userInfo.pageId]; | 309 safari.application.browserWindows.forEach(function(win) |
Sebastian Noack
2015/03/03 19:51:34
This is where we detect existing tabs now.
| |
266 var items = contextMenuItems.get(page); | 310 { |
267 if (!items) | 311 for (var i = 0; i < win.tabs.length; i++) |
268 return; | 312 { |
313 var tab = win.tabs[i]; | |
314 var url = tab.url; | |
269 | 315 |
270 var context = event.userInfo.tagName; | 316 if (url) |
271 if (context == "img") | 317 addPage(tab, url, false); |
272 context = "image"; | |
273 | |
274 for (var i = 0; i < items.length; i++) | |
275 { | |
276 // Supported contexts are: all, audio, image, video | |
277 var menuItem = items[i]; | |
278 if (menuItem.contexts.indexOf("all") == -1 && menuItem.contexts.indexOf(co ntext) == -1) | |
279 continue; | |
280 | |
281 event.contextMenu.appendContextMenuItem(i, menuItem.title); | |
282 } | 318 } |
283 }); | 319 }); |
284 | 320 |
285 safari.application.addEventListener("command", function(event) | |
286 { | |
287 var page = pages[event.userInfo.pageId]; | |
288 var items = contextMenuItems.get(page); | |
289 | |
290 items[event.command].onclick(page); | |
291 }); | |
292 | |
293 | 321 |
294 /* Web requests */ | 322 /* Web requests */ |
Sebastian Noack
2015/03/03 19:51:34
All other code above this line is unchanged. I mer
| |
295 | 323 |
296 ext.webRequest = { | 324 ext.webRequest = { |
297 onBeforeRequest: new ext._EventTarget(), | 325 onBeforeRequest: new ext._EventTarget(), |
298 handlerBehaviorChanged: function() {}, | 326 handlerBehaviorChanged: function() {}, |
299 indistinguishableTypes: [["OTHER", "FONT"]] | 327 indistinguishableTypes: [["OTHER", "FONT"]] |
300 }; | 328 }; |
301 | 329 |
302 | 330 |
303 /* Background page proxy (for access from content scripts) */ | 331 /* Background page proxy (for access from content scripts) */ |
304 | 332 |
(...skipping 213 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
518 { | 546 { |
519 case "loading": | 547 case "loading": |
520 var tab = event.target; | 548 var tab = event.target; |
521 var message = event.message; | 549 var message = event.message; |
522 | 550 |
523 var pageId; | 551 var pageId; |
524 var frameId; | 552 var frameId; |
525 | 553 |
526 if (message.isTopLevel) | 554 if (message.isTopLevel) |
527 { | 555 { |
528 pageId = ++pageCounter; | 556 pageId = addPage(tab, message.url, message.isPrerendered); |
529 frameId = 0; | 557 frameId = 0; |
530 | 558 |
531 if (!('_pages' in tab)) | 559 ext.pages.onLoading._dispatch(pages[pageId]); |
532 tab._pages = Object.create(null); | |
533 | |
534 var page = new Page(pageId, tab, message.url); | |
535 pages[pageId] = tab._pages[pageId] = page; | |
536 | |
537 // when a new page is shown, forget the previous page associated | |
538 // with its tab, and reset the toolbar item if necessary. | |
539 // Note that it wouldn't be sufficient to do that when the old | |
540 // page is unloading, because Safari dispatches window.onunload | |
541 // only when reloading the page or following links, but not when | |
542 // you enter a new URL in the address bar. | |
543 if (!message.isPrerendered) | |
544 replacePage(page); | |
545 | |
546 ext.pages.onLoading._dispatch(page); | |
547 } | 560 } |
548 else | 561 else |
549 { | 562 { |
550 var page; | 563 var page; |
551 var parentFrame; | 564 var parentFrame; |
552 | 565 |
553 var lastPageId; | 566 var lastPageId; |
554 var lastPage; | 567 var lastPage; |
555 var lastPageTopLevelFrame; | 568 var lastPageTopLevelFrame; |
556 | 569 |
(...skipping 30 matching lines...) Expand all Loading... | |
587 if (!page) | 600 if (!page) |
588 { | 601 { |
589 pageId = lastPageId; | 602 pageId = lastPageId; |
590 page = lastPage; | 603 page = lastPage; |
591 parentFrame = lastPageTopLevelFrame; | 604 parentFrame = lastPageTopLevelFrame; |
592 } | 605 } |
593 | 606 |
594 frameId = page._frames.length; | 607 frameId = page._frames.length; |
595 page._frames.push({url: new URL(message.url), parent: parentFrame} ); | 608 page._frames.push({url: new URL(message.url), parent: parentFrame} ); |
596 } | 609 } |
597 | |
598 event.message = {pageId: pageId, frameId: frameId}; | 610 event.message = {pageId: pageId, frameId: frameId}; |
599 break; | 611 break; |
600 case "webRequest": | 612 case "webRequest": |
601 var page = pages[event.message.pageId]; | 613 var page = pages[event.message.pageId]; |
602 var frame = page._frames[event.message.frameId]; | 614 var frame = page._frames[event.message.frameId]; |
603 | 615 |
604 var results = ext.webRequest.onBeforeRequest._dispatch( | 616 var results = ext.webRequest.onBeforeRequest._dispatch( |
605 new URL(event.message.url, frame.url), | 617 new URL(event.message.url, frame.url), |
606 event.message.type, page, frame | 618 event.message.type, page, frame |
607 ); | 619 ); |
(...skipping 58 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
666 tab.activate(); | 678 tab.activate(); |
667 if (callback) | 679 if (callback) |
668 callback(page); | 680 callback(page); |
669 return; | 681 return; |
670 } | 682 } |
671 } | 683 } |
672 | 684 |
673 ext.pages.open(optionsUrl, callback); | 685 ext.pages.open(optionsUrl, callback); |
674 }; | 686 }; |
675 })(); | 687 })(); |
OLD | NEW |