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

Unified Diff: safari/ext/content.js

Issue 5088751004942336: Issue 370 - Right-clicked element is removed independent of created filter (Closed)
Patch Set: Rebase to rev 3c9cea80c481 Created July 18, 2014, 8:54 a.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') | safari/ext/popup.js » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: safari/ext/content.js
===================================================================
rename from safari/content.js
rename to safari/ext/content.js
--- a/safari/content.js
+++ b/safari/ext/content.js
@@ -1,6 +1,6 @@
/*
* This file is part of Adblock Plus <http://adblockplus.org/>,
- * Copyright (C) 2006-2013 Eyeo GmbH
+ * Copyright (C) 2006-2014 Eyeo GmbH
*
* Adblock Plus is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 3 as
@@ -17,19 +17,135 @@
(function()
{
- safari.self.tab.dispatchMessage("loading", document.location.href);
+ // the safari object is missing in frames created from javascript: URLs.
+ // So we have to fallback to the safari object from the parent frame.
+ if (!("safari" in window))
+ window.safari = window.parent.safari;
- /* Background page proxy */
- var proxy = {
+ /* Intialization */
+
+ var beforeLoadEvent = document.createEvent("Event");
+ beforeLoadEvent.initEvent("beforeload");
+
+ var isTopLevel = window == window.top;
+ var isPrerendered = document.visibilityState == "prerender";
+
+ var documentInfo = safari.self.tab.canLoad(
+ beforeLoadEvent,
+ {
+ category: "loading",
+ url: document.location.href,
+ referrer: document.referrer,
+ isTopLevel: isTopLevel,
+ isPrerendered: isPrerendered
+ }
+ );
+
+ if (isTopLevel && isPrerendered)
+ {
+ var onVisibilitychange = function()
+ {
+ safari.self.tab.dispatchMessage("replaced", {pageId: documentInfo.pageId});
+ document.removeEventListener("visibilitychange", onVisibilitychange);
+ };
+ document.addEventListener("visibilitychange", onVisibilitychange);
+ }
+
+
+ /* Web requests */
+
+ document.addEventListener("beforeload", function(event)
+ {
+ var url = relativeToAbsoluteUrl(event.url);
+
+ // 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?:/.test(url))
+ return;
+
+ var type;
+ switch(event.target.localName)
+ {
+ case "frame":
+ case "iframe":
+ type = "sub_frame";
+ break;
+ case "img":
+ type = "image";
+ 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;
+ }
+ default:
+ type = "other";
+ }
+
+ if (!safari.self.tab.canLoad(
+ event, {
+ category: "webRequest",
+ url: url,
+ type: type,
+ pageId: documentInfo.pageId,
+ frameId: documentInfo.frameId
+ }
+ ))
+ {
+ event.preventDefault();
+
+ // Safari doesn't dispatch an "error" event when preventing an element
+ // from loading by cancelling the "beforeload" event. So we have to
+ // dispatch it manually. Otherwise element collapsing wouldn't work.
+ if (type != "sub_frame")
+ {
+ setTimeout(function()
+ {
+ var evt = document.createEvent("Event");
+ evt.initEvent("error");
+ event.target.dispatchEvent(evt);
+ }, 0);
+ }
+ }
+ }, true);
+
+
+ /* Context menus */
+
+ document.addEventListener("contextmenu", function(event)
+ {
+ var element = event.srcElement;
+ safari.self.tab.setContextMenuEventUserInfo(event, {
+ pageId: documentInfo.pageId,
+ srcUrl: ("src" in element) ? element.src : null,
+ tagName: element.localName
+ });
+ });
+
+
+ /* Background page */
+
+ var backgroundPageProxy = {
objects: [],
callbacks: [],
send: function(message)
{
- var evt = document.createEvent("Event");
- evt.initEvent("beforeload");
- return safari.self.tab.canLoad(evt, {type: "proxy", payload: message});
+ message.category = "proxy";
+ message.pageId = documentInfo.pageId;
+
+ return safari.self.tab.canLoad(beforeLoadEvent, message);
},
checkResult: function(result)
{
@@ -43,66 +159,57 @@
},
serialize: function(obj, memo)
{
- var objectId = this.objects.indexOf(obj);
- if (objectId != -1)
- return {type: "hosted", objectId: objectId};
+ if (typeof obj == "object" && obj != null || typeof obj == "function")
+ {
+ if ("__proxyObjectId" in obj)
+ return {type: "hosted", objectId: obj.__proxyObjectId};
- if (typeof obj == "function")
- {
- var callbackId = this.callbacks.indexOf(obj);
+ if (typeof obj == "function")
+ {
+ var callbackId;
+ if ("__proxyCallbackId" in obj)
+ callbackId = obj.__proxyCallbackId;
+ else
+ {
+ callbackId = this.callbacks.push(obj) - 1;
+ Object.defineProperty(obj, "__proxyCallbackId", {value: callbackId});
+ }
- if (callbackId == -1)
- {
- callbackId = this.callbacks.push(obj) - 1;
-
- safari.self.addEventListener("message", function(event)
- {
- if (event.name == "proxyCallback")
- if (event.message.callbackId == callbackId)
- obj.apply(
- this.getObject(event.message.contextId),
- this.deserializeSequence(event.message.args)
- );
- }.bind(this));
+ return {type: "callback", callbackId: callbackId, frameId: documentInfo.frameId};
}
- return {type: "callback", callbackId: callbackId};
- }
+ if (obj.constructor != Date && obj.constructor != RegExp)
+ {
+ if (!memo)
+ memo = {specs: [], objects: []};
- if (typeof obj == "object" &&
- obj != null &&
- obj.constructor != Date &&
- obj.constructor != RegExp)
- {
- if (!memo)
- memo = {specs: [], objects: []};
+ var idx = memo.objects.indexOf(obj);
+ if (idx != -1)
+ return memo.specs[idx];
- var idx = memo.objects.indexOf(obj);
- if (idx != -1)
- return memo.specs[idx];
+ var spec = {};
+ memo.specs.push(spec);
+ memo.objects.push(obj);
- var spec = {};
- memo.specs.push(spec);
- memo.objects.push(obj);
+ if (obj.constructor == Array)
+ {
+ spec.type = "array";
+ spec.items = [];
- if (obj.constructor == Array)
- {
- spec.type = "array";
- spec.items = [];
+ for (var i = 0; i < obj.length; i++)
+ spec.items.push(this.serialize(obj[i], memo));
+ }
+ else
+ {
+ spec.type = "object";
+ spec.properties = {};
- for (var i = 0; i < obj.length; i++)
- spec.items.push(this.serialize(obj[i], memo));
+ for (var k in obj)
+ spec.properties[k] = this.serialize(obj[k], memo);
+ }
+
+ return spec;
}
- else
- {
- spec.type = "object";
- spec.properties = {};
-
- for (var k in obj)
- spec.properties[k] = this.serialize(obj[k], memo);
- }
-
- return spec;
}
return {type: "value", value: obj};
@@ -143,10 +250,6 @@
return this.deserializeSequence(spec.items, array, memo);
}
},
- getObjectId: function(obj)
- {
- return this.objects.indexOf(obj);
- },
getProperty: function(objectId, property)
{
return this.deserializeResult(
@@ -164,7 +267,7 @@
return {
get: function()
{
- return proxy.getProperty(proxy.getObjectId(this), property);
+ return proxy.getProperty(this.__proxyObjectId, property);
},
set: function(value)
{
@@ -172,7 +275,7 @@
proxy.send(
{
type: "setProperty",
- objectId: proxy.getObjectId(this),
+ objectId: this.__proxyObjectId,
property: property,
value: proxy.serialize(value)
})
@@ -192,7 +295,7 @@
{
type: "callFunction",
functionId: objectId,
- contextId: proxy.getObjectId(this),
+ contextId: this.__proxyObjectId,
args: Array.prototype.map.call(
arguments,
proxy.serialize.bind(proxy)
@@ -201,7 +304,15 @@
);
};
},
- getObject: function(objectId) {
+ handleCallback: function(message)
+ {
+ this.callbacks[message.callbackId].apply(
+ this.getObject(message.contextId),
+ this.deserializeSequence(message.args)
+ );
+ },
+ getObject: function(objectId)
+ {
var objectInfo = this.send({
type: "inspectObject",
objectId: objectId
@@ -218,24 +329,27 @@
obj = {};
this.objects[objectId] = obj;
+ Object.defineProperty(obj, "__proxyObjectId", {value: objectId});
}
- var ignored = [];
+ var excluded = [];
+ var included = [];
if ("prototypeOf" in objectInfo)
{
var prototype = window[objectInfo.prototypeOf].prototype;
- ignored = Object.getOwnPropertyNames(prototype);
- ignored.splice(ignored.indexOf("constructor"), 1);
+ excluded = Object.getOwnPropertyNames(prototype);
+ included = ["constructor"];
obj.__proto__ = prototype;
}
else
{
if (objectInfo.isFunction)
- ignored = Object.getOwnPropertyNames(function() {});
- else
- ignored = [];
+ {
+ excluded = Object.getOwnPropertyNames(function() {});
+ included = ["prototype"];
+ }
if ("prototypeId" in objectInfo)
obj.__proto__ = this.getObject(objectInfo.prototypeId);
@@ -244,65 +358,64 @@
}
for (var property in objectInfo.properties)
- if (ignored.indexOf(property) == -1)
- Object.defineProperty(obj, property, this.createProperty(
- property, objectInfo.properties[property].enumerable
- ));
+ {
+ if (excluded.indexOf(property) == -1 || included.indexOf(property) != -1)
+ {
+ var desc = Object.getOwnPropertyDescriptor(obj, property);
- if (objectInfo.isFunction)
- obj.prototype = this.getProperty(objectId, "prototype");
+ if (!desc || desc.configurable)
+ {
+ Object.defineProperty(obj, property, this.createProperty(
+ property, objectInfo.properties[property].enumerable
+ ));
+ }
+ else if (desc.writable)
+ obj[property] = this.getProperty(objectId, property);
+ }
+ }
return obj;
}
};
-
- /* Web request blocking */
-
- document.addEventListener("beforeload", function(event)
- {
- var type;
-
- switch(event.target.nodeName)
+ ext.backgroundPage = {
+ sendMessage: function(message, responseCallback)
{
- case "FRAME":
- case "IFRAME":
- type = "frame";
- break;
- case "IMG":
- type = "image";
- break;
- case "OBJECT":
- case "EMBED":
- type = "object";
- break;
- case "SCRIPT":
- type = "script";
- break;
- case "LINK":
- if (/(^|\s)stylesheet($|\s)/i.test(event.target.rel))
- {
- type = "stylesheet";
- break;
- }
- default:
- type = "other";
+ messageProxy.sendMessage(message, responseCallback, documentInfo);
+ },
+ getWindow: function()
+ {
+ return backgroundPageProxy.getObject(0);
}
-
- if (!safari.self.tab.canLoad(event, {type: "webRequest", payload: {url: event.url, type: type}}))
- event.preventDefault();
- }, true);
-
-
- /* API */
-
- ext.backgroundPage = {
- _eventTarget: safari.self,
- _messageDispatcher: safari.self.tab,
-
- sendMessage: sendMessage,
- getWindow: function() { return proxy.getObject(0); }
};
- ext.onMessage = new MessageEventTarget(safari.self);
+
+ /* Message processing */
+
+ var messageProxy = new ext._MessageProxy(safari.self.tab);
+
+ safari.self.addEventListener("message", function(event)
+ {
+ if (event.message.pageId == documentInfo.pageId)
+ {
+ if (event.name == "request")
+ {
+ messageProxy.handleRequest(event.message, {});
+ return;
+ }
+
+ if (event.message.frameId == documentInfo.frameId)
+ {
+ switch (event.name)
+ {
+ case "response":
+ messageProxy.handleResponse(event.message);
+ break;
+ case "proxyCallback":
+ backgroundPageProxy.handleCallback(event.message);
+ break;
+ }
+ }
+ }
+ });
})();
« no previous file with comments | « safari/ext/common.js ('k') | safari/ext/popup.js » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld