 Issue 6346177440120832:
  Added abstraction for frames, to fix domain-based rules, whitelisting and ad counter on Safari  (Closed)
    
  
    Issue 6346177440120832:
  Added abstraction for frames, to fix domain-based rules, whitelisting and ad counter on Safari  (Closed) 
  | Index: safari/ext/background.js | 
| =================================================================== | 
| --- a/safari/ext/background.js | 
| +++ b/safari/ext/background.js | 
| @@ -17,7 +17,7 @@ | 
| (function() | 
| { | 
| - /* Tabs */ | 
| + /* Events */ | 
| var TabEventTarget = function() | 
| { | 
| @@ -51,14 +51,38 @@ | 
| } | 
| }; | 
| + var BackgroundMessageEventTarget = function() | 
| + { | 
| + MessageEventTarget.call(this, safari.application); | 
| + }; | 
| + BackgroundMessageEventTarget.prototype = { | 
| + __proto__: MessageEventTarget.prototype, | 
| + _getResponseDispatcher: function(event) | 
| + { | 
| + return event.target.page; | 
| + }, | 
| + _getSenderDetails: function(event) | 
| + { | 
| + return { | 
| + tab: new Tab(event.target), | 
| + frame: new Frame( | 
| + event.message.documentUrl, | 
| + event.message.isTopLevel, | 
| + event.target | 
| + ) | 
| + }; | 
| + } | 
| + }; | 
| + | 
| + | 
| + /* Tabs */ | 
| + | 
| Tab = function(tab) | 
| { | 
| this._tab = tab; | 
| - this._eventTarget = tab; | 
| - this._messageDispatcher = tab.page; | 
| - | 
| this.onLoading = new LoadingTabEventTarget(tab); | 
| + this.onBeforeNavigate = new TabEventTarget(tab, "beforeNavigate", false); | 
| this.onCompleted = new TabEventTarget(tab, "navigate", false); | 
| this.onActivated = new TabEventTarget(tab, "activate", false); | 
| this.onRemoved = new TabEventTarget(tab, "close", false); | 
| @@ -76,7 +100,13 @@ | 
| { | 
| this._tab.activate(); | 
| }, | 
| - sendMessage: sendMessage, | 
| + sendMessage: function(message, responseCallback) | 
| + { | 
| + _sendMessage( | 
| + message, responseCallback, | 
| + this._tab.page, this._tab | 
| + ); | 
| + }, | 
| browserAction: { | 
| setIcon: function(path) | 
| { | 
| @@ -96,12 +126,13 @@ | 
| } | 
| }; | 
| - TabMap = function() | 
| + TabMap = function(deleteTabOnBeforeNavigate) | 
| { | 
| this._tabs = []; | 
| this._values = []; | 
| - this._onClosed = this._onClosed.bind(this); | 
| + this._deleteOnEvent = this._deleteOnEvent.bind(this); | 
| + this._deleteTabOnBeforeNavigate = deleteTabOnBeforeNavigate; | 
| }; | 
| TabMap.prototype = | 
| { | 
| @@ -124,7 +155,9 @@ | 
| this._tabs.push(tab._tab); | 
| this._values.push(value); | 
| - tab._tab.addEventListener("close", this._onClosed, false); | 
| + tab._tab.addEventListener("close", this._deleteOnEvent, false); | 
| + if (this._deleteTabOnBeforeNavigate) | 
| + tab._tab.addEventListener("beforeNavigate", this._deleteOnEvent, false); | 
| } | 
| }, | 
| has: function(tab) | 
| @@ -145,12 +178,14 @@ | 
| this._tabs.splice(idx, 1); | 
| this._values.splice(idx, 1); | 
| - tab.removeEventListener("close", this._onClosed, false); | 
| + tab.removeEventListener("close", this._deleteOnEvent, false); | 
| + tab.removeEventListener("beforeNavigate", this._deleteOnEvent, false); | 
| } | 
| }, | 
| - _onClosed: function(event) | 
| + _deleteOnEvent: function(event) | 
| { | 
| - this._delete(event.target); | 
| + // delay so that other event handlers can still lookup this tab | 
| + setTimeout(this._delete.bind(this, event.target), 0); | 
| 
Felix Dahlke
2014/01/18 13:39:19
s/lookup this tab/look this tab up/
 
Sebastian Noack
2014/01/19 10:19:40
Done.
 | 
| } | 
| }; | 
| TabMap.prototype["delete"] = function(tab) | 
| @@ -189,6 +224,22 @@ | 
| }; | 
| + /* Frames */ | 
| + | 
| + Frame = function(url, isTopLevel, tab) | 
| + { | 
| + this.url = url; | 
| + | 
| + // there is no way to discover frames with Safari's API. | 
| + // so if this isn't the top level frame, assume that the parent is. | 
| + // this is the best we can do for Safari. :( | 
| 
Felix Dahlke
2014/01/18 13:39:19
We could cache a chain of frames like we do in And
 | 
| + if (!isTopLevel) | 
| + this.parent = new Frame(tab.url, true); | 
| + else | 
| + this.parent = null; | 
| + }; | 
| + | 
| + | 
| /* Background page proxy */ | 
| var proxy = { | 
| @@ -419,47 +470,29 @@ | 
| ext.webRequest = { | 
| onBeforeRequest: { | 
| _listeners: [], | 
| - _urlPatterns: [], | 
| - _handleMessage: function(message, tab) | 
| + _handleMessage: function(message, rawTab) | 
| { | 
| - tab = new Tab(tab); | 
| + var tab = new Tab(rawTab); | 
| + var frame = new Frame(message.documentUrl, message.isTopLevel, rawTab); | 
| for (var i = 0; i < this._listeners.length; i++) | 
| { | 
| - var regex = this._urlPatterns[i]; | 
| - | 
| - if ((!regex || regex.test(message.url)) && this._listeners[i](message.url, message.type, tab, 0, -1) === false) | 
| + if (this._listeners[i](message.url, message.type, tab, frame) === false) | 
| return false; | 
| } | 
| return true; | 
| }, | 
| - addListener: function(listener, urls) | 
| + addListener: function(listener) | 
| { | 
| - var regex; | 
| - | 
| - if (urls) | 
| - regex = new RegExp("^(?:" + urls.map(function(url) | 
| - { | 
| - return url.split("*").map(function(s) | 
| - { | 
| - return s.replace(/([.?+^$[\]\\(){}|-])/g, "\\$1"); | 
| - }).join(".*"); | 
| - }).join("|") + ")($|[?#])"); | 
| - | 
| this._listeners.push(listener); | 
| - this._urlPatterns.push(regex); | 
| }, | 
| removeListener: function(listener) | 
| { | 
| var idx = this._listeners.indexOf(listener); | 
| - | 
| if (idx != -1) | 
| - { | 
| this._listeners.splice(idx, 1); | 
| - this._urlPatterns.splice(idx, 1); | 
| - } | 
| } | 
| }, | 
| handlerBehaviorChanged: function() {} | 
| @@ -507,6 +540,7 @@ | 
| ext.tabs = { | 
| onLoading: new LoadingTabEventTarget(safari.application), | 
| + onBeforeNavigate: new TabEventTarget(safari.application, "beforeNavigate", true), | 
| onCompleted: new TabEventTarget(safari.application, "navigate", true), | 
| onActivated: new TabEventTarget(safari.application, "activate", true), | 
| onRemoved: new TabEventTarget(safari.application, "close", true) | 
| @@ -519,7 +553,7 @@ | 
| } | 
| }; | 
| - ext.onMessage = new MessageEventTarget(safari.application); | 
| + ext.onMessage = new BackgroundMessageEventTarget(); | 
| // TODO: Implement context menu | 
| ext.contextMenus = { |