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

Side by Side 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.
Left:
Right:
Use n/p to move between diff chunks; N/P to move between comments.
Jump to:
View unified diff | Download patch
« no previous file with comments | « safari/ext/common.js ('k') | safari/ext/popup.js » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 /* 1 /*
2 * This file is part of Adblock Plus <http://adblockplus.org/>, 2 * This file is part of Adblock Plus <http://adblockplus.org/>,
3 * Copyright (C) 2006-2013 Eyeo GmbH 3 * Copyright (C) 2006-2014 Eyeo GmbH
4 * 4 *
5 * Adblock Plus is free software: you can redistribute it and/or modify 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 6 * it under the terms of the GNU General Public License version 3 as
7 * published by the Free Software Foundation. 7 * published by the Free Software Foundation.
8 * 8 *
9 * Adblock Plus is distributed in the hope that it will be useful, 9 * Adblock Plus is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of 10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details. 12 * GNU General Public License for more details.
13 * 13 *
14 * You should have received a copy of the GNU General Public License 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/>. 15 * along with Adblock Plus. If not, see <http://www.gnu.org/licenses/>.
16 */ 16 */
17 17
18 (function() 18 (function()
19 { 19 {
20 safari.self.tab.dispatchMessage("loading", document.location.href); 20 // the safari object is missing in frames created from javascript: URLs.
21 // So we have to fallback to the safari object from the parent frame.
22 if (!("safari" in window))
23 window.safari = window.parent.safari;
21 24
22 25
23 /* Background page proxy */ 26 /* Intialization */
24 var proxy = { 27
28 var beforeLoadEvent = document.createEvent("Event");
29 beforeLoadEvent.initEvent("beforeload");
30
31 var isTopLevel = window == window.top;
32 var isPrerendered = document.visibilityState == "prerender";
33
34 var documentInfo = safari.self.tab.canLoad(
35 beforeLoadEvent,
36 {
37 category: "loading",
38 url: document.location.href,
39 referrer: document.referrer,
40 isTopLevel: isTopLevel,
41 isPrerendered: isPrerendered
42 }
43 );
44
45 if (isTopLevel && isPrerendered)
46 {
47 var onVisibilitychange = function()
48 {
49 safari.self.tab.dispatchMessage("replaced", {pageId: documentInfo.pageId}) ;
50 document.removeEventListener("visibilitychange", onVisibilitychange);
51 };
52 document.addEventListener("visibilitychange", onVisibilitychange);
53 }
54
55
56 /* Web requests */
57
58 document.addEventListener("beforeload", function(event)
59 {
60 var url = relativeToAbsoluteUrl(event.url);
61
62 // we don't block non-HTTP requests anyway, so we can bail out
63 // without asking the background page. This is even necessary
64 // because passing large data (like a photo encoded as data: URL)
65 // to the background page, freezes Safari.
66 if (!/^https?:/.test(url))
67 return;
68
69 var type;
70 switch(event.target.localName)
71 {
72 case "frame":
73 case "iframe":
74 type = "sub_frame";
75 break;
76 case "img":
77 type = "image";
78 break;
79 case "object":
80 case "embed":
81 type = "object";
82 break;
83 case "script":
84 type = "script";
85 break;
86 case "link":
87 if (/\bstylesheet\b/i.test(event.target.rel))
88 {
89 type = "stylesheet";
90 break;
91 }
92 default:
93 type = "other";
94 }
95
96 if (!safari.self.tab.canLoad(
97 event, {
98 category: "webRequest",
99 url: url,
100 type: type,
101 pageId: documentInfo.pageId,
102 frameId: documentInfo.frameId
103 }
104 ))
105 {
106 event.preventDefault();
107
108 // Safari doesn't dispatch an "error" event when preventing an element
109 // from loading by cancelling the "beforeload" event. So we have to
110 // dispatch it manually. Otherwise element collapsing wouldn't work.
111 if (type != "sub_frame")
112 {
113 setTimeout(function()
114 {
115 var evt = document.createEvent("Event");
116 evt.initEvent("error");
117 event.target.dispatchEvent(evt);
118 }, 0);
119 }
120 }
121 }, true);
122
123
124 /* Context menus */
125
126 document.addEventListener("contextmenu", function(event)
127 {
128 var element = event.srcElement;
129 safari.self.tab.setContextMenuEventUserInfo(event, {
130 pageId: documentInfo.pageId,
131 srcUrl: ("src" in element) ? element.src : null,
132 tagName: element.localName
133 });
134 });
135
136
137 /* Background page */
138
139 var backgroundPageProxy = {
25 objects: [], 140 objects: [],
26 callbacks: [], 141 callbacks: [],
27 142
28 send: function(message) 143 send: function(message)
29 { 144 {
30 var evt = document.createEvent("Event"); 145 message.category = "proxy";
31 evt.initEvent("beforeload"); 146 message.pageId = documentInfo.pageId;
32 return safari.self.tab.canLoad(evt, {type: "proxy", payload: message}); 147
148 return safari.self.tab.canLoad(beforeLoadEvent, message);
33 }, 149 },
34 checkResult: function(result) 150 checkResult: function(result)
35 { 151 {
36 if (!result.succeed) 152 if (!result.succeed)
37 throw result.error; 153 throw result.error;
38 }, 154 },
39 deserializeResult: function(result) 155 deserializeResult: function(result)
40 { 156 {
41 this.checkResult(result); 157 this.checkResult(result);
42 return this.deserialize(result.result); 158 return this.deserialize(result.result);
43 }, 159 },
44 serialize: function(obj, memo) 160 serialize: function(obj, memo)
45 { 161 {
46 var objectId = this.objects.indexOf(obj); 162 if (typeof obj == "object" && obj != null || typeof obj == "function")
47 if (objectId != -1) 163 {
48 return {type: "hosted", objectId: objectId}; 164 if ("__proxyObjectId" in obj)
165 return {type: "hosted", objectId: obj.__proxyObjectId};
49 166
50 if (typeof obj == "function") 167 if (typeof obj == "function")
51 { 168 {
52 var callbackId = this.callbacks.indexOf(obj); 169 var callbackId;
170 if ("__proxyCallbackId" in obj)
171 callbackId = obj.__proxyCallbackId;
172 else
173 {
174 callbackId = this.callbacks.push(obj) - 1;
175 Object.defineProperty(obj, "__proxyCallbackId", {value: callbackId}) ;
176 }
53 177
54 if (callbackId == -1) 178 return {type: "callback", callbackId: callbackId, frameId: documentInf o.frameId};
55 {
56 callbackId = this.callbacks.push(obj) - 1;
57
58 safari.self.addEventListener("message", function(event)
59 {
60 if (event.name == "proxyCallback")
61 if (event.message.callbackId == callbackId)
62 obj.apply(
63 this.getObject(event.message.contextId),
64 this.deserializeSequence(event.message.args)
65 );
66 }.bind(this));
67 } 179 }
68 180
69 return {type: "callback", callbackId: callbackId}; 181 if (obj.constructor != Date && obj.constructor != RegExp)
70 } 182 {
183 if (!memo)
184 memo = {specs: [], objects: []};
71 185
72 if (typeof obj == "object" && 186 var idx = memo.objects.indexOf(obj);
73 obj != null && 187 if (idx != -1)
74 obj.constructor != Date && 188 return memo.specs[idx];
75 obj.constructor != RegExp)
76 {
77 if (!memo)
78 memo = {specs: [], objects: []};
79 189
80 var idx = memo.objects.indexOf(obj); 190 var spec = {};
81 if (idx != -1) 191 memo.specs.push(spec);
82 return memo.specs[idx]; 192 memo.objects.push(obj);
83 193
84 var spec = {}; 194 if (obj.constructor == Array)
85 memo.specs.push(spec); 195 {
86 memo.objects.push(obj); 196 spec.type = "array";
197 spec.items = [];
87 198
88 if (obj.constructor == Array) 199 for (var i = 0; i < obj.length; i++)
89 { 200 spec.items.push(this.serialize(obj[i], memo));
90 spec.type = "array"; 201 }
91 spec.items = []; 202 else
203 {
204 spec.type = "object";
205 spec.properties = {};
92 206
93 for (var i = 0; i < obj.length; i++) 207 for (var k in obj)
94 spec.items.push(this.serialize(obj[i], memo)); 208 spec.properties[k] = this.serialize(obj[k], memo);
209 }
210
211 return spec;
95 } 212 }
96 else
97 {
98 spec.type = "object";
99 spec.properties = {};
100
101 for (var k in obj)
102 spec.properties[k] = this.serialize(obj[k], memo);
103 }
104
105 return spec;
106 } 213 }
107 214
108 return {type: "value", value: obj}; 215 return {type: "value", value: obj};
109 }, 216 },
110 deserializeSequence: function(specs, array, memo) 217 deserializeSequence: function(specs, array, memo)
111 { 218 {
112 if (!array) 219 if (!array)
113 array = []; 220 array = [];
114 221
115 if (!memo) 222 if (!memo)
(...skipping 20 matching lines...) Expand all
136 if (idx != -1) 243 if (idx != -1)
137 return memo.arrays[idx]; 244 return memo.arrays[idx];
138 245
139 var array = []; 246 var array = [];
140 memo.specs.push(spec); 247 memo.specs.push(spec);
141 memo.arrays.push(array); 248 memo.arrays.push(array);
142 249
143 return this.deserializeSequence(spec.items, array, memo); 250 return this.deserializeSequence(spec.items, array, memo);
144 } 251 }
145 }, 252 },
146 getObjectId: function(obj)
147 {
148 return this.objects.indexOf(obj);
149 },
150 getProperty: function(objectId, property) 253 getProperty: function(objectId, property)
151 { 254 {
152 return this.deserializeResult( 255 return this.deserializeResult(
153 this.send( 256 this.send(
154 { 257 {
155 type: "getProperty", 258 type: "getProperty",
156 objectId: objectId, 259 objectId: objectId,
157 property: property 260 property: property
158 }) 261 })
159 ); 262 );
160 }, 263 },
161 createProperty: function(property, enumerable) 264 createProperty: function(property, enumerable)
162 { 265 {
163 var proxy = this; 266 var proxy = this;
164 return { 267 return {
165 get: function() 268 get: function()
166 { 269 {
167 return proxy.getProperty(proxy.getObjectId(this), property); 270 return proxy.getProperty(this.__proxyObjectId, property);
168 }, 271 },
169 set: function(value) 272 set: function(value)
170 { 273 {
171 proxy.checkResult( 274 proxy.checkResult(
172 proxy.send( 275 proxy.send(
173 { 276 {
174 type: "setProperty", 277 type: "setProperty",
175 objectId: proxy.getObjectId(this), 278 objectId: this.__proxyObjectId,
176 property: property, 279 property: property,
177 value: proxy.serialize(value) 280 value: proxy.serialize(value)
178 }) 281 })
179 ); 282 );
180 }, 283 },
181 enumerable: enumerable, 284 enumerable: enumerable,
182 configurable: true 285 configurable: true
183 }; 286 };
184 }, 287 },
185 createFunction: function(objectId) 288 createFunction: function(objectId)
186 { 289 {
187 var proxy = this; 290 var proxy = this;
188 return function() 291 return function()
189 { 292 {
190 return proxy.deserializeResult( 293 return proxy.deserializeResult(
191 proxy.send( 294 proxy.send(
192 { 295 {
193 type: "callFunction", 296 type: "callFunction",
194 functionId: objectId, 297 functionId: objectId,
195 contextId: proxy.getObjectId(this), 298 contextId: this.__proxyObjectId,
196 args: Array.prototype.map.call( 299 args: Array.prototype.map.call(
197 arguments, 300 arguments,
198 proxy.serialize.bind(proxy) 301 proxy.serialize.bind(proxy)
199 ) 302 )
200 }) 303 })
201 ); 304 );
202 }; 305 };
203 }, 306 },
204 getObject: function(objectId) { 307 handleCallback: function(message)
308 {
309 this.callbacks[message.callbackId].apply(
310 this.getObject(message.contextId),
311 this.deserializeSequence(message.args)
312 );
313 },
314 getObject: function(objectId)
315 {
205 var objectInfo = this.send({ 316 var objectInfo = this.send({
206 type: "inspectObject", 317 type: "inspectObject",
207 objectId: objectId 318 objectId: objectId
208 }); 319 });
209 320
210 var obj = this.objects[objectId]; 321 var obj = this.objects[objectId];
211 if (obj) 322 if (obj)
212 Object.getOwnPropertyNames(obj).forEach(function(prop) { delete obj[prop ]; }); 323 Object.getOwnPropertyNames(obj).forEach(function(prop) { delete obj[prop ]; });
213 else 324 else
214 { 325 {
215 if (objectInfo.isFunction) 326 if (objectInfo.isFunction)
216 obj = this.createFunction(objectId); 327 obj = this.createFunction(objectId);
217 else 328 else
218 obj = {}; 329 obj = {};
219 330
220 this.objects[objectId] = obj; 331 this.objects[objectId] = obj;
332 Object.defineProperty(obj, "__proxyObjectId", {value: objectId});
221 } 333 }
222 334
223 var ignored = []; 335 var excluded = [];
336 var included = [];
224 if ("prototypeOf" in objectInfo) 337 if ("prototypeOf" in objectInfo)
225 { 338 {
226 var prototype = window[objectInfo.prototypeOf].prototype; 339 var prototype = window[objectInfo.prototypeOf].prototype;
227 340
228 ignored = Object.getOwnPropertyNames(prototype); 341 excluded = Object.getOwnPropertyNames(prototype);
229 ignored.splice(ignored.indexOf("constructor"), 1); 342 included = ["constructor"];
230 343
231 obj.__proto__ = prototype; 344 obj.__proto__ = prototype;
232 } 345 }
233 else 346 else
234 { 347 {
235 if (objectInfo.isFunction) 348 if (objectInfo.isFunction)
236 ignored = Object.getOwnPropertyNames(function() {}); 349 {
237 else 350 excluded = Object.getOwnPropertyNames(function() {});
238 ignored = []; 351 included = ["prototype"];
352 }
239 353
240 if ("prototypeId" in objectInfo) 354 if ("prototypeId" in objectInfo)
241 obj.__proto__ = this.getObject(objectInfo.prototypeId); 355 obj.__proto__ = this.getObject(objectInfo.prototypeId);
242 else 356 else
243 obj.__proto__ = null; 357 obj.__proto__ = null;
244 } 358 }
245 359
246 for (var property in objectInfo.properties) 360 for (var property in objectInfo.properties)
247 if (ignored.indexOf(property) == -1) 361 {
248 Object.defineProperty(obj, property, this.createProperty( 362 if (excluded.indexOf(property) == -1 || included.indexOf(property) != -1 )
249 property, objectInfo.properties[property].enumerable 363 {
250 )); 364 var desc = Object.getOwnPropertyDescriptor(obj, property);
251 365
252 if (objectInfo.isFunction) 366 if (!desc || desc.configurable)
253 obj.prototype = this.getProperty(objectId, "prototype"); 367 {
368 Object.defineProperty(obj, property, this.createProperty(
369 property, objectInfo.properties[property].enumerable
370 ));
371 }
372 else if (desc.writable)
373 obj[property] = this.getProperty(objectId, property);
374 }
375 }
254 376
255 return obj; 377 return obj;
256 } 378 }
257 }; 379 };
258 380
259 381 ext.backgroundPage = {
260 /* Web request blocking */ 382 sendMessage: function(message, responseCallback)
261
262 document.addEventListener("beforeload", function(event)
263 {
264 var type;
265
266 switch(event.target.nodeName)
267 { 383 {
268 case "FRAME": 384 messageProxy.sendMessage(message, responseCallback, documentInfo);
269 case "IFRAME": 385 },
270 type = "frame"; 386 getWindow: function()
271 break; 387 {
272 case "IMG": 388 return backgroundPageProxy.getObject(0);
273 type = "image";
274 break;
275 case "OBJECT":
276 case "EMBED":
277 type = "object";
278 break;
279 case "SCRIPT":
280 type = "script";
281 break;
282 case "LINK":
283 if (/(^|\s)stylesheet($|\s)/i.test(event.target.rel))
284 {
285 type = "stylesheet";
286 break;
287 }
288 default:
289 type = "other";
290 } 389 }
291 390 };
292 if (!safari.self.tab.canLoad(event, {type: "webRequest", payload: {url: even t.url, type: type}}))
293 event.preventDefault();
294 }, true);
295 391
296 392
297 /* API */ 393 /* Message processing */
298 394
299 ext.backgroundPage = { 395 var messageProxy = new ext._MessageProxy(safari.self.tab);
300 _eventTarget: safari.self,
301 _messageDispatcher: safari.self.tab,
302 396
303 sendMessage: sendMessage, 397 safari.self.addEventListener("message", function(event)
304 getWindow: function() { return proxy.getObject(0); } 398 {
305 }; 399 if (event.message.pageId == documentInfo.pageId)
400 {
401 if (event.name == "request")
402 {
403 messageProxy.handleRequest(event.message, {});
404 return;
405 }
306 406
307 ext.onMessage = new MessageEventTarget(safari.self); 407 if (event.message.frameId == documentInfo.frameId)
408 {
409 switch (event.name)
410 {
411 case "response":
412 messageProxy.handleResponse(event.message);
413 break;
414 case "proxyCallback":
415 backgroundPageProxy.handleCallback(event.message);
416 break;
417 }
418 }
419 }
420 });
308 })(); 421 })();
OLDNEW
« 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