Index: safari/ext/background.js |
=================================================================== |
--- a/safari/ext/background.js |
+++ b/safari/ext/background.js |
@@ -17,6 +17,13 @@ |
(function() |
{ |
+ var isPreloadedPage = function(message, tab) |
+ { |
+ // the message was sent by a preloaded page if document.hidden was set, despite the tab is visible |
+ return message.isDocumentHidden && tab.browserWindow.visible && tab.browserWindow.activeTab == tab |
+ }; |
+ |
+ |
/* Events */ |
var TabEventTarget = function() |
@@ -38,6 +45,7 @@ |
var LoadingTabEventTarget = function(target) |
{ |
WrappedEventTarget.call(this, target, "message", false); |
+ this._preloadedTabs = new TabMap(); |
}; |
LoadingTabEventTarget.prototype = { |
__proto__: WrappedEventTarget.prototype, |
@@ -45,9 +53,35 @@ |
{ |
return function (event) |
{ |
- if (event.name == "loading") |
- listener(new Tab(event.target)); |
- }; |
+ switch (event.name) |
+ { |
+ case "loading": |
+ var tab = new Tab(event.target); |
+ |
+ // when the "loading" message was sent form a preloaded |
Wladimir Palant
2014/01/24 14:11:34
form => from
|
+ // page in Safari 7.0, we have to wait until the page is |
+ // shown, before calling the listener. The high-level code |
+ // doesn't know anything about preloaded pages and expects |
+ // all events to be related to the current visible page. |
+ if (isPreloadedPage(event.message, event.target)) |
+ this._preloadedTabs.set(tab, null); |
+ else |
+ { |
+ this._preloadedTabs.delete(tab); |
+ listener(tab); |
+ } |
+ |
+ break; |
+ case "show": |
+ var tab = new Tab(event.target); |
+ |
+ if (this._preloadedTabs.has(tab)) |
+ { |
+ this._preloadedTabs.delete(tab); |
Wladimir Palant
2014/01/24 14:11:34
What if a preloaded page is simply discarded? Won'
Sebastian Noack
2014/01/24 14:17:49
Just temporarily until another page is loaded in t
|
+ listener(tab); |
+ } |
+ } |
+ }.bind(this); |
} |
}; |
@@ -71,6 +105,23 @@ |
event.target |
) |
}; |
+ }, |
+ _ignoreIf: function(event) |
+ { |
+ // when receiving a message from a preloaded page in Safari 7.0, we |
+ // have to defer procesing of that message, until the page is shown. |
+ // The high-level code doesn't know anything about preloaded pages |
+ // and expects all message to be sent from the current visible page. |
+ if (isPreloadedPage(event.message, event.target)) |
+ { |
+ event.target.page.dispatchMessage("response", { |
+ requestId: event.message.requestId, |
+ deferred: true |
+ }); |
+ return true; |
+ } |
+ |
+ return false; |
} |
}; |
@@ -104,8 +155,19 @@ |
sendMessage: function(message, responseCallback) |
{ |
_sendMessage( |
- message, responseCallback, |
- this._tab.page, this._tab |
+ // message payload |
+ message, |
+ // response callback |
+ responseCallback && function(response) { responseCallback(response.payload); }, |
+ // message dispatcher |
+ this._tab.page, |
+ // response event target |
+ this._tab, |
+ // extra data |
+ { |
+ isTabVisible: this._tab.browserWindow.visible && |
+ this._tab.browserWindow.activeTab == this._tab |
+ } |
); |
} |
}; |
@@ -574,16 +636,23 @@ |
_handleMessage: function(message, rawTab) |
{ |
+ // we have to defer loading of resources on preloaded pages |
+ // in Safari 7.0, until the page is shown. The high-level code |
+ // doesn't know anything about preloaded pages and expects all |
+ // web requests to be related to the current visible page. |
+ if (isPreloadedPage(message, rawTab)) |
+ return "deferred"; |
+ |
var tab = new Tab(rawTab); |
var frame = new Frame(message.documentUrl, message.isTopLevel, rawTab); |
for (var i = 0; i < this._listeners.length; i++) |
{ |
if (this._listeners[i](message.url, message.type, tab, frame) === false) |
- return false; |
+ return "blocked"; |
} |
- return true; |
+ return "ok"; |
}, |
addListener: function(listener) |
{ |