| Left: | ||
| Right: |
| 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-2013 Eyeo GmbH | 3 * Copyright (C) 2006-2013 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 /* Tabs */ | 20 /* Events */ |
| 21 | 21 |
| 22 var TabEventTarget = function() | 22 var TabEventTarget = function() |
| 23 { | 23 { |
| 24 WrappedEventTarget.apply(this, arguments); | 24 WrappedEventTarget.apply(this, arguments); |
| 25 }; | 25 }; |
| 26 TabEventTarget.prototype = { | 26 TabEventTarget.prototype = { |
| 27 __proto__: WrappedEventTarget.prototype, | 27 __proto__: WrappedEventTarget.prototype, |
| 28 _wrapListener: function(listener) | 28 _wrapListener: function(listener) |
| 29 { | 29 { |
| 30 return function(event) | 30 return function(event) |
| (...skipping 13 matching lines...) Expand all Loading... | |
| 44 _wrapListener: function(listener) | 44 _wrapListener: function(listener) |
| 45 { | 45 { |
| 46 return function (event) | 46 return function (event) |
| 47 { | 47 { |
| 48 if (event.name == "loading") | 48 if (event.name == "loading") |
| 49 listener(new Tab(event.target)); | 49 listener(new Tab(event.target)); |
| 50 }; | 50 }; |
| 51 } | 51 } |
| 52 }; | 52 }; |
| 53 | 53 |
| 54 var BackgroundMessageEventTarget = function() | |
| 55 { | |
| 56 MessageEventTarget.call(this, safari.application); | |
| 57 }; | |
| 58 BackgroundMessageEventTarget.prototype = { | |
| 59 __proto__: MessageEventTarget.prototype, | |
| 60 _getResponseDispatcher: function(event) | |
| 61 { | |
| 62 return event.target.page; | |
| 63 }, | |
| 64 _getSenderDetails: function(event) | |
| 65 { | |
| 66 return { | |
| 67 tab: new Tab(event.target), | |
| 68 frame: new Frame( | |
| 69 event.message.documentUrl, | |
| 70 event.message.isTopLevel, | |
| 71 event.target | |
| 72 ) | |
| 73 }; | |
| 74 } | |
| 75 }; | |
| 76 | |
| 77 | |
| 78 /* Tabs */ | |
| 79 | |
| 54 Tab = function(tab) | 80 Tab = function(tab) |
| 55 { | 81 { |
| 56 this._tab = tab; | 82 this._tab = tab; |
| 57 | 83 |
| 58 this._eventTarget = tab; | |
| 59 this._messageDispatcher = tab.page; | |
| 60 | |
| 61 this.onLoading = new LoadingTabEventTarget(tab); | 84 this.onLoading = new LoadingTabEventTarget(tab); |
| 85 this.onBeforeNavigate = new TabEventTarget(tab, "beforeNavigate", false); | |
| 62 this.onCompleted = new TabEventTarget(tab, "navigate", false); | 86 this.onCompleted = new TabEventTarget(tab, "navigate", false); |
| 63 this.onActivated = new TabEventTarget(tab, "activate", false); | 87 this.onActivated = new TabEventTarget(tab, "activate", false); |
| 64 this.onRemoved = new TabEventTarget(tab, "close", false); | 88 this.onRemoved = new TabEventTarget(tab, "close", false); |
| 65 }; | 89 }; |
| 66 Tab.prototype = { | 90 Tab.prototype = { |
| 67 get url() | 91 get url() |
| 68 { | 92 { |
| 69 return this._tab.url; | 93 return this._tab.url; |
| 70 }, | 94 }, |
| 71 close: function() | 95 close: function() |
| 72 { | 96 { |
| 73 this._tab.close(); | 97 this._tab.close(); |
| 74 }, | 98 }, |
| 75 activate: function() | 99 activate: function() |
| 76 { | 100 { |
| 77 this._tab.activate(); | 101 this._tab.activate(); |
| 78 }, | 102 }, |
| 79 sendMessage: sendMessage, | 103 sendMessage: function(message, responseCallback) |
| 104 { | |
| 105 _sendMessage( | |
| 106 message, responseCallback, | |
| 107 this._tab.page, this._tab | |
| 108 ); | |
| 109 }, | |
| 80 browserAction: { | 110 browserAction: { |
| 81 setIcon: function(path) | 111 setIcon: function(path) |
| 82 { | 112 { |
| 83 safari.extension.toolbarItems[0].image = safari.extension.baseURI + path ; | 113 safari.extension.toolbarItems[0].image = safari.extension.baseURI + path ; |
| 84 }, | 114 }, |
| 85 setTitle: function(title) | 115 setTitle: function(title) |
| 86 { | 116 { |
| 87 safari.extension.toolbarItems[0].toolTip = title; | 117 safari.extension.toolbarItems[0].toolTip = title; |
| 88 }, | 118 }, |
| 89 setBadge: function(badge) | 119 setBadge: function(badge) |
| 90 { | 120 { |
| 91 if (!badge) | 121 if (!badge) |
| 92 safari.extension.toolbarItems[0].badge = 0; | 122 safari.extension.toolbarItems[0].badge = 0; |
| 93 else if ("number" in badge) | 123 else if ("number" in badge) |
| 94 safari.extension.toolbarItems[0].badge = badge.number; | 124 safari.extension.toolbarItems[0].badge = badge.number; |
| 95 } | 125 } |
| 96 } | 126 } |
| 97 }; | 127 }; |
| 98 | 128 |
| 99 TabMap = function() | 129 TabMap = function(deleteTabOnBeforeNavigate) |
| 100 { | 130 { |
| 101 this._tabs = []; | 131 this._tabs = []; |
| 102 this._values = []; | 132 this._values = []; |
| 103 | 133 |
| 104 this._onClosed = this._onClosed.bind(this); | 134 this._deleteOnEvent = this._deleteOnEvent.bind(this); |
| 135 this._deleteTabOnBeforeNavigate = deleteTabOnBeforeNavigate; | |
| 105 }; | 136 }; |
| 106 TabMap.prototype = | 137 TabMap.prototype = |
| 107 { | 138 { |
| 108 get: function(tab) { | 139 get: function(tab) { |
| 109 var idx; | 140 var idx; |
| 110 | 141 |
| 111 if (!tab || (idx = this._tabs.indexOf(tab._tab)) == -1) | 142 if (!tab || (idx = this._tabs.indexOf(tab._tab)) == -1) |
| 112 return null; | 143 return null; |
| 113 | 144 |
| 114 return this._values[idx]; | 145 return this._values[idx]; |
| 115 }, | 146 }, |
| 116 set: function(tab, value) | 147 set: function(tab, value) |
| 117 { | 148 { |
| 118 var idx = this._tabs.indexOf(tab._tab); | 149 var idx = this._tabs.indexOf(tab._tab); |
| 119 | 150 |
| 120 if (idx != -1) | 151 if (idx != -1) |
| 121 this._values[idx] = value; | 152 this._values[idx] = value; |
| 122 else | 153 else |
| 123 { | 154 { |
| 124 this._tabs.push(tab._tab); | 155 this._tabs.push(tab._tab); |
| 125 this._values.push(value); | 156 this._values.push(value); |
| 126 | 157 |
| 127 tab._tab.addEventListener("close", this._onClosed, false); | 158 tab._tab.addEventListener("close", this._deleteOnEvent, false); |
| 159 if (this._deleteTabOnBeforeNavigate) | |
| 160 tab._tab.addEventListener("beforeNavigate", this._deleteOnEvent, false ); | |
| 128 } | 161 } |
| 129 }, | 162 }, |
| 130 has: function(tab) | 163 has: function(tab) |
| 131 { | 164 { |
| 132 return this._tabs.indexOf(tab._tab) != -1; | 165 return this._tabs.indexOf(tab._tab) != -1; |
| 133 }, | 166 }, |
| 134 clear: function() | 167 clear: function() |
| 135 { | 168 { |
| 136 while (this._tabs.length > 0) | 169 while (this._tabs.length > 0) |
| 137 this._delete(this._tabs[0]); | 170 this._delete(this._tabs[0]); |
| 138 }, | 171 }, |
| 139 _delete: function(tab) | 172 _delete: function(tab) |
| 140 { | 173 { |
| 141 var idx = this._tabs.indexOf(tab); | 174 var idx = this._tabs.indexOf(tab); |
| 142 | 175 |
| 143 if (idx != -1) | 176 if (idx != -1) |
| 144 { | 177 { |
| 145 this._tabs.splice(idx, 1); | 178 this._tabs.splice(idx, 1); |
| 146 this._values.splice(idx, 1); | 179 this._values.splice(idx, 1); |
| 147 | 180 |
| 148 tab.removeEventListener("close", this._onClosed, false); | 181 tab.removeEventListener("close", this._deleteOnEvent, false); |
| 182 tab.removeEventListener("beforeNavigate", this._deleteOnEvent, false); | |
| 149 } | 183 } |
| 150 }, | 184 }, |
| 151 _onClosed: function(event) | 185 _deleteOnEvent: function(event) |
| 152 { | 186 { |
| 153 this._delete(event.target); | 187 // delay so that other event handlers can still lookup this tab |
| 188 setTimeout(this._delete.bind(this, event.target), 0); | |
|
Felix Dahlke
2014/01/18 13:39:19
s/lookup this tab/look this tab up/
Sebastian Noack
2014/01/19 10:19:40
Done.
| |
| 154 } | 189 } |
| 155 }; | 190 }; |
| 156 TabMap.prototype["delete"] = function(tab) | 191 TabMap.prototype["delete"] = function(tab) |
| 157 { | 192 { |
| 158 this._delete(tab._tab); | 193 this._delete(tab._tab); |
| 159 }; | 194 }; |
| 160 | 195 |
| 161 | 196 |
| 162 /* Windows */ | 197 /* Windows */ |
| 163 | 198 |
| (...skipping 18 matching lines...) Expand all Loading... | |
| 182 { | 217 { |
| 183 var tab = this._win.openTab(); | 218 var tab = this._win.openTab(); |
| 184 tab.url = url; | 219 tab.url = url; |
| 185 | 220 |
| 186 if (callback) | 221 if (callback) |
| 187 callback(new Tab(tab)); | 222 callback(new Tab(tab)); |
| 188 } | 223 } |
| 189 }; | 224 }; |
| 190 | 225 |
| 191 | 226 |
| 227 /* Frames */ | |
| 228 | |
| 229 Frame = function(url, isTopLevel, tab) | |
| 230 { | |
| 231 this.url = url; | |
| 232 | |
| 233 // there is no way to discover frames with Safari's API. | |
| 234 // so if this isn't the top level frame, assume that the parent is. | |
| 235 // this is the best we can do for Safari. :( | |
|
Felix Dahlke
2014/01/18 13:39:19
We could cache a chain of frames like we do in And
| |
| 236 if (!isTopLevel) | |
| 237 this.parent = new Frame(tab.url, true); | |
| 238 else | |
| 239 this.parent = null; | |
| 240 }; | |
| 241 | |
| 242 | |
| 192 /* Background page proxy */ | 243 /* Background page proxy */ |
| 193 | 244 |
| 194 var proxy = { | 245 var proxy = { |
| 195 tabs: [], | 246 tabs: [], |
| 196 objects: [], | 247 objects: [], |
| 197 | 248 |
| 198 registerObject: function(obj, objects) | 249 registerObject: function(obj, objects) |
| 199 { | 250 { |
| 200 var objectId = objects.indexOf(obj); | 251 var objectId = objects.indexOf(obj); |
| 201 | 252 |
| (...skipping 210 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 412 } | 463 } |
| 413 } | 464 } |
| 414 }; | 465 }; |
| 415 | 466 |
| 416 | 467 |
| 417 /* Web request blocking */ | 468 /* Web request blocking */ |
| 418 | 469 |
| 419 ext.webRequest = { | 470 ext.webRequest = { |
| 420 onBeforeRequest: { | 471 onBeforeRequest: { |
| 421 _listeners: [], | 472 _listeners: [], |
| 422 _urlPatterns: [], | |
| 423 | 473 |
| 424 _handleMessage: function(message, tab) | 474 _handleMessage: function(message, rawTab) |
| 425 { | 475 { |
| 426 tab = new Tab(tab); | 476 var tab = new Tab(rawTab); |
| 477 var frame = new Frame(message.documentUrl, message.isTopLevel, rawTab); | |
| 427 | 478 |
| 428 for (var i = 0; i < this._listeners.length; i++) | 479 for (var i = 0; i < this._listeners.length; i++) |
| 429 { | 480 { |
| 430 var regex = this._urlPatterns[i]; | 481 if (this._listeners[i](message.url, message.type, tab, frame) === fals e) |
| 431 | |
| 432 if ((!regex || regex.test(message.url)) && this._listeners[i](message. url, message.type, tab, 0, -1) === false) | |
| 433 return false; | 482 return false; |
| 434 } | 483 } |
| 435 | 484 |
| 436 return true; | 485 return true; |
| 437 }, | 486 }, |
| 438 addListener: function(listener, urls) | 487 addListener: function(listener) |
| 439 { | 488 { |
| 440 var regex; | |
| 441 | |
| 442 if (urls) | |
| 443 regex = new RegExp("^(?:" + urls.map(function(url) | |
| 444 { | |
| 445 return url.split("*").map(function(s) | |
| 446 { | |
| 447 return s.replace(/([.?+^$[\]\\(){}|-])/g, "\\$1"); | |
| 448 }).join(".*"); | |
| 449 }).join("|") + ")($|[?#])"); | |
| 450 | |
| 451 this._listeners.push(listener); | 489 this._listeners.push(listener); |
| 452 this._urlPatterns.push(regex); | |
| 453 }, | 490 }, |
| 454 removeListener: function(listener) | 491 removeListener: function(listener) |
| 455 { | 492 { |
| 456 var idx = this._listeners.indexOf(listener); | 493 var idx = this._listeners.indexOf(listener); |
| 457 | |
| 458 if (idx != -1) | 494 if (idx != -1) |
| 459 { | |
| 460 this._listeners.splice(idx, 1); | 495 this._listeners.splice(idx, 1); |
| 461 this._urlPatterns.splice(idx, 1); | |
| 462 } | |
| 463 } | 496 } |
| 464 }, | 497 }, |
| 465 handlerBehaviorChanged: function() {} | 498 handlerBehaviorChanged: function() {} |
| 466 }; | 499 }; |
| 467 | 500 |
| 468 | 501 |
| 469 /* Synchronous messaging */ | 502 /* Synchronous messaging */ |
| 470 | 503 |
| 471 safari.application.addEventListener("message", function(event) | 504 safari.application.addEventListener("message", function(event) |
| 472 { | 505 { |
| (...skipping 27 matching lines...) Expand all Loading... | |
| 500 })); | 533 })); |
| 501 }, | 534 }, |
| 502 getLastFocused: function(callback) | 535 getLastFocused: function(callback) |
| 503 { | 536 { |
| 504 callback(new Window(safari.application.activeBrowserWindow)); | 537 callback(new Window(safari.application.activeBrowserWindow)); |
| 505 } | 538 } |
| 506 }; | 539 }; |
| 507 | 540 |
| 508 ext.tabs = { | 541 ext.tabs = { |
| 509 onLoading: new LoadingTabEventTarget(safari.application), | 542 onLoading: new LoadingTabEventTarget(safari.application), |
| 543 onBeforeNavigate: new TabEventTarget(safari.application, "beforeNavigate", t rue), | |
| 510 onCompleted: new TabEventTarget(safari.application, "navigate", true), | 544 onCompleted: new TabEventTarget(safari.application, "navigate", true), |
| 511 onActivated: new TabEventTarget(safari.application, "activate", true), | 545 onActivated: new TabEventTarget(safari.application, "activate", true), |
| 512 onRemoved: new TabEventTarget(safari.application, "close", true) | 546 onRemoved: new TabEventTarget(safari.application, "close", true) |
| 513 }; | 547 }; |
| 514 | 548 |
| 515 ext.backgroundPage = { | 549 ext.backgroundPage = { |
| 516 getWindow: function() | 550 getWindow: function() |
| 517 { | 551 { |
| 518 return safari.extension.globalPage.contentWindow; | 552 return safari.extension.globalPage.contentWindow; |
| 519 } | 553 } |
| 520 }; | 554 }; |
| 521 | 555 |
| 522 ext.onMessage = new MessageEventTarget(safari.application); | 556 ext.onMessage = new BackgroundMessageEventTarget(); |
| 523 | 557 |
| 524 // TODO: Implement context menu | 558 // TODO: Implement context menu |
| 525 ext.contextMenus = { | 559 ext.contextMenus = { |
| 526 create: function(title, contexts, onclick) {}, | 560 create: function(title, contexts, onclick) {}, |
| 527 removeAll: function(callback) {} | 561 removeAll: function(callback) {} |
| 528 }; | 562 }; |
| 529 })(); | 563 })(); |
| OLD | NEW |