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

Delta Between Two Patch Sets: safari/content.js

Issue 16067002: Added Safari Support (Closed)
Left Patch Set: Created Oct. 21, 2013, 8:11 p.m.
Right Patch Set: Bugfixes Created Nov. 15, 2013, 8:58 a.m.
Left:
Right:
Use n/p to move between diff chunks; N/P to move between comments.
Jump to:
Left: Side by side diff | Download
Right: Side by side diff | Download
« no previous file with change/comment | « safari/common.js ('k') | stats.js » ('j') | no next file with change/comment »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
LEFTRIGHT
1 (function() { 1 /*
2 * This file is part of Adblock Plus <http://adblockplus.org/>,
3 * Copyright (C) 2006-2013 Eyeo GmbH
4 *
5 * Adblock Plus is free software: you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License version 3 as
7 * published by the Free Software Foundation.
8 *
9 * Adblock Plus is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with Adblock Plus. If not, see <http://www.gnu.org/licenses/>.
16 */
17
18 (function()
19 {
2 /* Background page proxy */ 20 /* Background page proxy */
3
4 var proxy = { 21 var proxy = {
5 objects: [], 22 objects: [],
6 callbacks: [], 23 callbacks: [],
7 24
8 send: function(message) { 25 send: function(message)
26 {
9 var evt = document.createEvent("Event"); 27 var evt = document.createEvent("Event");
10 evt.initEvent("beforeload"); 28 evt.initEvent("beforeload");
11 return safari.self.tab.canLoad(evt, {type: "proxy", payload: message}); 29 return safari.self.tab.canLoad(evt, {type: "proxy", payload: message});
12 }, 30 },
13 checkResult: function(result) { 31 checkResult: function(result)
32 {
14 if (!result.succeed) 33 if (!result.succeed)
15 throw result.error; 34 throw result.error;
16 }, 35 },
17 deserializeResult: function(result) { 36 deserializeResult: function(result)
37 {
18 this.checkResult(result); 38 this.checkResult(result);
19 return this.deserialize(result.result); 39 return this.deserialize(result.result);
20 }, 40 },
21 serialize: function(obj, memo) { 41 serialize: function(obj, memo)
42 {
22 var objectId = this.objects.indexOf(obj); 43 var objectId = this.objects.indexOf(obj);
23 if (objectId != -1) 44 if (objectId != -1)
24 return {type: "hosted", objectId: objectId}; 45 return {type: "hosted", objectId: objectId};
25 46
26 if (typeof obj == "function") { 47 if (typeof obj == "function")
48 {
27 var callbackId = this.callbacks.indexOf(obj); 49 var callbackId = this.callbacks.indexOf(obj);
28 50
29 if (callbackId == -1) { 51 if (callbackId == -1)
52 {
30 callbackId = this.callbacks.push(obj) - 1; 53 callbackId = this.callbacks.push(obj) - 1;
31 54
32 safari.self.addEventListener("message", function(event) { 55 safari.self.addEventListener("message", function(event)
56 {
33 if (event.name == "proxyCallback") 57 if (event.name == "proxyCallback")
34 if (event.message.callbackId == callbackId) 58 if (event.message.callbackId == callbackId)
35 obj.apply( 59 obj.apply(
36 this.getObject(event.message.contextId), 60 this.getObject(event.message.contextId),
37 this.deserializeSequence(event.message.args) 61 this.deserializeSequence(event.message.args)
38 ); 62 );
39 }.bind(this)); 63 }.bind(this));
40 } 64 }
41 65
42 return {type: "callback", callbackId: callbackId}; 66 return {type: "callback", callbackId: callbackId};
43 } 67 }
44 68
45 if (typeof obj == "object") 69 if (typeof obj == "object" &&
46 if (obj != null) 70 obj != null &&
47 if (obj.constructor != Date) 71 obj.constructor != Date &&
48 if (obj.constructor != RegExp) { 72 obj.constructor != RegExp)
73 {
49 if (!memo) 74 if (!memo)
50 memo = {specs: [], objects: []}; 75 memo = {specs: [], objects: []};
51 76
52 var idx = memo.objects.indexOf(obj); 77 var idx = memo.objects.indexOf(obj);
53 if (idx != -1) 78 if (idx != -1)
54 return memo.specs[idx]; 79 return memo.specs[idx];
55 80
56 var spec = {}; 81 var spec = {};
57 memo.specs.push(spec); 82 memo.specs.push(spec);
58 memo.objects.push(obj); 83 memo.objects.push(obj);
59 84
60 if (obj.constructor == Array) { 85 if (obj.constructor == Array)
86 {
61 spec.type = "array"; 87 spec.type = "array";
62 spec.items = []; 88 spec.items = [];
63 89
64 for (var i = 0; i < obj.length; i++) 90 for (var i = 0; i < obj.length; i++)
65 spec.items.push(this.serialize(obj[i], memo)); 91 spec.items.push(this.serialize(obj[i], memo));
66 } else { 92 }
93 else
94 {
67 spec.type = "object"; 95 spec.type = "object";
68 spec.properties = {}; 96 spec.properties = {};
69 97
70 for (var k in obj) 98 for (var k in obj)
71 spec.properties[k] = this.serialize(obj[k], memo); 99 spec.properties[k] = this.serialize(obj[k], memo);
72 } 100 }
73 101
74 return spec; 102 return spec;
75 } 103 }
76 104
77 return {type: "value", value: obj}; 105 return {type: "value", value: obj};
78 }, 106 },
79 deserializeSequence: function(specs, array, memo) { 107 deserializeSequence: function(specs, array, memo)
108 {
80 if (!array) 109 if (!array)
81 array = []; 110 array = [];
82 111
83 if (!memo) 112 if (!memo)
84 memo = {specs: [], arrays: []}; 113 memo = {specs: [], arrays: []};
85 114
86 for (var i = 0; i < specs.length; i++) 115 for (var i = 0; i < specs.length; i++)
87 array.push(this.deserialize(specs[i], memo)); 116 array.push(this.deserialize(specs[i], memo));
88 117
89 return array; 118 return array;
90 }, 119 },
91 deserialize: function(spec, memo) { 120 deserialize: function(spec, memo)
92 switch (spec.type) { 121 {
122 switch (spec.type)
123 {
93 case "value": 124 case "value":
94 return spec.value; 125 return spec.value;
95 case "object": 126 case "object":
96 case "function": 127 return this.getObject(spec.objectId);
97 return this.getObject(spec.objectId, spec.type);
98 case "array": 128 case "array":
99 if (!memo) 129 if (!memo)
100 memo = {specs: [], arrays: []}; 130 memo = {specs: [], arrays: []};
101 131
102 var idx = memo.specs.indexOf(spec); 132 var idx = memo.specs.indexOf(spec);
103 if (idx != -1) 133 if (idx != -1)
104 return memo.arrays[idx]; 134 return memo.arrays[idx];
105 135
106 var array = []; 136 var array = [];
107 memo.specs.push(spec); 137 memo.specs.push(spec);
108 memo.arrays.push(array); 138 memo.arrays.push(array);
109 139
110 return this.deserializeSequence(spec.items, array, memo); 140 return this.deserializeSequence(spec.items, array, memo);
111 } 141 }
112 }, 142 },
113 getProperty: function(objectId, property) { 143 getProperty: function(objectId, property)
144 {
114 return this.deserializeResult( 145 return this.deserializeResult(
115 this.send({ 146 this.send(
147 {
116 type: "getProperty", 148 type: "getProperty",
117 objectId: objectId, 149 objectId: objectId,
118 property: property 150 property: property
119 }) 151 })
120 ); 152 );
121 }, 153 },
122 createProperty: function(objectId, property, enumerable) { 154 createProperty: function(objectId, property, enumerable)
155 {
123 return { 156 return {
124 get: function() { 157 get: function()
158 {
125 return this.getProperty(objectId, property); 159 return this.getProperty(objectId, property);
126 }.bind(this), 160 }.bind(this),
127 set: function(value) { 161 set: function(value)
162 {
128 this.checkResult( 163 this.checkResult(
129 this.send({ 164 this.send(
165 {
130 type: "setProperty", 166 type: "setProperty",
131 objectId: objectId, 167 objectId: objectId,
132 property: property, 168 property: property,
133 value: this.serialize(value) 169 value: this.serialize(value)
134 }) 170 })
135 ) 171 );
136 }.bind(this), 172 }.bind(this),
137 enumerable: enumerable 173 enumerable: enumerable,
174 configurable: true
138 }; 175 };
139 }, 176 },
140 createObject: function(objectId) { 177 createFunction: function(objectId)
141 var objectInfo = this.send({ 178 {
142 type: "inspectObject",
143 objectId: objectId
144 });
145
146 var prototype;
147 if (objectInfo.prototypeId != null)
148 prototype = this.getObject(objectInfo.prototypeId);
149 else
150 prototype = Object.prototype;
151
152 var properties = {};
153 for (var property in objectInfo.properties)
154 properties[property] = this.createProperty(
155 objectId, property,
156 objectInfo.properties[property].enumerable
157 );
158
159 return Object.create(prototype, properties);
160 },
161 createFunction: function(objectId) {
162 var objectInfo = this.send({
163 type: "inspectObject",
164 objectId: objectId
165 });
166
167 var proxy = this; 179 var proxy = this;
168 var func = function() { 180 return function()
181 {
169 return proxy.deserializeResult( 182 return proxy.deserializeResult(
170 proxy.send({ 183 proxy.send(
184 {
171 type: "callFunction", 185 type: "callFunction",
172 functionId: objectId, 186 functionId: objectId,
173 contextId: proxy.objects.indexOf(this), 187 contextId: proxy.objects.indexOf(this),
174 args: Array.prototype.map.call( 188 args: Array.prototype.map.call(
175 arguments, 189 arguments,
176 proxy.serialize.bind(proxy) 190 proxy.serialize.bind(proxy)
177 ) 191 )
178 }) 192 })
179 ); 193 );
180 }; 194 };
181 195 },
182 var builtin = Object.getOwnPropertyNames(func); 196 getObject: function(objectId) {
197 var objectInfo = this.send({
198 type: "inspectObject",
199 objectId: objectId
200 });
201
202 var obj = this.objects[objectId];
203 if (obj)
204 Object.getOwnPropertyNames(obj).forEach(function(prop) { delete obj[prop ]; });
205 else
206 {
207 if (objectInfo.isFunction)
208 obj = this.createFunction(objectId);
209 else
210 obj = {};
211
212 this.objects[objectId] = obj;
213 }
214
215 var ignored = [];
216 if ("prototypeOf" in objectInfo)
217 {
218 var prototype = window[objectInfo.prototypeOf].prototype;
219
220 ignored = Object.getOwnPropertyNames(prototype);
221 ignored.splice(ignored.indexOf("constructor"), 1);
222
223 obj.__proto__ = prototype;
224 }
225 else
226 {
227 if (objectInfo.isFunction)
228 ignored = Object.getOwnPropertyNames(function() {});
229 else
230 ignored = [];
231
232 if ("prototypeId" in objectInfo)
233 obj.__proto__ = this.getObject(objectInfo.prototypeId);
234 else
235 obj.__proto__ = null;
236 }
237
183 for (var property in objectInfo.properties) 238 for (var property in objectInfo.properties)
184 if (builtin.indexOf(property) == -1) 239 if (ignored.indexOf(property) == -1)
185 Object.defineProperty(func, property, this.createProperty( 240 Object.defineProperty(obj, property, this.createProperty(
186 objectId, property, 241 objectId, property,
187 objectInfo.properties[property].enumerable 242 objectInfo.properties[property].enumerable
188 )); 243 ));
189 244
190 func.prototype = this.getProperty(objectId, "prototype"); 245 if (objectInfo.isFunction)
191 return func; 246 obj.prototype = this.getProperty(objectId, "prototype");
192 },
193 getObject: function(objectId, type) {
194 var obj = this.objects[objectId];
195
196 if (!obj) {
197 if (type == "function")
198 obj = this.createFunction(objectId);
199 else
200 obj = this.createObject(objectId);
201
202 this.objects[objectId] = obj;
203 }
204 247
205 return obj; 248 return obj;
206 } 249 }
207 }; 250 };
208 251
209 252
210 /* Web request blocking */ 253 /* Web request blocking */
211 254
212 document.addEventListener("beforeload", function(event) { 255 document.addEventListener("beforeload", function(event)
256 {
213 var type; 257 var type;
214 258
215 switch(event.target.nodeName) { 259 switch(event.target.nodeName)
260 {
216 case "FRAME": 261 case "FRAME":
217 case "IFRAME": 262 case "IFRAME":
218 type = "frame"; 263 type = "frame";
219 break; 264 break;
220 case "IMG": 265 case "IMG":
221 type = "image"; 266 type = "image";
222 break; 267 break;
223 case "OBJECT": 268 case "OBJECT":
224 case "EMBED": 269 case "EMBED":
225 type = "object"; 270 type = "object";
226 break; 271 break;
227 case "SCRIPT": 272 case "SCRIPT":
228 type = "script"; 273 type = "script";
229 break; 274 break;
230 case "LINK": 275 case "LINK":
231 if (/(^|\s)stylesheet($|\s)/i.test(event.target.rel)) { 276 if (/(^|\s)stylesheet($|\s)/i.test(event.target.rel))
277 {
232 type = "stylesheet"; 278 type = "stylesheet";
233 break; 279 break;
234 } 280 }
235 default: 281 default:
236 type = "other"; 282 type = "other";
237 } 283 }
238 284
239 if (!safari.self.tab.canLoad(event, {type: "webRequest", payload: {url: even t.url, type: type}})) 285 if (!safari.self.tab.canLoad(event, {type: "webRequest", payload: {url: even t.url, type: type}}))
240 event.preventDefault(); 286 event.preventDefault();
241 }, true); 287 }, true);
242 288
289
243 /* API */ 290 /* API */
244 291
245 ext.backgroundPage = { 292 ext.backgroundPage = {
246 _eventTarget: safari.self, 293 _eventTarget: safari.self,
247 _messageDispatcher: safari.self.tab, 294 _messageDispatcher: safari.self.tab,
248 295
249 sendMessage: sendMessage, 296 sendMessage: sendMessage,
250 getWindow: function() { return proxy.getObject(0); } 297 getWindow: function() { return proxy.getObject(0); }
251 }; 298 };
252 299
253 ext.onMessage = new MessageEventTarget(safari.self); 300 ext.onMessage = new MessageEventTarget(safari.self);
254 })(); 301 })();
LEFTRIGHT

Powered by Google App Engine
This is Rietveld