Left: | ||
Right: |
LEFT | RIGHT |
---|---|
1 /* | 1 /* |
2 * This file is part of Adblock Plus <https://adblockplus.org/>, | 2 * This file is part of Adblock Plus <https://adblockplus.org/>, |
3 * Copyright (C) 2006-2015 Eyeo GmbH | 3 * Copyright (C) 2006-2015 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 /** | 18 /** |
19 * @fileOverview Content policy implementation, responsible for blocking things. | 19 * @fileOverview Content policy implementation, responsible for blocking things. |
20 */ | 20 */ |
21 | 21 |
22 Cu.import("resource://gre/modules/XPCOMUtils.jsm"); | 22 "use strict"; |
23 Cu.import("resource://gre/modules/Services.jsm"); | 23 |
24 let {XPCOMUtils} = Cu.import("resource://gre/modules/XPCOMUtils.jsm", {}); | |
25 let {Services} = Cu.import("resource://gre/modules/Services.jsm", {}); | |
24 | 26 |
25 let {Utils} = require("utils"); | 27 let {Utils} = require("utils"); |
26 let {Prefs} = require("prefs"); | 28 let {Prefs} = require("prefs"); |
27 let {FilterStorage} = require("filterStorage"); | 29 let {FilterStorage} = require("filterStorage"); |
28 let {BlockingFilter, WhitelistFilter, RegExpFilter} = require("filterClasses"); | 30 let {BlockingFilter, WhitelistFilter, RegExpFilter} = require("filterClasses"); |
29 let {defaultMatcher} = require("matcher"); | 31 let {defaultMatcher} = require("matcher"); |
30 let {objectMouseEventHander} = require("objectTabs"); | 32 let {objectMouseEventHander} = require("objectTabs"); |
31 let {RequestNotifier} = require("requestNotifier"); | 33 let {RequestNotifier} = require("requestNotifier"); |
32 let {ElemHide} = require("elemHide"); | 34 let {ElemHide} = require("elemHide"); |
33 | 35 |
(...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
79 localizedDescr: {}, | 81 localizedDescr: {}, |
80 | 82 |
81 /** | 83 /** |
82 * Lists the non-visual content types. | 84 * Lists the non-visual content types. |
83 * @type Object | 85 * @type Object |
84 */ | 86 */ |
85 nonVisual: {}, | 87 nonVisual: {}, |
86 | 88 |
87 /** | 89 /** |
88 * Map containing all schemes that should be ignored by content policy. | 90 * Map containing all schemes that should be ignored by content policy. |
89 * @type Object | 91 * @type Set |
90 */ | 92 */ |
91 whitelistSchemes: {}, | 93 whitelistSchemes: new Set(), |
92 | 94 |
93 /** | 95 /** |
94 * Called on module startup, initializes various exported properties. | 96 * Called on module startup, initializes various exported properties. |
95 */ | 97 */ |
96 init: function() | 98 init: function() |
97 { | 99 { |
98 // type constant by type description and type description by type constant | 100 // type constant by type description and type description by type constant |
99 let iface = Ci.nsIContentPolicy; | 101 let iface = Ci.nsIContentPolicy; |
100 for (let typeName of contentTypes) | 102 for (let typeName of contentTypes) |
101 { | 103 { |
(...skipping 25 matching lines...) Expand all Loading... | |
127 this.type.POPUP = 0xFFFE; | 129 this.type.POPUP = 0xFFFE; |
128 this.typeDescr[0xFFFE] = "POPUP"; | 130 this.typeDescr[0xFFFE] = "POPUP"; |
129 this.localizedDescr[0xFFFE] = Utils.getString("type_label_popup"); | 131 this.localizedDescr[0xFFFE] = Utils.getString("type_label_popup"); |
130 this.typeMask[0xFFFE] = RegExpFilter.typeMap.POPUP; | 132 this.typeMask[0xFFFE] = RegExpFilter.typeMap.POPUP; |
131 | 133 |
132 for (let type of nonVisualTypes) | 134 for (let type of nonVisualTypes) |
133 this.nonVisual[this.type[type]] = true; | 135 this.nonVisual[this.type[type]] = true; |
134 | 136 |
135 // whitelisted URL schemes | 137 // whitelisted URL schemes |
136 for (let scheme of Prefs.whitelistschemes.toLowerCase().split(" ")) | 138 for (let scheme of Prefs.whitelistschemes.toLowerCase().split(" ")) |
137 this.whitelistSchemes[scheme] = true; | 139 this.whitelistSchemes.add(scheme); |
138 | 140 |
139 // Generate class identifier used to collapse node and register correspondin g | 141 // Generate class identifier used to collapse node and register correspondin g |
140 // stylesheet. | 142 // stylesheet. |
141 let offset = "a".charCodeAt(0); | 143 let offset = "a".charCodeAt(0); |
142 for (let i = 0; i < 20; i++) | 144 for (let i = 0; i < 20; i++) |
143 collapsedClass += String.fromCharCode(offset + Math.random() * 26); | 145 collapsedClass += String.fromCharCode(offset + Math.random() * 26); |
144 | 146 |
145 let collapseStyle = Services.io.newURI("data:text/css," + | 147 let collapseStyle = Services.io.newURI("data:text/css," + |
146 encodeURIComponent("." + collapsedClass + | 148 encodeURIComponent("." + collapsedClass + |
147 "{-moz-binding: url(chrome://global/content/bindings/general.xml#foobarb azdummy) !important;}"), null, null); | 149 "{-moz-binding: url(chrome://global/content/bindings/general.xml#foobarb azdummy) !important;}"), null, null); |
148 Utils.styleService.loadAndRegisterSheet(collapseStyle, Ci.nsIStyleSheetServi ce.USER_SHEET); | 150 Utils.styleService.loadAndRegisterSheet(collapseStyle, Ci.nsIStyleSheetServi ce.USER_SHEET); |
149 onShutdown.add(function() | 151 onShutdown.add(() => |
150 { | 152 { |
151 Utils.styleService.unregisterSheet(collapseStyle, Ci.nsIStyleSheetService. USER_SHEET); | 153 Utils.styleService.unregisterSheet(collapseStyle, Ci.nsIStyleSheetService. USER_SHEET); |
152 }); | 154 }); |
153 }, | 155 }, |
154 | 156 |
155 /** | 157 /** |
156 * Checks whether a node should be blocked, hides it if necessary | 158 * Checks whether a node should be blocked, hides it if necessary |
157 * @param wnd {nsIDOMWindow} | 159 * @param wnd {nsIDOMWindow} |
158 * @param node {nsIDOMElement} | 160 * @param node {nsIDOMElement} |
159 * @param contentType {String} | 161 * @param contentType {String} |
160 * @param location {nsIURI} | 162 * @param location {nsIURI} |
161 * @param collapse {Boolean} true to force hiding of the node | 163 * @param collapse {Boolean} true to force hiding of the node |
162 * @return {Boolean} false if the node should be blocked | 164 * @return {Boolean} false if the node should be blocked |
163 */ | 165 */ |
164 processNode: function(wnd, node, contentType, location, collapse) | 166 processNode: function(wnd, node, contentType, location, collapse) |
165 { | 167 { |
166 let topWnd = wnd.top; | 168 let topWnd = wnd.top; |
167 if (!topWnd || !topWnd.location || !topWnd.location.href) | 169 if (!topWnd || !topWnd.location || !topWnd.location.href) |
168 return true; | 170 return true; |
169 | 171 |
170 let originWindow = Utils.getOriginWindow(wnd); | 172 let originWindow = Utils.getOriginWindow(wnd); |
171 let wndLocation = originWindow.location.href; | 173 let wndLocation = originWindow.location.href; |
172 let docDomain = getHostname(wndLocation); | 174 let docDomain = getHostname(wndLocation); |
173 let match = null; | 175 let match = null; |
174 let [sitekey, sitekeyWnd] = getSitekey(wnd); | 176 let [sitekey, sitekeyWnd] = getSitekey(wnd); |
175 let nogeneric = false; | 177 let nogeneric = false; |
176 | 178 |
177 function cleanWindowLocation(wnd) | 179 function cleanWindowLocation(wnd) |
Thomas Greiner
2015/11/10 18:22:33
This function doesn't need to be inside `processNo
Wladimir Palant
2015/11/10 19:13:15
Given that this is a temporary solution I'd rather
| |
178 { | 180 { |
179 let url = getWindowLocation(wnd); | 181 let url = getWindowLocation(wnd); |
180 let index = url.indexOf("#"); | 182 let index = url.indexOf("#"); |
181 if (index >= 0) | 183 if (index >= 0) |
182 url = url.substring(0, index); | 184 url = url.substring(0, index); |
183 | 185 |
184 return url; | 186 return url; |
185 } | 187 } |
186 | 188 |
187 if (!match && Prefs.enabled) | 189 if (!match && Prefs.enabled) |
188 { | 190 { |
189 let testWnd = wnd; | 191 let testWnd = wnd; |
190 let testSitekey = sitekey; | 192 let testSitekey = sitekey; |
191 let testSitekeyWnd = sitekeyWnd; | 193 let testSitekeyWnd = sitekeyWnd; |
192 let parentWndLocation = cleanWindowLocation(testWnd); | 194 let parentWndLocation = cleanWindowLocation(testWnd); |
193 while (true) | 195 while (true) |
194 { | 196 { |
195 let testWndLocation = parentWndLocation; | 197 let testWndLocation = parentWndLocation; |
196 parentWndLocation = (testWnd == testWnd.parent ? testWndLocation : clean WindowLocation(testWnd.parent)); | 198 parentWndLocation = (testWnd == testWnd.parent ? testWndLocation : clean WindowLocation(testWnd.parent)); |
197 let parentDocDomain = getHostname(parentWndLocation); | 199 let parentDocDomain = getHostname(parentWndLocation); |
198 | 200 |
199 let typeMap = RegExpFilter.typeMap.DOCUMENT; | 201 let typeMap = RegExpFilter.typeMap.DOCUMENT; |
200 if (contentType == Policy.type.ELEMHIDE) | 202 if (contentType == Policy.type.ELEMHIDE) |
201 typeMap = typeMap | RegExpFilter.typeMap.ELEMHIDE; | 203 typeMap = typeMap | RegExpFilter.typeMap.ELEMHIDE; |
202 let whitelistMatch = defaultMatcher.matchesAny(testWndLocation, typeMap, parentDocDomain, false, sitekey); | 204 let whitelistMatch = defaultMatcher.matchesAny(testWndLocation, typeMap, parentDocDomain, false, testSitekey); |
Thomas Greiner
2015/11/10 18:22:34
`sitekey` is the bottom window's sitekey so should
Wladimir Palant
2015/11/10 19:13:15
Yes, this should really be testSitekey - this was
Wladimir Palant
2015/11/11 07:54:20
Done.
| |
203 if (whitelistMatch instanceof WhitelistFilter) | 205 if (whitelistMatch instanceof WhitelistFilter) |
204 { | 206 { |
205 FilterStorage.increaseHitCount(whitelistMatch, wnd); | 207 FilterStorage.increaseHitCount(whitelistMatch, wnd); |
206 RequestNotifier.addNodeData(testWnd.document, topWnd, | 208 RequestNotifier.addNodeData(testWnd.document, topWnd, |
207 (whitelistMatch.contentType & RegExpFilter.typeMap.DOCUMENT) ? Polic y.type.DOCUMENT : Policy.type.ELEMHIDE, | 209 (whitelistMatch.contentType & RegExpFilter.typeMap.DOCUMENT) ? Polic y.type.DOCUMENT : Policy.type.ELEMHIDE, |
208 parentDocDomain, false, testWndLocation, whitelistMatch); | 210 parentDocDomain, false, testWndLocation, whitelistMatch); |
209 return true; | 211 return true; |
210 } | 212 } |
211 | 213 |
212 let genericType = (contentType == Policy.type.ELEMHIDE ? | 214 let genericType = (contentType == Policy.type.ELEMHIDE ? |
(...skipping 79 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
292 return !match || match instanceof WhitelistFilter; | 294 return !match || match instanceof WhitelistFilter; |
293 }, | 295 }, |
294 | 296 |
295 /** | 297 /** |
296 * Checks whether the location's scheme is blockable. | 298 * Checks whether the location's scheme is blockable. |
297 * @param location {nsIURI} | 299 * @param location {nsIURI} |
298 * @return {Boolean} | 300 * @return {Boolean} |
299 */ | 301 */ |
300 isBlockableScheme: function(location) | 302 isBlockableScheme: function(location) |
301 { | 303 { |
302 return !(location.scheme in Policy.whitelistSchemes); | 304 return !this.whitelistSchemes.has(location.scheme); |
303 }, | 305 }, |
304 | 306 |
305 /** | 307 /** |
306 * Checks whether a page is whitelisted. | 308 * Checks whether a page is whitelisted. |
307 * @param {String} url | 309 * @param {String} url |
308 * @param {String} [parentUrl] location of the parent page | 310 * @param {String} [parentUrl] location of the parent page |
309 * @param {String} [sitekey] public key provided on the page | 311 * @param {String} [sitekey] public key provided on the page |
310 * @return {Filter} filter that matched the URL or null if not whitelisted | 312 * @return {Filter} filter that matched the URL or null if not whitelisted |
311 */ | 313 */ |
312 isWhitelisted: function(url, parentUrl, sitekey) | 314 isWhitelisted: function(url, parentUrl, sitekey) |
313 { | 315 { |
314 if (!url) | 316 if (!url) |
315 return null; | 317 return null; |
316 | 318 |
317 // Do not apply exception rules to schemes on our whitelistschemes list. | 319 // Do not apply exception rules to schemes on our whitelistschemes list. |
318 let match = /^([\w\-]+):/.exec(url); | 320 let match = /^([\w\-]+):/.exec(url); |
319 if (match && match[1] in Policy.whitelistSchemes) | 321 if (match && this.whitelistSchemes.has(match[1])) |
320 return null; | 322 return null; |
321 | 323 |
322 if (!parentUrl) | 324 if (!parentUrl) |
323 parentUrl = url; | 325 parentUrl = url; |
324 | 326 |
325 // Ignore fragment identifier | 327 // Ignore fragment identifier |
326 let index = url.indexOf("#"); | 328 let index = url.indexOf("#"); |
327 if (index >= 0) | 329 if (index >= 0) |
328 url = url.substring(0, index); | 330 url = url.substring(0, index); |
329 | 331 |
330 let result = defaultMatcher.matchesAny(url, RegExpFilter.typeMap.DOCUMENT, g etHostname(parentUrl), false, sitekey); | 332 let result = defaultMatcher.matchesAny(url, RegExpFilter.typeMap.DOCUMENT, g etHostname(parentUrl), false, sitekey); |
331 return (result instanceof WhitelistFilter ? result : null); | 333 return (result instanceof WhitelistFilter ? result : null); |
332 }, | 334 }, |
333 | 335 |
334 /** | 336 /** |
335 * Checks whether the page loaded in a window is whitelisted for indication in the UI. | 337 * Checks whether the page loaded in a window is whitelisted for indication in the UI. |
336 * @param wnd {nsIDOMWindow} | 338 * @param wnd {nsIDOMWindow} |
337 * @return {Filter} matching exception rule or null if not whitelisted | 339 * @return {Filter} matching exception rule or null if not whitelisted |
338 */ | 340 */ |
339 isWindowWhitelisted: function(wnd) | 341 isWindowWhitelisted: function(wnd) |
340 { | 342 { |
341 return Policy.isWhitelisted(getWindowLocation(wnd)); | 343 return this.isWhitelisted(getWindowLocation(wnd)); |
342 }, | 344 }, |
343 | 345 |
344 /** | 346 /** |
345 * Asynchronously re-checks filters for given nodes. | 347 * Asynchronously re-checks filters for given nodes. |
346 * @param {Node[]} nodes | 348 * @param {Node[]} nodes |
347 * @param {RequestEntry} entry | 349 * @param {RequestEntry} entry |
348 */ | 350 */ |
349 refilterNodes: function(nodes, entry) | 351 refilterNodes: function(nodes, entry) |
350 { | 352 { |
351 // Ignore nodes that have been blocked already | 353 // Ignore nodes that have been blocked already |
(...skipping 24 matching lines...) Expand all Loading... | |
376 { | 378 { |
377 let registrar = Components.manager.QueryInterface(Ci.nsIComponentRegistrar); | 379 let registrar = Components.manager.QueryInterface(Ci.nsIComponentRegistrar); |
378 registrar.registerFactory(this.classID, this.classDescription, this.contract ID, this); | 380 registrar.registerFactory(this.classID, this.classDescription, this.contract ID, this); |
379 | 381 |
380 let catMan = Utils.categoryManager; | 382 let catMan = Utils.categoryManager; |
381 for (let category of this.xpcom_categories) | 383 for (let category of this.xpcom_categories) |
382 catMan.addCategoryEntry(category, this.contractID, this.contractID, false, true); | 384 catMan.addCategoryEntry(category, this.contractID, this.contractID, false, true); |
383 | 385 |
384 Services.obs.addObserver(this, "content-document-global-created", true); | 386 Services.obs.addObserver(this, "content-document-global-created", true); |
385 | 387 |
386 onShutdown.add(function() | 388 onShutdown.add(() => |
387 { | 389 { |
388 Services.obs.removeObserver(this, "content-document-global-created"); | 390 Services.obs.removeObserver(this, "content-document-global-created"); |
389 | 391 |
390 for (let category of this.xpcom_categories) | 392 for (let category of this.xpcom_categories) |
391 catMan.deleteCategoryEntry(category, this.contractID, false); | 393 catMan.deleteCategoryEntry(category, this.contractID, false); |
392 | 394 |
393 registrar.unregisterFactory(this.classID, this); | 395 registrar.unregisterFactory(this.classID, this); |
394 }.bind(this)); | 396 }); |
395 }, | 397 }, |
396 | 398 |
397 // | 399 // |
398 // nsISupports interface implementation | 400 // nsISupports interface implementation |
399 // | 401 // |
400 | 402 |
401 QueryInterface: XPCOMUtils.generateQI([Ci.nsIContentPolicy, Ci.nsIObserver, | 403 QueryInterface: XPCOMUtils.generateQI([Ci.nsIContentPolicy, Ci.nsIObserver, |
402 Ci.nsIChannelEventSink, Ci.nsIFactory, Ci.nsISupportsWeakReference]), | 404 Ci.nsIChannelEventSink, Ci.nsIFactory, Ci.nsISupportsWeakReference]), |
403 | 405 |
404 // | 406 // |
(...skipping 47 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
452 let uri = additional || Utils.makeURI(subject.location.href); | 454 let uri = additional || Utils.makeURI(subject.location.href); |
453 if (!Policy.processNode(subject.opener, subject.opener.document, Policy. type.POPUP, uri, false)) | 455 if (!Policy.processNode(subject.opener, subject.opener.document, Policy. type.POPUP, uri, false)) |
454 { | 456 { |
455 subject.stop(); | 457 subject.stop(); |
456 Utils.runAsync(() => subject.close()); | 458 Utils.runAsync(() => subject.close()); |
457 } | 459 } |
458 else if (uri.spec == "about:blank") | 460 else if (uri.spec == "about:blank") |
459 { | 461 { |
460 // An about:blank pop-up most likely means that a load will be | 462 // An about:blank pop-up most likely means that a load will be |
461 // initiated asynchronously. Wait for that. | 463 // initiated asynchronously. Wait for that. |
462 Utils.runAsync(function() | 464 Utils.runAsync(() => |
463 { | 465 { |
464 let channel = subject.QueryInterface(Ci.nsIInterfaceRequestor) | 466 let channel = subject.QueryInterface(Ci.nsIInterfaceRequestor) |
465 .getInterface(Ci.nsIDocShell) | 467 .getInterface(Ci.nsIDocShell) |
466 .QueryInterface(Ci.nsIDocumentLoader) | 468 .QueryInterface(Ci.nsIDocumentLoader) |
467 .documentChannel; | 469 .documentChannel; |
468 if (channel) | 470 if (channel) |
469 this.observe(subject, topic, data, channel.URI); | 471 this.observe(subject, topic, data, channel.URI); |
470 }); | 472 }); |
471 } | 473 } |
472 break; | 474 break; |
473 } | 475 } |
474 } | 476 } |
475 }, | 477 }, |
476 | 478 |
477 // | 479 // |
478 // nsIChannelEventSink interface implementation | 480 // nsIChannelEventSink interface implementation |
479 // | 481 // |
480 | 482 |
481 asyncOnChannelRedirect: function(oldChannel, newChannel, flags, callback) | 483 asyncOnChannelRedirect: function(oldChannel, newChannel, flags, callback) |
482 { | 484 { |
483 let result = Cr.NS_OK; | 485 let result = Cr.NS_OK; |
484 try | 486 try |
485 { | 487 { |
486 // nsILoadInfo.contentPolicyType was introduced in Gecko 35, then | 488 // nsILoadInfo.contentPolicyType was introduced in Gecko 35, then |
487 // renamed to nsILoadInfo.externalContentPolicyType in Gecko 44. | 489 // renamed to nsILoadInfo.externalContentPolicyType in Gecko 44. |
488 let loadInfo = oldChannel.loadInfo; | 490 let loadInfo = oldChannel.loadInfo; |
489 let contentType = loadInfo.externalContentPolicyType || loadInfo.contentPo licyType; | 491 let contentType = ("externalContentPolicyType" in loadInfo ? |
492 loadInfo.externalContentPolicyType : loadInfo.contentPolicyType); | |
490 if (!contentType) | 493 if (!contentType) |
491 return; | 494 return; |
492 | 495 |
493 let wnd = Utils.getRequestWindow(newChannel); | 496 let wnd = Utils.getRequestWindow(newChannel); |
494 if (!wnd) | 497 if (!wnd) |
495 return; | 498 return; |
496 | 499 |
497 if (contentType == Ci.nsIContentPolicy.TYPE_DOCUMENT) | 500 if (contentType == Ci.nsIContentPolicy.TYPE_DOCUMENT) |
498 { | 501 { |
499 if (wnd.history.length <= 1 && wnd.opener) | 502 if (wnd.history.length <= 1 && wnd.opener) |
500 { | 503 { |
501 // Special treatment for pop-up windows. Note that we might not have | 504 // Special treatment for pop-up windows - this will close the window |
505 // rather than preventing the redirect. Note that we might not have | |
502 // seen the original channel yet because the redirect happened before | 506 // seen the original channel yet because the redirect happened before |
503 // the async code in observe() had a chance to run. | 507 // the async code in observe() had a chance to run. |
504 this.observe(wnd, "content-document-global-created", null, oldChannel. URI); | 508 this.observe(wnd, "content-document-global-created", null, oldChannel. URI); |
505 this.observe(wnd, "content-document-global-created", null, newChannel. URI); | 509 this.observe(wnd, "content-document-global-created", null, newChannel. URI); |
506 } | 510 } |
507 return; | 511 return; |
508 } | 512 } |
509 | 513 |
510 if (!Policy.processNode(wnd, wnd.document, contentType, newChannel.URI, fa lse)) | 514 if (!Policy.processNode(wnd, wnd.document, contentType, newChannel.URI, fa lse)) |
511 result = Cr.NS_BINDING_ABORTED; | 515 result = Cr.NS_BINDING_ABORTED; |
(...skipping 207 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
719 if (!wnd || wnd.closed) | 723 if (!wnd || wnd.closed) |
720 return; | 724 return; |
721 | 725 |
722 if (entry.type == Policy.type.OBJECT) | 726 if (entry.type == Policy.type.OBJECT) |
723 { | 727 { |
724 node.removeEventListener("mouseover", objectMouseEventHander, true); | 728 node.removeEventListener("mouseover", objectMouseEventHander, true); |
725 node.removeEventListener("mouseout", objectMouseEventHander, true); | 729 node.removeEventListener("mouseout", objectMouseEventHander, true); |
726 } | 730 } |
727 Policy.processNode(wnd, node, entry.type, Utils.makeURI(entry.location), true) ; | 731 Policy.processNode(wnd, node, entry.type, Utils.makeURI(entry.location), true) ; |
728 } | 732 } |
LEFT | RIGHT |