OLD | NEW |
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-2014 Eyeo GmbH | 3 * Copyright (C) 2006-2014 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 /* Pages */ |
21 | 21 |
22 var pages = {__proto__: null}; | 22 var pages = {__proto__: null}; |
23 var pageCounter = 0; | 23 var pageCounter = 0; |
24 | 24 |
25 var Page = function(id, tab, url, prerendered) | 25 var Page = function(id, tab, url) |
26 { | 26 { |
27 this._id = id; | 27 this._id = id; |
28 this._tab = tab; | 28 this._tab = tab; |
29 this._frames = [{url: url, parent: null}]; | 29 this._frames = [{url: url, parent: null}]; |
30 this._prerendered = prerendered; | |
31 | 30 |
32 if (tab.page) | 31 if (tab.page) |
33 this._messageProxy = new ext._MessageProxy(tab.page); | 32 this._messageProxy = new ext._MessageProxy(tab.page); |
34 else | 33 else |
35 // while the new tab page is shown on Safari 7, the 'page' property | 34 // while the new tab page is shown on Safari 7, the 'page' property |
36 // of the tab is undefined, and we can't send messages to that page | 35 // of the tab is undefined, and we can't send messages to that page |
37 this._messageProxy = { | 36 this._messageProxy = { |
38 handleRequest: function() {}, | 37 handleRequest: function() {}, |
39 handleResponse: function() {}, | 38 handleResponse: function() {}, |
40 sendMessage: function() {} | 39 sendMessage: function() {} |
(...skipping 16 matching lines...) Expand all Loading... |
57 this._tab.close(); | 56 this._tab.close(); |
58 }, | 57 }, |
59 sendMessage: function(message, responseCallback) | 58 sendMessage: function(message, responseCallback) |
60 { | 59 { |
61 this._messageProxy.sendMessage(message, responseCallback, {pageId: this._i
d}); | 60 this._messageProxy.sendMessage(message, responseCallback, {pageId: this._i
d}); |
62 } | 61 } |
63 }; | 62 }; |
64 | 63 |
65 var isPageActive = function(page) | 64 var isPageActive = function(page) |
66 { | 65 { |
67 return page._tab == page._tab.browserWindow.activeTab && !page._prerendered; | 66 var tab = page._tab; |
| 67 return tab == tab.browserWindow.activeTab && page == tab._visiblePage; |
68 }; | 68 }; |
69 | 69 |
70 var forgetPage = function(id) | 70 var forgetPage = function(id) |
71 { | 71 { |
72 ext._removeFromAllPageMaps(id); | 72 ext._removeFromAllPageMaps(id); |
| 73 |
| 74 delete pages[id]._tab._pages[id]; |
73 delete pages[id]; | 75 delete pages[id]; |
74 }; | 76 }; |
75 | 77 |
76 var replacePage = function(page) | 78 var replacePage = function(page) |
77 { | 79 { |
78 for (var id in pages) | 80 page._tab._visiblePage = page; |
| 81 |
| 82 for (var id in page._tab._pages) |
79 { | 83 { |
80 if (id != page._id && pages[id]._tab == page._tab) | 84 if (id != page._id) |
81 forgetPage(id); | 85 forgetPage(id); |
82 } | 86 } |
83 | 87 |
84 if (isPageActive(page)) | 88 if (isPageActive(page)) |
85 updateToolbarItemForPage(page); | 89 updateToolbarItemForPage(page); |
86 }; | 90 }; |
87 | 91 |
88 ext.pages = { | 92 ext.pages = { |
89 open: function(url, callback) | 93 open: function(url, callback) |
90 { | 94 { |
(...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
132 // this event is dispatched on closing windows and tabs. However when a | 136 // this event is dispatched on closing windows and tabs. However when a |
133 // window is closed, it is first dispatched on each tab in the window and | 137 // window is closed, it is first dispatched on each tab in the window and |
134 // then on the window itself. But we are only interested in closed tabs. | 138 // then on the window itself. But we are only interested in closed tabs. |
135 if (!(event.target instanceof SafariBrowserTab)) | 139 if (!(event.target instanceof SafariBrowserTab)) |
136 return; | 140 return; |
137 | 141 |
138 // when a tab is closed, forget the previous page associated with that | 142 // when a tab is closed, forget the previous page associated with that |
139 // tab. Note that it wouldn't be sufficient do that when the old page | 143 // tab. Note that it wouldn't be sufficient do that when the old page |
140 // is unloading, because Safari dispatches window.onunload only when | 144 // is unloading, because Safari dispatches window.onunload only when |
141 // reloading the page or following links, but not when closing the tab. | 145 // reloading the page or following links, but not when closing the tab. |
142 for (var id in pages) | 146 for (var id in event.target._pages) |
143 { | 147 forgetPage(id); |
144 if (pages[id]._tab == event.target) | |
145 forgetPage(id); | |
146 } | |
147 }, true); | 148 }, true); |
148 | 149 |
149 | 150 |
150 /* Browser actions */ | 151 /* Browser actions */ |
151 | 152 |
152 var toolbarItemProperties = {}; | 153 var toolbarItemProperties = {}; |
153 | 154 |
154 var getToolbarItemForWindow = function(win) | 155 var getToolbarItemForWindow = function(win) |
155 { | 156 { |
156 for (var i = 0; i < safari.extension.toolbarItems.length; i++) | 157 for (var i = 0; i < safari.extension.toolbarItems.length; i++) |
(...skipping 63 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
220 { | 221 { |
221 // this event is also dispatched on windows that got focused. But we | 222 // this event is also dispatched on windows that got focused. But we |
222 // are only interested in tabs, which became active in their window. | 223 // are only interested in tabs, which became active in their window. |
223 if (!(event.target instanceof SafariBrowserTab)) | 224 if (!(event.target instanceof SafariBrowserTab)) |
224 return; | 225 return; |
225 | 226 |
226 // update the toolbar item for the page visible in the tab that just | 227 // update the toolbar item for the page visible in the tab that just |
227 // became active. If we can't find that page (e.g. when a page was | 228 // became active. If we can't find that page (e.g. when a page was |
228 // opened in a new tab, and our content script didn't run yet), the | 229 // opened in a new tab, and our content script didn't run yet), the |
229 // toolbar item of the window, is reset to its intial configuration. | 230 // toolbar item of the window, is reset to its intial configuration. |
230 var activePage = null; | 231 updateToolbarItemForPage(event.target._visiblePage, event.target.browserWind
ow); |
231 for (var id in pages) | |
232 { | |
233 var page = pages[id]; | |
234 if (page._tab == event.target && !page._prerendered) | |
235 { | |
236 activePage = page; | |
237 break; | |
238 } | |
239 } | |
240 | |
241 updateToolbarItemForPage(activePage, event.target.browserWindow); | |
242 }, true); | 232 }, true); |
243 | 233 |
244 | 234 |
245 /* Context menus */ | 235 /* Context menus */ |
246 | 236 |
247 var contextMenuItems = new ext.PageMap(); | 237 var contextMenuItems = new ext.PageMap(); |
248 | 238 |
249 var ContextMenus = function(page) | 239 var ContextMenus = function(page) |
250 { | 240 { |
251 this._page = page; | 241 this._page = page; |
(...skipping 281 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
533 var page = null; | 523 var page = null; |
534 var frame = null; | 524 var frame = null; |
535 | 525 |
536 var lastPage; | 526 var lastPage; |
537 var lastPageTopLevelFrame; | 527 var lastPageTopLevelFrame; |
538 | 528 |
539 // find the parent frame and its page for this sub frame, | 529 // find the parent frame and its page for this sub frame, |
540 // by matching its referrer with the URL of frames previously | 530 // by matching its referrer with the URL of frames previously |
541 // loaded in the same tab. If there is more than one match, | 531 // loaded in the same tab. If there is more than one match, |
542 // the most recent loaded page and frame is preferred. | 532 // the most recent loaded page and frame is preferred. |
543 for (var curPageId in pages) | 533 for (var curPageId in (tab ? tab._pages : pages)) |
544 { | 534 { |
545 var curPage = pages[curPageId]; | 535 var curPage = pages[curPageId]; |
546 if (tab && curPage._tab != tab) | |
547 continue; | |
548 | 536 |
549 for (var i = 0; i < curPage._frames.length; i++) | 537 for (var i = 0; i < curPage._frames.length; i++) |
550 { | 538 { |
551 var curFrame = curPage._frames[i]; | 539 var curFrame = curPage._frames[i]; |
552 | 540 |
553 if (curFrame.url == url) | 541 if (curFrame.url == url) |
554 { | 542 { |
555 page = curPage; | 543 page = curPage; |
556 frame = curFrame; | 544 frame = curFrame; |
557 } | 545 } |
(...skipping 15 matching lines...) Expand all Loading... |
573 }; | 561 }; |
574 | 562 |
575 safari.application.addEventListener("message", function(event) | 563 safari.application.addEventListener("message", function(event) |
576 { | 564 { |
577 switch (event.name) | 565 switch (event.name) |
578 { | 566 { |
579 case "canLoad": | 567 case "canLoad": |
580 switch (event.message.category) | 568 switch (event.message.category) |
581 { | 569 { |
582 case "loading": | 570 case "loading": |
| 571 var tab = event.target; |
| 572 var message = event.message; |
| 573 |
583 var pageId; | 574 var pageId; |
584 var frameId; | 575 var frameId; |
585 | 576 |
586 if (event.message.isTopLevel) | 577 if (message.isTopLevel) |
587 { | 578 { |
588 pageId = ++pageCounter; | 579 pageId = ++pageCounter; |
589 frameId = 0; | 580 frameId = 0; |
590 | 581 |
591 var isPrerendered = event.message.isPrerendered; | 582 var page = new Page(pageId, tab, message.url); |
592 var page = new Page( | |
593 pageId, | |
594 event.target, | |
595 event.message.url, | |
596 isPrerendered | |
597 ); | |
598 | 583 |
599 if (event.message.isPopup && !event.target._popupLoaded) | 584 if (message.isPopup && !tab._popupLoaded) |
600 { | 585 { |
601 if (!("_opener" in event.target)) | 586 if (!("_opener" in tab)) |
602 event.target._opener = findPageAndFrame(null, event.message.re
ferrer); | 587 tab._opener = findPageAndFrame(null, message.referrer); |
603 | 588 |
604 if (page.url != "about:blank") | 589 if (page.url != "about:blank") |
605 event.target._popupLoaded = true; | 590 tab._popupLoaded = true; |
606 | 591 |
607 ext.pages.onPopup._dispatch(page, event.target._opener); | 592 ext.pages.onPopup._dispatch(page, tab._opener); |
608 } | 593 } |
609 | 594 |
610 if (event.target.browserWindow) | 595 if (tab.browserWindow) |
611 { | 596 { |
612 pages[pageId] = page; | 597 pages[pageId] = (tab._pages || (tab._pages = {__proto__: null}))
[pageId] = page; |
613 | 598 |
614 // when a new page is shown, forget the previous page associated | 599 // when a new page is shown, forget the previous page associated |
615 // with its tab, and reset the toolbar item if necessary. | 600 // with its tab, and reset the toolbar item if necessary. |
616 // Note that it wouldn't be sufficient to do that when the old | 601 // Note that it wouldn't be sufficient to do that when the old |
617 // page is unloading, because Safari dispatches window.onunload | 602 // page is unloading, because Safari dispatches window.onunload |
618 // only when reloading the page or following links, but not when | 603 // only when reloading the page or following links, but not when |
619 // you enter a new URL in the address bar. | 604 // you enter a new URL in the address bar. |
620 if (!isPrerendered) | 605 if (!message.isPrerendered) |
621 replacePage(page); | 606 replacePage(page); |
622 | 607 |
623 ext.pages.onLoading._dispatch(page); | 608 ext.pages.onLoading._dispatch(page); |
624 } | 609 } |
625 } | 610 } |
626 else | 611 else |
627 { | 612 { |
628 var parent = findPageAndFrame(event.target, event.message.referrer
); | 613 var parent = findPageAndFrame(tab, message.referrer); |
629 | 614 |
630 pageId = parent.page._id; | 615 pageId = parent.page._id; |
631 frameId = parent.page._frames.length; | 616 frameId = parent.page._frames.length; |
632 | 617 |
633 parent.page._frames.push({ | 618 parent.page._frames.push({url: message.url, parent: parent.frame})
; |
634 url: event.message.url, | |
635 parent: parent.frame | |
636 }); | |
637 } | 619 } |
638 | 620 |
639 event.message = {pageId: pageId, frameId: frameId}; | 621 event.message = {pageId: pageId, frameId: frameId}; |
640 break; | 622 break; |
641 case "webRequest": | 623 case "webRequest": |
642 var page = pages[event.message.pageId]; | 624 var page = pages[event.message.pageId]; |
643 | 625 |
644 event.message = ext.webRequest.onBeforeRequest._dispatch( | 626 event.message = ext.webRequest.onBeforeRequest._dispatch( |
645 event.message.url, | 627 event.message.url, |
646 event.message.type, | 628 event.message.type, |
647 page, | 629 page, |
648 page._frames[event.message.frameId] | 630 page._frames[event.message.frameId] |
649 ); | 631 ); |
650 break; | 632 break; |
651 case "proxy": | 633 case "proxy": |
652 event.message = backgroundPageProxy.handleMessage(event.message); | 634 event.message = backgroundPageProxy.handleMessage(event.message); |
653 break; | 635 break; |
654 } | 636 } |
655 break; | 637 break; |
656 case "request": | 638 case "request": |
657 var page = pages[event.message.pageId]; | 639 var page = pages[event.message.pageId]; |
658 var sender = {page: page, frame: page._frames[event.message.frameId]}; | 640 var sender = {page: page, frame: page._frames[event.message.frameId]}; |
659 page._messageProxy.handleRequest(event.message, sender); | 641 page._messageProxy.handleRequest(event.message, sender); |
660 break; | 642 break; |
661 case "response": | 643 case "response": |
662 pages[event.message.pageId]._messageProxy.handleResponse(event.message); | 644 pages[event.message.pageId]._messageProxy.handleResponse(event.message); |
663 break; | 645 break; |
664 case "replaced": | 646 case "replaced": |
665 var page = pages[event.message.pageId]; | |
666 page._prerendered = false; | |
667 | |
668 // when a prerendered page is shown, forget the previous page | 647 // when a prerendered page is shown, forget the previous page |
669 // associated with its tab, and reset the toolbar item if necessary. | 648 // associated with its tab, and reset the toolbar item if necessary. |
670 // Note that it wouldn't be sufficient to do that when the old | 649 // Note that it wouldn't be sufficient to do that when the old |
671 // page is unloading, because Safari dispatches window.onunload | 650 // page is unloading, because Safari dispatches window.onunload |
672 // only when reloading the page or following links, but not when | 651 // only when reloading the page or following links, but not when |
673 // the current page is replaced with a prerendered page. | 652 // the current page is replaced with a prerendered page. |
674 replacePage(page); | 653 replacePage(pages[event.message.pageId]); |
675 break; | 654 break; |
676 } | 655 } |
677 }); | 656 }); |
678 | 657 |
679 | 658 |
680 /* Storage */ | 659 /* Storage */ |
681 | 660 |
682 ext.storage = safari.extension.settings; | 661 ext.storage = safari.extension.settings; |
683 })(); | 662 })(); |
OLD | NEW |