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") |
+ if (obj != null) |
+ if (obj.constructor != Date) |
+ if (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); |
+})(); |