| Index: safari/ext/background.js |
| =================================================================== |
| --- a/safari/ext/background.js |
| +++ b/safari/ext/background.js |
| @@ -17,6 +17,19 @@ |
| (function() |
| { |
| + var isTabVisible = function(tab) |
| + { |
| + return tab.browserWindow.visible && tab.browserWindow.activeTab == tab; |
| + }; |
| + |
| + var sentByPreloadedPage = function(message, tab) |
| + { |
| + // the message was sent by a preloaded page if document.hidden was set, |
| + // despite the tab is visible |
| + return message.isDocumentHidden && isTabVisible(tab); |
| + }; |
| + |
| + |
| /* Events */ |
| var TabEventTarget = function() |
| @@ -38,6 +51,7 @@ |
| var LoadingTabEventTarget = function(target) |
| { |
| WrappedEventTarget.call(this, target, "message", false); |
| + this._preloadedTabs = new TabMap(); |
| }; |
| LoadingTabEventTarget.prototype = { |
| __proto__: WrappedEventTarget.prototype, |
| @@ -45,9 +59,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 |
| + // 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 (sentByPreloadedPage(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); |
| + listener(tab); |
| + } |
| + } |
| + }.bind(this); |
| } |
| }; |
| @@ -71,6 +111,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 (sentByPreloadedPage(event.message, event.target)) |
| + { |
| + event.target.page.dispatchMessage("response", { |
| + requestId: event.message.requestId, |
| + deferred: true |
| + }); |
| + return true; |
| + } |
| + |
| + return false; |
| } |
| }; |
| @@ -104,8 +161,18 @@ |
| 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: isTabVisible(this._tab) |
| + } |
| ); |
| } |
| }; |
| @@ -574,16 +641,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 (sentByPreloadedPage(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) |
| { |