| 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-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 |
| (...skipping 53 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 64 * @class | 64 * @class |
| 65 */ | 65 */ |
| 66 let ElemHide = exports.ElemHide = | 66 let ElemHide = exports.ElemHide = |
| 67 { | 67 { |
| 68 /** | 68 /** |
| 69 * Indicates whether filters have been added or removed since the last apply() call. | 69 * Indicates whether filters have been added or removed since the last apply() call. |
| 70 * @type Boolean | 70 * @type Boolean |
| 71 */ | 71 */ |
| 72 isDirty: false, | 72 isDirty: false, |
| 73 | 73 |
| 74 /** | 74 QueryInterface: XPCOMUtils.generateQI([Ci.nsIObserver, Ci.nsISupportsWeakRefer ence]), |
| 75 * Inidicates whether the element hiding stylesheet is currently applied. | |
| 76 * @type Boolean | |
| 77 */ | |
| 78 applied: false, | |
| 79 | 75 |
| 80 /** | 76 /** |
| 81 * Called on module startup. | 77 * Called on module startup. |
| 82 */ | 78 */ |
| 83 init: function() | 79 init: function() |
| 84 { | 80 { |
| 85 TimeLine.enter("Entered ElemHide.init()"); | 81 TimeLine.enter("Entered ElemHide.init()"); |
| 86 Prefs.addListener(function(name) | 82 Prefs.addListener(function(name) |
| 87 { | 83 { |
| 88 if (name == "enabled") | 84 if (name == "enabled") |
| 89 ElemHide.apply(); | 85 ElemHide.apply(); |
| 90 }); | 86 }); |
|
Wladimir Palant
2014/05/20 19:36:12
This code is no longer necessary.
| |
| 91 onShutdown.add(function() | 87 onShutdown.add(function() |
| 92 { | 88 { |
| 93 ElemHide.unapply(); | 89 Services.obs.removeObserver(this, "content-document-global-created"); |
| 94 }); | 90 }.bind(this)); |
| 95 | 91 |
| 96 TimeLine.log("done adding prefs listener"); | 92 TimeLine.log("done adding prefs listener"); |
| 97 | 93 |
| 98 let styleFile = IO.resolveFilePath(Prefs.data_directory); | 94 let styleFile = IO.resolveFilePath(Prefs.data_directory); |
| 99 styleFile.append("elemhide.css"); | 95 styleFile.append("elemhide.css"); |
| 100 styleURL = Services.io.newFileURI(styleFile).QueryInterface(Ci.nsIFileURL); | 96 styleURL = Services.io.newFileURI(styleFile).QueryInterface(Ci.nsIFileURL); |
| 101 TimeLine.log("done determining stylesheet URL"); | 97 TimeLine.log("done determining stylesheet URL"); |
| 102 | 98 |
| 99 Services.obs.addObserver(this, "content-document-global-created", true); | |
| 100 | |
| 103 TimeLine.leave("ElemHide.init() done"); | 101 TimeLine.leave("ElemHide.init() done"); |
| 104 }, | 102 }, |
| 105 | 103 |
| 106 /** | 104 /** |
| 107 * Removes all known filters | 105 * Removes all known filters |
| 108 */ | 106 */ |
| 109 clear: function() | 107 clear: function() |
| 110 { | 108 { |
| 111 filterByKey = {__proto__: null}; | 109 filterByKey = {__proto__: null}; |
| 112 keyByFilter = {__proto__: null}; | 110 keyByFilter = {__proto__: null}; |
| 113 knownExceptions = {__proto__: null}; | 111 knownExceptions = {__proto__: null}; |
| 114 exceptions = {__proto__: null}; | 112 exceptions = {__proto__: null}; |
| 115 ElemHide.isDirty = false; | 113 ElemHide.isDirty = false; |
| 116 ElemHide.unapply(); | 114 }, |
| 115 | |
| 116 observe: function (subject, topic, data, additional) | |
| 117 { | |
| 118 if (topic != "content-document-global-created") | |
| 119 return; | |
| 120 | |
| 121 if (!Prefs.enabled) | |
| 122 return; | |
| 123 | |
| 124 let uri = subject.document.documentURIObject; | |
| 125 if (!uri) | |
| 126 return; | |
| 127 | |
| 128 switch(uri.scheme) | |
| 129 { | |
| 130 case "http": | |
| 131 case "https": | |
| 132 case "mailbox": | |
| 133 case "imap": | |
| 134 case "news": | |
| 135 case "snews": | |
| 136 break; | |
| 137 default: | |
| 138 // Avoid injecting in chrome documents | |
| 139 return; | |
| 140 } | |
|
Wladimir Palant
2014/05/20 19:36:12
Please use Policy.isBlockableScheme() here (from c
| |
| 141 | |
| 142 // XXX is there some better way to test if it's disabled on that domain that we should do before? | |
| 143 if (!ElemHide.anySelectorForDomain(uri.host)) | |
| 144 return; | |
|
Wladimir Palant
2014/05/20 19:36:12
Wow, performance will go down the drain here. We c
| |
| 145 | |
| 146 var windowUtils = subject.QueryInterface(Ci.nsIInterfaceRequestor).getInterf ace(Ci.nsIDOMWindowUtils); | |
| 147 windowUtils.loadSheet(styleURL, Ci.nsIStyleSheetService.USER_SHEET); | |
| 117 }, | 148 }, |
| 118 | 149 |
| 119 /** | 150 /** |
| 120 * Add a new element hiding filter | 151 * Add a new element hiding filter |
| 121 * @param {ElemHideFilter} filter | 152 * @param {ElemHideFilter} filter |
| 122 */ | 153 */ |
| 123 add: function(filter) | 154 add: function(filter) |
| 124 { | 155 { |
| 125 if (filter instanceof ElemHideException) | 156 if (filter instanceof ElemHideException) |
| 126 { | 157 { |
| (...skipping 76 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 203 _applying: false, | 234 _applying: false, |
| 204 | 235 |
| 205 /** | 236 /** |
| 206 * Will be set to true if an apply() call arrives while apply() is already | 237 * Will be set to true if an apply() call arrives while apply() is already |
| 207 * running (delayed execution). | 238 * running (delayed execution). |
| 208 * @type Boolean | 239 * @type Boolean |
| 209 */ | 240 */ |
| 210 _needsApply: false, | 241 _needsApply: false, |
| 211 | 242 |
| 212 /** | 243 /** |
| 213 * Generates stylesheet URL and applies it globally | 244 * Generates stylesheet URL. |
| 214 */ | 245 */ |
| 246 // XXX Rename | |
| 215 apply: function() | 247 apply: function() |
|
Wladimir Palant
2014/05/20 19:36:12
saveStylesheet()?
| |
| 216 { | 248 { |
| 217 if (this._applying) | 249 if (this._applying) |
| 218 { | 250 { |
| 219 this._needsApply = true; | 251 this._needsApply = true; |
| 220 return; | 252 return; |
| 221 } | 253 } |
| 222 | 254 |
| 223 TimeLine.enter("Entered ElemHide.apply()"); | 255 TimeLine.enter("Entered ElemHide.apply()"); |
| 224 | 256 |
| 225 if (!ElemHide.isDirty || !Prefs.enabled) | |
| 226 { | |
| 227 // Nothing changed, looks like we merely got enabled/disabled | |
| 228 if (Prefs.enabled && !ElemHide.applied) | |
| 229 { | |
| 230 try | |
| 231 { | |
| 232 Utils.styleService.loadAndRegisterSheet(styleURL, Ci.nsIStyleSheetServ ice.USER_SHEET); | |
| 233 ElemHide.applied = true; | |
| 234 } | |
| 235 catch (e) | |
| 236 { | |
| 237 Cu.reportError(e); | |
| 238 } | |
| 239 TimeLine.log("Applying existing stylesheet finished"); | |
| 240 } | |
| 241 else if (!Prefs.enabled && ElemHide.applied) | |
| 242 { | |
| 243 ElemHide.unapply(); | |
| 244 TimeLine.log("ElemHide.unapply() finished"); | |
| 245 } | |
| 246 | |
| 247 TimeLine.leave("ElemHide.apply() done (no file changes)"); | |
| 248 return; | |
| 249 } | |
| 250 | |
| 251 IO.writeToFile(styleURL.file, this._generateCSSContent(), function(e) | 257 IO.writeToFile(styleURL.file, this._generateCSSContent(), function(e) |
| 252 { | 258 { |
| 253 TimeLine.enter("ElemHide.apply() write callback"); | 259 TimeLine.enter("ElemHide.apply() write callback"); |
| 254 this._applying = false; | 260 this._applying = false; |
| 255 | 261 |
| 256 // _generateCSSContent is throwing NS_ERROR_NOT_AVAILABLE to indicate that | 262 // _generateCSSContent is throwing NS_ERROR_NOT_AVAILABLE to indicate that |
| 257 // there are no filters. If that exception is passed through XPCOM we will | 263 // there are no filters. If that exception is passed through XPCOM we will |
| 258 // see a proper exception here, otherwise a number. | 264 // see a proper exception here, otherwise a number. |
| 259 let noFilters = (e == Cr.NS_ERROR_NOT_AVAILABLE || (e && e.result == Cr.NS _ERROR_NOT_AVAILABLE)); | 265 let noFilters = (e == Cr.NS_ERROR_NOT_AVAILABLE || (e && e.result == Cr.NS _ERROR_NOT_AVAILABLE)); |
| 260 if (noFilters) | 266 if (noFilters) |
| 261 { | 267 { |
| 262 e = null; | 268 e = null; |
| 263 IO.removeFile(styleURL.file, function(e) {}); | 269 IO.removeFile(styleURL.file, function(e) {}); |
| 264 } | 270 } |
| 265 else if (e) | 271 else if (e) |
| 266 Cu.reportError(e); | 272 Cu.reportError(e); |
| 267 | 273 |
| 268 if (this._needsApply) | 274 if (this._needsApply) |
| 269 { | 275 { |
| 270 this._needsApply = false; | 276 this._needsApply = false; |
| 271 this.apply(); | 277 this.apply(); |
| 272 } | 278 } |
| 273 else if (!e) | 279 else if (!e) |
| 274 { | 280 { |
| 275 ElemHide.isDirty = false; | 281 ElemHide.isDirty = false; |
| 276 | 282 |
| 277 ElemHide.unapply(); | |
| 278 TimeLine.log("ElemHide.unapply() finished"); | |
| 279 | |
| 280 if (!noFilters) | |
| 281 { | |
| 282 try | |
| 283 { | |
| 284 Utils.styleService.loadAndRegisterSheet(styleURL, Ci.nsIStyleSheetSe rvice.USER_SHEET); | |
| 285 ElemHide.applied = true; | |
| 286 } | |
| 287 catch (e) | |
| 288 { | |
| 289 Cu.reportError(e); | |
| 290 } | |
| 291 TimeLine.log("Applying stylesheet finished"); | |
| 292 } | |
| 293 | |
| 294 FilterNotifier.triggerListeners("elemhideupdate"); | 283 FilterNotifier.triggerListeners("elemhideupdate"); |
|
Wladimir Palant
2014/05/20 19:36:12
Apparently, this is dead code. This notification h
| |
| 295 } | 284 } |
| 296 TimeLine.leave("ElemHide.apply() write callback done"); | 285 TimeLine.leave("ElemHide.apply() write callback done"); |
| 297 }.bind(this), "ElemHideWrite"); | 286 }.bind(this), "ElemHideWrite"); |
| 298 | 287 |
| 299 this._applying = true; | 288 this._applying = true; |
| 300 | 289 |
| 301 TimeLine.leave("ElemHide.apply() done", "ElemHideWrite"); | 290 TimeLine.leave("ElemHide.apply() done", "ElemHideWrite"); |
| 302 }, | 291 }, |
| 303 | 292 |
| 304 _generateCSSContent: function() | 293 _generateCSSContent: function() |
| (...skipping 49 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 354 yield selector.replace(/[^\x01-\x7F]/g, escapeChar) + "{" + cssTemplate. replace("%ID%", list[selector]) + "}"; | 343 yield selector.replace(/[^\x01-\x7F]/g, escapeChar) + "{" + cssTemplate. replace("%ID%", list[selector]) + "}"; |
| 355 yield '}'; | 344 yield '}'; |
| 356 } | 345 } |
| 357 }, | 346 }, |
| 358 | 347 |
| 359 /** | 348 /** |
| 360 * Unapplies current stylesheet URL | 349 * Unapplies current stylesheet URL |
| 361 */ | 350 */ |
| 362 unapply: function() | 351 unapply: function() |
| 363 { | 352 { |
| 364 if (ElemHide.applied) | |
| 365 { | |
| 366 try | |
| 367 { | |
| 368 Utils.styleService.unregisterSheet(styleURL, Ci.nsIStyleSheetService.USE R_SHEET); | |
| 369 } | |
| 370 catch (e) | |
| 371 { | |
| 372 Cu.reportError(e); | |
| 373 } | |
| 374 ElemHide.applied = false; | |
| 375 } | |
| 376 }, | 353 }, |
|
Wladimir Palant
2014/05/20 19:36:12
This function should be removed.
| |
| 377 | 354 |
| 378 /** | 355 /** |
| 379 * Retrieves the currently applied stylesheet URL | 356 * Retrieves the currently applied stylesheet URL |
| 380 * @type String | 357 * @type String |
| 381 */ | 358 */ |
| 382 get styleURL() ElemHide.applied ? styleURL.spec : null, | 359 get styleURL() styleURL.spec, |
|
Wladimir Palant
2014/05/20 19:36:12
This getter was also introduced in https://hg.adbl
| |
| 383 | 360 |
| 384 /** | 361 /** |
| 385 * Retrieves an element hiding filter by the corresponding protocol key | 362 * Retrieves an element hiding filter by the corresponding protocol key |
| 386 */ | 363 */ |
| 387 getFilterByKey: function(/**String*/ key) /**Filter*/ | 364 getFilterByKey: function(/**String*/ key) /**Filter*/ |
| 388 { | 365 { |
| 389 return (key in filterByKey ? filterByKey[key] : null); | 366 return (key in filterByKey ? filterByKey[key] : null); |
| 390 }, | 367 }, |
| 391 | 368 |
| 392 /** | 369 /** |
| (...skipping 12 matching lines...) Expand all Loading... | |
| 405 // workaround WebKit bug 132872, also see #419 | 382 // workaround WebKit bug 132872, also see #419 |
| 406 let domains = filter.domains; | 383 let domains = filter.domains; |
| 407 | 384 |
| 408 if (specificOnly && (!domains || domains[""])) | 385 if (specificOnly && (!domains || domains[""])) |
| 409 continue; | 386 continue; |
| 410 | 387 |
| 411 if (filter.isActiveOnDomain(domain) && !this.getException(filter, domain)) | 388 if (filter.isActiveOnDomain(domain) && !this.getException(filter, domain)) |
| 412 result.push(filter.selector); | 389 result.push(filter.selector); |
| 413 } | 390 } |
| 414 return result; | 391 return result; |
| 392 }, | |
| 393 | |
| 394 anySelectorForDomain: function(/**String*/ domain) | |
| 395 { | |
| 396 for (let key in filterByKey) | |
| 397 { | |
| 398 let filter = filterByKey[key]; | |
| 399 | |
| 400 if (filter.isActiveOnDomain(domain) && !this.getException(filter, domain)) | |
| 401 return true; | |
| 402 } | |
| 403 | |
| 404 return false; | |
| 415 } | 405 } |
| 416 }; | 406 }; |
| OLD | NEW |