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

Unified Diff: safari/ext/content.js

Issue 5092502491103232: Deal with preloadded pages in Safari 7.0 (Closed)
Patch Set: Created Jan. 23, 2014, 3:21 p.m.
Use n/p to move between diff chunks; N/P to move between comments.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « safari/ext/common.js ('k') | no next file » | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: safari/ext/content.js
===================================================================
--- a/safari/ext/content.js
+++ b/safari/ext/content.js
@@ -18,7 +18,7 @@
(function()
{
if (window == window.top)
- safari.self.tab.dispatchMessage("loading");
+ safari.self.tab.dispatchMessage("loading", {isDocumentHidden: document.hidden});
/* Events */
@@ -36,6 +36,14 @@
_getSenderDetails: function(event)
{
return {};
+ },
+ _ignoreIf: function(event)
+ {
+ // If the current page is a preloaded page in Safari 7.0, we have to
+ // ignore all messages sent from the background page. The high-level code
+ // doesn't know anything about preloaded pages and expects messages to be
+ // handled only by the current visible page.
+ return document.hidden && event.message.isTabVisible;
}
};
@@ -279,11 +287,10 @@
/* Web request blocking */
- document.addEventListener("beforeload", function(event)
+ var canLoad = function(event)
{
var type;
-
- switch(event.target.localName)
+ switch (event.target.localName)
{
case "frame":
case "iframe":
@@ -309,17 +316,24 @@
type = "other";
}
- if (!safari.self.tab.canLoad(
+ return safari.self.tab.canLoad(
event, {
type: "webRequest",
payload: {
url: event.url,
type: type,
documentUrl: document.location.href,
- isTopLevel: window == window.top
+ isTopLevel: window == window.top,
+ isDocumentHidden: document.hidden
}
}
- ))
+ );
+ };
+
+ document.addEventListener("beforeload", function(event)
+ {
+ var result;
+ if (event.target._blocked || (result = canLoad(event)) == "blocked")
{
event.preventDefault();
@@ -327,9 +341,11 @@
// element from loading by cancelling the "beforeload" event. So we have
// to dispatch it manually. Otherwise element collapsing wouldn't work.
var evt = document.createEvent("Event");
- evt.initEvent(type == "sub_frame" ? "load" : "error");
+ evt.initEvent(/^i?frame$/.test(event.target.localName) ? "load" : "error");
event.target.dispatchEvent(evt);
}
+ else if (result == "deferred")
+ deferredBeforeLoadEvents.push(event);
}, true);
@@ -339,11 +355,25 @@
sendMessage: function(message, responseCallback)
{
_sendMessage(
- message, responseCallback,
- safari.self.tab, safari.self,
+ // message payload
+ message,
+ // response callback
+ function(response)
+ {
+ if (response.deferred)
+ deferredMessages.push([message, responseCallback]);
+ else if (responseCallback)
+ responseCallback(response.payload);
+ },
+ // message dispatcher
+ safari.self.tab,
+ // response event target
+ safari.self,
+ // extra data
{
documentUrl: document.location.href,
- isTopLevel: window == window.top
+ isTopLevel: window == window.top,
+ isDocumentHidden: document.hidden
}
);
},
@@ -356,6 +386,60 @@
ext.onMessage = new ContentMessageEventTarget();
+ // Starting with Safari 7.0 content scripts also run in preloaded pages.
+ // However our high-level code doesn't know anything about preloaded pages
+ // and expects only one page running in each tab. So we have to defer
+ // all requests to the background page, until the preloaded page is shown.
+
+ var deferredMessages = [];
+ var deferredBeforeLoadEvents = [];
+
+ document.addEventListener("visibilitychange", function()
+ {
+ if (document.hidden)
+ return;
+
+ // notify background page, that it can catch up on onLoading events
+ if (window == window.top)
+ safari.self.tab.dispatchMessage("show");
+
+ // catch up on deferred messages
+ for (var i = 0; i < deferredMessages.length; i++)
+ ext.backgroundPage.sendMessage.apply(null, deferredMessages[i]);
+ deferredMessages = [];
+
+ // catch up on deferred resource blocking
+ for (var i = 0; i < deferredBeforeLoadEvents.length; i++)
+ {
+ var result = canLoad(deferredBeforeLoadEvents[i]);
+ if (result == "blocked")
+ {
+ // if at least one script was supposed to be blocked,
+ // we have to reload the preloaded page. Executed scripts
+ // won't undo themselves by removing them from the DOM
+ var element = deferredBeforeLoadEvents[i].target;
+ if (element.localName == "script")
+ {
+ document.documentElement.style.display = "none";
+ document.location.reload();
+ return;
+ }
+
+ // other resources that were supposed to be blocked are replaced
+ // with an identical clone, in order to trigger "beforeload" again
+ if (element.parentNode)
+ {
+ var clone = element.cloneNode(true);
+ clone._blocked = true; // remember that this should be blocked,
+ // to avoid checking twice
+ element.parentNode.replaceChild(clone, element);
+ }
+ }
+ }
+ deferredBeforeLoadEvents = [];
+ });
+
+
// Safari does not pass the element which the context menu is refering to
// so we need to add it to the event's user info.
document.addEventListener("contextmenu", function(event)
« no previous file with comments | « safari/ext/common.js ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld