 Issue 29340571:
  Issue 3687 - Add experimental support for Safari content blockers  (Closed)
    
  
    Issue 29340571:
  Issue 3687 - Add experimental support for Safari content blockers  (Closed) 
  | Index: safari/ext/content.js | 
| diff --git a/safari/ext/content.js b/safari/ext/content.js | 
| index 164d1a4d9574b6b1e4ef569a15260b2f313f57db..3d095c134468438493dfbbb321159a17a498375e 100644 | 
| --- a/safari/ext/content.js | 
| +++ b/safari/ext/content.js | 
| @@ -28,6 +28,21 @@ | 
| var beforeLoadEvent = document.createEvent("Event"); | 
| beforeLoadEvent.initEvent("beforeload"); | 
| + // Decide if we should use the new content blocker API or not. (Note when the | 
| + // API is used Safari breaks the canLoad function, making it either throw an | 
| + // exception or return true when used.) | 
| + var usingContentBlockerAPI = true; | 
| + try | 
| + { | 
| + if (safari.self.tab.canLoad(beforeLoadEvent, | 
| + {category: "request", | 
| + payload: {type: "prefs.get", | 
| + key: "safariContentBlocker"}}) != true) | 
| + usingContentBlockerAPI = false; | 
| + } | 
| + catch (e) | 
| + { } | 
| 
Sebastian Noack
2016/05/18 11:16:33
Nit: The closing brace should go on a new line as
 
kzar
2016/05/18 11:32:08
Done.
 | 
| + | 
| var isTopLevel; | 
| var isPrerendered; | 
| var documentId; | 
| @@ -46,7 +61,9 @@ | 
| referrer: document.referrer, | 
| isTopLevel: isTopLevel, | 
| isPrerendered: isPrerendered, | 
| - documentId: documentId | 
| + documentId: documentId, | 
| + legacyAPISupported: "canLoad" in safari.self.tab && | 
| + "onbeforeload" in Element.prototype | 
| }); | 
| } | 
| @@ -60,83 +77,87 @@ | 
| notifyFrameLoading(); | 
| }); | 
| - // Notify the background page when a prerendered page is displayed. That way | 
| - // the existing page of the tab can be replaced with this new one. | 
| - if (isTopLevel && isPrerendered) | 
| + if (!usingContentBlockerAPI) | 
| { | 
| - var onVisibilitychange = function() | 
| + // Notify the background page when a prerendered page is displayed. That way | 
| + // the existing page of the tab can be replaced with this new one. | 
| + if (isTopLevel && isPrerendered) | 
| { | 
| - safari.self.tab.dispatchMessage("replaced", {documentId: documentId}); | 
| - document.removeEventListener("visibilitychange", onVisibilitychange); | 
| - }; | 
| - document.addEventListener("visibilitychange", onVisibilitychange); | 
| - } | 
| - | 
| + var onVisibilitychange = function() | 
| + { | 
| + safari.self.tab.dispatchMessage("replaced", {documentId: documentId}); | 
| + document.removeEventListener("visibilitychange", onVisibilitychange); | 
| + }; | 
| + document.addEventListener("visibilitychange", onVisibilitychange); | 
| + } | 
| /* Web requests */ | 
| - document.addEventListener("beforeload", function(event) | 
| - { | 
| - // we don't block non-HTTP requests anyway, so we can bail out | 
| - // without asking the background page. This is even necessary | 
| - // because passing large data (like a photo encoded as data: URL) | 
| - // to the background page, freezes Safari. | 
| - if (/^(?!https?:)[\w-]+:/.test(event.url)) | 
| - return; | 
| + document.addEventListener("beforeload", function(event) | 
| + { | 
| + // we don't block non-HTTP requests anyway, so we can bail out | 
| + // without asking the background page. This is even necessary | 
| + // because passing large data (like a photo encoded as data: URL) | 
| + // to the background page, freezes Safari. | 
| + if (/^(?!https?:)[\w-]+:/.test(event.url)) | 
| + return; | 
| - var type = "OTHER"; | 
| - var eventName = "error"; | 
| + var type = "OTHER"; | 
| + var eventName = "error"; | 
| - switch(event.target.localName) | 
| - { | 
| - case "frame": | 
| - case "iframe": | 
| - type = "SUBDOCUMENT"; | 
| - eventName = "load"; | 
| - break; | 
| - case "img": | 
| - case "input": | 
| - type = "IMAGE"; | 
| - break; | 
| - case "video": | 
| - case "audio": | 
| - case "source": | 
| - type = "MEDIA"; | 
| - break; | 
| - case "object": | 
| - case "embed": | 
| - type = "OBJECT"; | 
| - break; | 
| - case "script": | 
| - type = "SCRIPT"; | 
| - break; | 
| - case "link": | 
| - if (/\bstylesheet\b/i.test(event.target.rel)) | 
| - type = "STYLESHEET"; | 
| - break; | 
| - } | 
| + switch(event.target.localName) | 
| + { | 
| + case "frame": | 
| + case "iframe": | 
| + type = "SUBDOCUMENT"; | 
| + eventName = "load"; | 
| + break; | 
| + case "img": | 
| + case "input": | 
| + type = "IMAGE"; | 
| + break; | 
| + case "video": | 
| + case "audio": | 
| + case "source": | 
| + type = "MEDIA"; | 
| + break; | 
| + case "object": | 
| + case "embed": | 
| + type = "OBJECT"; | 
| + break; | 
| + case "script": | 
| + type = "SCRIPT"; | 
| + break; | 
| + case "link": | 
| + if (/\bstylesheet\b/i.test(event.target.rel)) | 
| + type = "STYLESHEET"; | 
| + break; | 
| + } | 
| - if (!safari.self.tab.canLoad(event, { | 
| - category: "webRequest", | 
| - url: event.url, | 
| - type: type, | 
| - documentId: documentId})) | 
| - { | 
| - event.preventDefault(); | 
| - | 
| - // Safari doesn't dispatch the expected events for elements that have been | 
| - // prevented from loading by having their "beforeload" event cancelled. | 
| - // That is a "load" event for blocked frames, and an "error" event for | 
| - // other blocked elements. We need to dispatch those events manually here | 
| - // to avoid breaking element collapsing and pages that rely on those events. | 
| - setTimeout(function() | 
| + if (!safari.self.tab.canLoad( | 
| + event, { | 
| + category: "webRequest", | 
| + url: event.url, | 
| + type: type, | 
| + documentId: documentId})) | 
| { | 
| - var evt = document.createEvent("Event"); | 
| - evt.initEvent(eventName); | 
| - event.target.dispatchEvent(evt); | 
| - }, 0); | 
| - } | 
| - }, true); | 
| + event.preventDefault(); | 
| + | 
| + // Safari doesn't dispatch the expected events for elements that have | 
| + // been prevented from loading by having their "beforeload" event | 
| + // cancelled. That is a "load" event for blocked frames, and an "error" | 
| + // event for other blocked elements. We need to dispatch those events | 
| + // manually here to avoid breaking element collapsing and pages that | 
| + // rely on those events. | 
| + setTimeout(function() | 
| + { | 
| + var evt = document.createEvent("Event"); | 
| + evt.initEvent(eventName); | 
| + event.target.dispatchEvent(evt); | 
| + }, 0); | 
| 
Sebastian Noack
2016/05/18 11:16:33
Nit: 0 is the default for the second argument to s
 
kzar
2016/05/18 11:32:08
Done.
 | 
| + } | 
| + }, true); | 
| + } | 
| /* Context menus */ |