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

Unified Diff: safari/content.js

Issue 16067002: Added Safari Support (Closed)
Patch Set: Bugfixes Created Nov. 15, 2013, 8:58 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/common.js ('k') | stats.js » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: safari/content.js
===================================================================
new file mode 100644
--- /dev/null
+++ b/safari/content.js
@@ -0,0 +1,301 @@
+/*
+ * This file is part of Adblock Plus <http://adblockplus.org/>,
+ * Copyright (C) 2006-2013 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
+ * published by the Free Software Foundation.
+ *
+ * Adblock Plus is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Adblock Plus. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+(function()
+{
+ /* Background page proxy */
+ var proxy = {
+ objects: [],
+ callbacks: [],
+
+ send: function(message)
+ {
+ var evt = document.createEvent("Event");
+ evt.initEvent("beforeload");
+ return safari.self.tab.canLoad(evt, {type: "proxy", payload: message});
+ },
+ checkResult: function(result)
+ {
+ if (!result.succeed)
+ throw result.error;
+ },
+ deserializeResult: function(result)
+ {
+ this.checkResult(result);
+ return this.deserialize(result.result);
+ },
+ serialize: function(obj, memo)
+ {
+ var objectId = this.objects.indexOf(obj);
+ if (objectId != -1)
+ return {type: "hosted", objectId: objectId};
+
+ if (typeof obj == "function")
+ {
+ var callbackId = this.callbacks.indexOf(obj);
+
+ 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};
+ }
+
+ 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 spec = {};
+ memo.specs.push(spec);
+ memo.objects.push(obj);
+
+ 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 k in obj)
+ spec.properties[k] = this.serialize(obj[k], memo);
+ }
+
+ return spec;
+ }
+
+ return {type: "value", value: obj};
+ },
+ deserializeSequence: function(specs, array, memo)
+ {
+ if (!array)
+ array = [];
+
+ if (!memo)
+ memo = {specs: [], arrays: []};
+
+ for (var i = 0; i < specs.length; i++)
+ array.push(this.deserialize(specs[i], memo));
+
+ return array;
+ },
+ deserialize: function(spec, memo)
+ {
+ switch (spec.type)
+ {
+ case "value":
+ return spec.value;
+ case "object":
+ return this.getObject(spec.objectId);
+ case "array":
+ if (!memo)
+ memo = {specs: [], arrays: []};
+
+ var idx = memo.specs.indexOf(spec);
+ if (idx != -1)
+ return memo.arrays[idx];
+
+ var array = [];
+ memo.specs.push(spec);
+ memo.arrays.push(array);
+
+ return this.deserializeSequence(spec.items, array, memo);
+ }
+ },
+ getProperty: function(objectId, property)
+ {
+ return this.deserializeResult(
+ this.send(
+ {
+ type: "getProperty",
+ objectId: objectId,
+ property: property
+ })
+ );
+ },
+ createProperty: function(objectId, property, enumerable)
+ {
+ return {
+ get: function()
+ {
+ return this.getProperty(objectId, property);
+ }.bind(this),
+ set: function(value)
+ {
+ this.checkResult(
+ this.send(
+ {
+ type: "setProperty",
+ objectId: objectId,
+ property: property,
+ value: this.serialize(value)
+ })
+ );
+ }.bind(this),
+ enumerable: enumerable,
+ configurable: true
+ };
+ },
+ createFunction: function(objectId)
+ {
+ var proxy = this;
+ return function()
+ {
+ return proxy.deserializeResult(
+ proxy.send(
+ {
+ type: "callFunction",
+ functionId: objectId,
+ contextId: proxy.objects.indexOf(this),
+ args: Array.prototype.map.call(
+ arguments,
+ proxy.serialize.bind(proxy)
+ )
+ })
+ );
+ };
+ },
+ getObject: function(objectId) {
+ var objectInfo = this.send({
+ type: "inspectObject",
+ objectId: objectId
+ });
+
+ var obj = this.objects[objectId];
+ if (obj)
+ Object.getOwnPropertyNames(obj).forEach(function(prop) { delete obj[prop]; });
+ else
+ {
+ if (objectInfo.isFunction)
+ obj = this.createFunction(objectId);
+ else
+ obj = {};
+
+ this.objects[objectId] = obj;
+ }
+
+ var ignored = [];
+ if ("prototypeOf" in objectInfo)
+ {
+ var prototype = window[objectInfo.prototypeOf].prototype;
+
+ ignored = Object.getOwnPropertyNames(prototype);
+ ignored.splice(ignored.indexOf("constructor"), 1);
+
+ obj.__proto__ = prototype;
+ }
+ else
+ {
+ if (objectInfo.isFunction)
+ ignored = Object.getOwnPropertyNames(function() {});
+ else
+ ignored = [];
+
+ if ("prototypeId" in objectInfo)
+ obj.__proto__ = this.getObject(objectInfo.prototypeId);
+ else
+ obj.__proto__ = null;
+ }
+
+ for (var property in objectInfo.properties)
+ if (ignored.indexOf(property) == -1)
+ Object.defineProperty(obj, property, this.createProperty(
+ objectId, property,
+ objectInfo.properties[property].enumerable
+ ));
+
+ if (objectInfo.isFunction)
+ obj.prototype = this.getProperty(objectId, "prototype");
+
+ return obj;
+ }
+ };
+
+
+ /* Web request blocking */
+
+ document.addEventListener("beforeload", function(event)
+ {
+ var type;
+
+ switch(event.target.nodeName)
+ {
+ 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";
+ }
+
+ 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);
+})();
« no previous file with comments | « safari/common.js ('k') | stats.js » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld