| OLD | NEW | 
|---|
| 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-2014 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   // the safari object is missing in frames created from javascript: URLs. | 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. | 21   // So we have to fallback to the safari object from the parent frame. | 
| 22   if (!("safari" in window)) | 22   if (!("safari" in window)) | 
| 23     window.safari = window.parent.safari; | 23     window.safari = window.parent.safari; | 
| 24 | 24 | 
| 25   if (window == window.top) | 25 | 
| 26     safari.self.tab.dispatchMessage("loading"); | 26   /* Intialization */ | 
|  | 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   } | 
| 27 | 54 | 
| 28 | 55 | 
| 29   /* Events */ | 56   /* Web requests */ | 
| 30 | 57 | 
| 31   var ContentMessageEventTarget = function() | 58   document.addEventListener("beforeload", function(event) | 
| 32   { | 59   { | 
| 33     MessageEventTarget.call(this, safari.self); | 60     // we don't block non-HTTP requests anyway, so we can bail out | 
| 34   }; | 61     // without asking the background page. This is even necessary | 
| 35   ContentMessageEventTarget.prototype = { | 62     // because passing large data (like a photo encoded as data: URL) | 
| 36     __proto__: MessageEventTarget.prototype, | 63     // to the background page, freezes Safari. | 
| 37     _getResponseDispatcher: function(event) | 64     if (!/^https?:/.test(event.url)) | 
|  | 65       return; | 
|  | 66 | 
|  | 67     var type; | 
|  | 68     switch(event.target.localName) | 
| 38     { | 69     { | 
| 39       return event.target.tab; | 70       case "frame": | 
| 40     }, | 71       case "iframe": | 
| 41     _getSenderDetails: function(event) | 72         type = "sub_frame"; | 
|  | 73         break; | 
|  | 74       case "img": | 
|  | 75         type = "image"; | 
|  | 76         break; | 
|  | 77       case "object": | 
|  | 78       case "embed": | 
|  | 79         type = "object"; | 
|  | 80         break; | 
|  | 81       case "script": | 
|  | 82         type = "script"; | 
|  | 83         break; | 
|  | 84       case "link": | 
|  | 85         if (/\bstylesheet\b/i.test(event.target.rel)) | 
|  | 86         { | 
|  | 87           type = "stylesheet"; | 
|  | 88           break; | 
|  | 89         } | 
|  | 90       default: | 
|  | 91         type = "other"; | 
|  | 92     } | 
|  | 93 | 
|  | 94     if (!safari.self.tab.canLoad( | 
|  | 95       event, { | 
|  | 96         category: "webRequest", | 
|  | 97         url: event.url, | 
|  | 98         type: type, | 
|  | 99         pageId: documentInfo.pageId, | 
|  | 100         frameId: documentInfo.frameId | 
|  | 101       } | 
|  | 102     )) | 
| 42     { | 103     { | 
| 43       return {}; | 104       event.preventDefault(); | 
|  | 105 | 
|  | 106       // Safari doesn't dispatch an "error" event when preventing an element | 
|  | 107       // from loading by cancelling the "beforeload" event. So we have to | 
|  | 108       // dispatch it manually. Otherwise element collapsing wouldn't work. | 
|  | 109       if (type != "sub_frame") | 
|  | 110       { | 
|  | 111         var evt = document.createEvent("Event"); | 
|  | 112         evt.initEvent("error"); | 
|  | 113         event.target.dispatchEvent(evt); | 
|  | 114       } | 
| 44     } | 115     } | 
| 45   }; | 116   }, true); | 
| 46 | 117 | 
| 47 | 118 | 
| 48   /* Background page proxy */ | 119   /* Context menus */ | 
| 49   var proxy = { | 120 | 
|  | 121   document.addEventListener("contextmenu", function(event) | 
|  | 122   { | 
|  | 123     var element = event.srcElement; | 
|  | 124     safari.self.tab.setContextMenuEventUserInfo(event, { | 
|  | 125       pageId: documentInfo.pageId, | 
|  | 126       srcUrl: ("src" in element) ? element.src : null, | 
|  | 127       tagName: element.localName | 
|  | 128     }); | 
|  | 129   }); | 
|  | 130 | 
|  | 131 | 
|  | 132   /* Background page */ | 
|  | 133 | 
|  | 134   var backgroundPageProxy = { | 
| 50     objects: [], | 135     objects: [], | 
| 51     callbacks: [], | 136     callbacks: [], | 
| 52 | 137 | 
| 53     send: function(message) | 138     send: function(message) | 
| 54     { | 139     { | 
| 55       var evt = document.createEvent("Event"); | 140       message.category = "proxy"; | 
| 56       evt.initEvent("beforeload"); | 141       message.pageId = documentInfo.pageId; | 
| 57       return safari.self.tab.canLoad(evt, {type: "proxy", payload: message}); | 142 | 
|  | 143       return safari.self.tab.canLoad(beforeLoadEvent, message); | 
| 58     }, | 144     }, | 
| 59     checkResult: function(result) | 145     checkResult: function(result) | 
| 60     { | 146     { | 
| 61       if (!result.succeed) | 147       if (!result.succeed) | 
| 62         throw result.error; | 148         throw result.error; | 
| 63     }, | 149     }, | 
| 64     deserializeResult: function(result) | 150     deserializeResult: function(result) | 
| 65     { | 151     { | 
| 66       this.checkResult(result); | 152       this.checkResult(result); | 
| 67       return this.deserialize(result.result); | 153       return this.deserialize(result.result); | 
| 68     }, | 154     }, | 
| 69     serialize: function(obj, memo) | 155     serialize: function(obj, memo) | 
| 70     { | 156     { | 
| 71       var objectId = this.objects.indexOf(obj); | 157       var objectId = this.objects.indexOf(obj); | 
| 72       if (objectId != -1) | 158       if (objectId != -1) | 
| 73         return {type: "hosted", objectId: objectId}; | 159         return {type: "hosted", objectId: objectId}; | 
| 74 | 160 | 
| 75       if (typeof obj == "function") | 161       if (typeof obj == "function") | 
| 76       { | 162       { | 
| 77         var callbackId = this.callbacks.indexOf(obj); | 163         var callbackId = this.callbacks.indexOf(obj); | 
| 78 |  | 
| 79         if (callbackId == -1) | 164         if (callbackId == -1) | 
| 80         { |  | 
| 81           callbackId = this.callbacks.push(obj) - 1; | 165           callbackId = this.callbacks.push(obj) - 1; | 
| 82 | 166 | 
| 83           safari.self.addEventListener("message", function(event) | 167         return {type: "callback", callbackId: callbackId, frameId: documentInfo.
     frameId}; | 
| 84           { |  | 
| 85             if (event.name == "proxyCallback") |  | 
| 86             if (event.message.callbackId == callbackId) |  | 
| 87               obj.apply( |  | 
| 88                 this.getObject(event.message.contextId), |  | 
| 89                 this.deserializeSequence(event.message.args) |  | 
| 90               ); |  | 
| 91           }.bind(this)); |  | 
| 92         } |  | 
| 93 |  | 
| 94         return {type: "callback", callbackId: callbackId}; |  | 
| 95       } | 168       } | 
| 96 | 169 | 
| 97       if (typeof obj == "object" && | 170       if (typeof obj == "object" && | 
| 98           obj != null && | 171           obj != null && | 
| 99           obj.constructor != Date && | 172           obj.constructor != Date && | 
| 100           obj.constructor != RegExp) | 173           obj.constructor != RegExp) | 
| 101       { | 174       { | 
| 102         if (!memo) | 175         if (!memo) | 
| 103           memo = {specs: [], objects: []}; | 176           memo = {specs: [], objects: []}; | 
| 104 | 177 | 
| (...skipping 114 matching lines...) Expand 10 before | Expand all | Expand 10 after  Loading... | 
| 219             functionId: objectId, | 292             functionId: objectId, | 
| 220             contextId: proxy.getObjectId(this), | 293             contextId: proxy.getObjectId(this), | 
| 221             args: Array.prototype.map.call( | 294             args: Array.prototype.map.call( | 
| 222               arguments, | 295               arguments, | 
| 223               proxy.serialize.bind(proxy) | 296               proxy.serialize.bind(proxy) | 
| 224             ) | 297             ) | 
| 225           }) | 298           }) | 
| 226         ); | 299         ); | 
| 227       }; | 300       }; | 
| 228     }, | 301     }, | 
| 229     getObject: function(objectId) { | 302     handleCallback: function(message) | 
|  | 303     { | 
|  | 304       this.callbacks[message.callbackId].apply( | 
|  | 305         this.getObject(message.contextId), | 
|  | 306         this.deserializeSequence(message.args) | 
|  | 307       ); | 
|  | 308     }, | 
|  | 309     getObject: function(objectId) | 
|  | 310     { | 
| 230       var objectInfo = this.send({ | 311       var objectInfo = this.send({ | 
| 231         type: "inspectObject", | 312         type: "inspectObject", | 
| 232         objectId: objectId | 313         objectId: objectId | 
| 233       }); | 314       }); | 
| 234 | 315 | 
| 235       var obj = this.objects[objectId]; | 316       var obj = this.objects[objectId]; | 
| 236       if (obj) | 317       if (obj) | 
| 237         Object.getOwnPropertyNames(obj).forEach(function(prop) { delete obj[prop
     ]; }); | 318         Object.getOwnPropertyNames(obj).forEach(function(prop) { delete obj[prop
     ]; }); | 
| 238       else | 319       else | 
| 239       { | 320       { | 
| (...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after  Loading... | 
| 274             property, objectInfo.properties[property].enumerable | 355             property, objectInfo.properties[property].enumerable | 
| 275           )); | 356           )); | 
| 276 | 357 | 
| 277       if (objectInfo.isFunction) | 358       if (objectInfo.isFunction) | 
| 278         obj.prototype = this.getProperty(objectId, "prototype"); | 359         obj.prototype = this.getProperty(objectId, "prototype"); | 
| 279 | 360 | 
| 280       return obj; | 361       return obj; | 
| 281     } | 362     } | 
| 282   }; | 363   }; | 
| 283 | 364 | 
|  | 365   ext.backgroundPage = { | 
|  | 366     sendMessage: function(message, responseCallback) | 
|  | 367     { | 
|  | 368       messageProxy.sendMessage(message, responseCallback, documentInfo); | 
|  | 369     }, | 
|  | 370     getWindow: function() | 
|  | 371     { | 
|  | 372       return backgroundPageProxy.getObject(0); | 
|  | 373     } | 
|  | 374   }; | 
|  | 375 | 
| 284 | 376 | 
| 285   /* Web request blocking */ | 377   /* Message processing */ | 
| 286 | 378 | 
| 287   document.addEventListener("beforeload", function(event) | 379   var messageProxy = new ext._MessageProxy(safari.self.tab); | 
|  | 380 | 
|  | 381   safari.self.addEventListener("message", function(event) | 
| 288   { | 382   { | 
| 289     // we don't block non-HTTP requests anyway, so we can bail out | 383     if (event.message.pageId == documentInfo.pageId) | 
| 290     // without asking the background page. This is even necessary | 384     { | 
| 291     // because passing large data (like a photo encoded as data: URL) | 385       if (event.name == "request") | 
| 292     // to the background page, freezes Safari. | 386       { | 
| 293     if (!/^https?:/.test(event.url)) | 387         messageProxy.handleRequest(event.message, {}); | 
| 294       return; | 388         return; | 
|  | 389       } | 
| 295 | 390 | 
| 296     var type; | 391       if (event.message.frameId == documentInfo.frameId) | 
| 297 | 392       { | 
| 298     switch(event.target.localName) | 393         switch (event.name) | 
| 299     { |  | 
| 300       case "frame": |  | 
| 301       case "iframe": |  | 
| 302         type = "sub_frame"; |  | 
| 303         break; |  | 
| 304       case "img": |  | 
| 305         type = "image"; |  | 
| 306         break; |  | 
| 307       case "object": |  | 
| 308       case "embed": |  | 
| 309         type = "object"; |  | 
| 310         break; |  | 
| 311       case "script": |  | 
| 312         type = "script"; |  | 
| 313         break; |  | 
| 314       case "link": |  | 
| 315         if (/\bstylesheet\b/i.test(event.target.rel)) |  | 
| 316         { | 394         { | 
| 317           type = "stylesheet"; | 395           case "response": | 
| 318           break; | 396             messageProxy.handleResponse(event.message); | 
| 319         } | 397             break; | 
| 320       default: | 398           case "proxyCallback": | 
| 321         type = "other"; | 399             backgroundPageProxy.handleCallback(event.message); | 
| 322     } | 400             break; | 
| 323 |  | 
| 324     if (!safari.self.tab.canLoad( |  | 
| 325       event, { |  | 
| 326         type: "webRequest", |  | 
| 327         payload: { |  | 
| 328           url: event.url, |  | 
| 329           type: type, |  | 
| 330           documentUrl: document.location.href, |  | 
| 331           isTopLevel: window == window.top |  | 
| 332         } | 401         } | 
| 333       } | 402       } | 
| 334     )) |  | 
| 335     { |  | 
| 336       event.preventDefault(); |  | 
| 337 |  | 
| 338       // Safari doesn't dispatch an "error" event when preventing an element |  | 
| 339       // from loading by cancelling the "beforeload" event. So we have to |  | 
| 340       // dispatch it manually. Otherwise element collapsing wouldn't work. |  | 
| 341       if (type != "sub_frame") |  | 
| 342       { |  | 
| 343         var evt = document.createEvent("Event"); |  | 
| 344         evt.initEvent("error"); |  | 
| 345         event.target.dispatchEvent(evt); |  | 
| 346       } |  | 
| 347     } | 403     } | 
| 348   }, true); | 404   }); | 
| 349 |  | 
| 350 |  | 
| 351   /* API */ |  | 
| 352 |  | 
| 353   ext.backgroundPage = { |  | 
| 354     sendMessage: function(message, responseCallback) |  | 
| 355     { |  | 
| 356       _sendMessage( |  | 
| 357         message, responseCallback, |  | 
| 358         safari.self.tab, safari.self, |  | 
| 359         { |  | 
| 360           documentUrl: document.location.href, |  | 
| 361           isTopLevel: window == window.top |  | 
| 362         } |  | 
| 363       ); |  | 
| 364     }, |  | 
| 365     getWindow: function() |  | 
| 366     { |  | 
| 367       return proxy.getObject(0); |  | 
| 368     } |  | 
| 369   }; |  | 
| 370 |  | 
| 371   ext.onMessage = new ContentMessageEventTarget(); |  | 
| 372 |  | 
| 373 |  | 
| 374   // Safari does not pass the element which the context menu is refering to |  | 
| 375   // so we need to add it to the event's user info. |  | 
| 376   document.addEventListener("contextmenu", function(event) |  | 
| 377   { |  | 
| 378     var element = event.srcElement; |  | 
| 379     safari.self.tab.setContextMenuEventUserInfo(event, { |  | 
| 380       srcUrl: ("src" in element) ? element.src : null, |  | 
| 381       tagName: element.localName |  | 
| 382     }); |  | 
| 383   }, false); |  | 
| 384 })(); | 405 })(); | 
| OLD | NEW | 
|---|