| Index: lib/elemHide.js | 
| =================================================================== | 
| deleted file mode 100644 | 
| --- a/lib/elemHide.js | 
| +++ /dev/null | 
| @@ -1,389 +0,0 @@ | 
| -/* | 
| - * This file is part of Adblock Plus <https://adblockplus.org/>, | 
| - * Copyright (C) 2006-2016 Eyeo GmbH | 
| - * | 
| - * Adblock Plus is free software: you can redistribute it and/or modify | 
| - * it under the terms of the GNU General Public License version 3 as | 
| - * published by the Free Software Foundation. | 
| - * | 
| - * Adblock Plus is distributed in the hope that it will be useful, | 
| - * but WITHOUT ANY WARRANTY; without even the implied warranty of | 
| - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the | 
| - * GNU General Public License for more details. | 
| - * | 
| - * You should have received a copy of the GNU General Public License | 
| - * along with Adblock Plus.  If not, see <http://www.gnu.org/licenses/>. | 
| - */ | 
| - | 
| -/** | 
| - * @fileOverview Element hiding implementation. | 
| - */ | 
| - | 
| -Cu.import("resource://gre/modules/Services.jsm"); | 
| - | 
| -var {Utils} = require("utils"); | 
| -var {IO} = require("io"); | 
| -var {Prefs} = require("prefs"); | 
| -var {ElemHideException} = require("filterClasses"); | 
| -var {FilterNotifier} = require("filterNotifier"); | 
| - | 
| -/** | 
| - * Lookup table, filters by their associated key | 
| - * @type Object | 
| - */ | 
| -var filterByKey = Object.create(null); | 
| - | 
| -/** | 
| - * Lookup table, keys of the filters by filter text | 
| - * @type Object | 
| - */ | 
| -var keyByFilter = Object.create(null); | 
| - | 
| -/** | 
| - * Lookup table, keys are known element hiding exceptions | 
| - * @type Object | 
| - */ | 
| -var knownExceptions = Object.create(null); | 
| - | 
| -/** | 
| - * Lookup table, lists of element hiding exceptions by selector | 
| - * @type Object | 
| - */ | 
| -var exceptions = Object.create(null); | 
| - | 
| -/** | 
| - * Currently applied stylesheet URL | 
| - * @type nsIURI | 
| - */ | 
| -var styleURL = null; | 
| - | 
| -/** | 
| - * Element hiding component | 
| - * @class | 
| - */ | 
| -var ElemHide = exports.ElemHide = | 
| -{ | 
| -  /** | 
| -   * Indicates whether filters have been added or removed since the last apply() call. | 
| -   * @type Boolean | 
| -   */ | 
| -  isDirty: false, | 
| - | 
| -  /** | 
| -   * Inidicates whether the element hiding stylesheet is currently applied. | 
| -   * @type Boolean | 
| -   */ | 
| -  applied: false, | 
| - | 
| -  /** | 
| -   * Called on module startup. | 
| -   */ | 
| -  init: function() | 
| -  { | 
| -    Prefs.addListener(function(name) | 
| -    { | 
| -      if (name == "enabled") | 
| -        ElemHide.apply(); | 
| -    }); | 
| -    onShutdown.add(() => ElemHide.unapply()); | 
| - | 
| -    let styleFile = IO.resolveFilePath(Prefs.data_directory); | 
| -    styleFile.append("elemhide.css"); | 
| -    styleURL = Services.io.newFileURI(styleFile).QueryInterface(Ci.nsIFileURL); | 
| -  }, | 
| - | 
| -  /** | 
| -   * Removes all known filters | 
| -   */ | 
| -  clear: function() | 
| -  { | 
| -    filterByKey = Object.create(null); | 
| -    keyByFilter = Object.create(null); | 
| -    knownExceptions = Object.create(null); | 
| -    exceptions = Object.create(null); | 
| -    ElemHide.isDirty = false; | 
| -    ElemHide.unapply(); | 
| -  }, | 
| - | 
| -  /** | 
| -   * Add a new element hiding filter | 
| -   * @param {ElemHideFilter} filter | 
| -   */ | 
| -  add: function(filter) | 
| -  { | 
| -    if (filter instanceof ElemHideException) | 
| -    { | 
| -      if (filter.text in knownExceptions) | 
| -        return; | 
| - | 
| -      let selector = filter.selector; | 
| -      if (!(selector in exceptions)) | 
| -        exceptions[selector] = []; | 
| -      exceptions[selector].push(filter); | 
| -      knownExceptions[filter.text] = true; | 
| -    } | 
| -    else | 
| -    { | 
| -      if (filter.text in keyByFilter) | 
| -        return; | 
| - | 
| -      let key; | 
| -      do { | 
| -        key = Math.random().toFixed(15).substr(5); | 
| -      } while (key in filterByKey); | 
| - | 
| -      filterByKey[key] = filter; | 
| -      keyByFilter[filter.text] = key; | 
| -      ElemHide.isDirty = true; | 
| -    } | 
| -  }, | 
| - | 
| -  /** | 
| -   * Removes an element hiding filter | 
| -   * @param {ElemHideFilter} filter | 
| -   */ | 
| -  remove: function(filter) | 
| -  { | 
| -    if (filter instanceof ElemHideException) | 
| -    { | 
| -      if (!(filter.text in knownExceptions)) | 
| -        return; | 
| - | 
| -      let list = exceptions[filter.selector]; | 
| -      let index = list.indexOf(filter); | 
| -      if (index >= 0) | 
| -        list.splice(index, 1); | 
| -      delete knownExceptions[filter.text]; | 
| -    } | 
| -    else | 
| -    { | 
| -      if (!(filter.text in keyByFilter)) | 
| -        return; | 
| - | 
| -      let key = keyByFilter[filter.text]; | 
| -      delete filterByKey[key]; | 
| -      delete keyByFilter[filter.text]; | 
| -      ElemHide.isDirty = true; | 
| -    } | 
| -  }, | 
| - | 
| -  /** | 
| -   * Checks whether an exception rule is registered for a filter on a particular | 
| -   * domain. | 
| -   */ | 
| -  getException: function(/**Filter*/ filter, /**String*/ docDomain) /**ElemHideException*/ | 
| -  { | 
| -    if (!(filter.selector in exceptions)) | 
| -      return null; | 
| - | 
| -    let list = exceptions[filter.selector]; | 
| -    for (let i = list.length - 1; i >= 0; i--) | 
| -      if (list[i].isActiveOnDomain(docDomain)) | 
| -        return list[i]; | 
| - | 
| -    return null; | 
| -  }, | 
| - | 
| -  /** | 
| -   * Will be set to true if apply() is running (reentrance protection). | 
| -   * @type Boolean | 
| -   */ | 
| -  _applying: false, | 
| - | 
| -  /** | 
| -   * Will be set to true if an apply() call arrives while apply() is already | 
| -   * running (delayed execution). | 
| -   * @type Boolean | 
| -   */ | 
| -  _needsApply: false, | 
| - | 
| -  /** | 
| -   * Generates stylesheet URL and applies it globally | 
| -   */ | 
| -  apply: function() | 
| -  { | 
| -    if (this._applying) | 
| -    { | 
| -      this._needsApply = true; | 
| -      return; | 
| -    } | 
| - | 
| -    if (!ElemHide.isDirty || !Prefs.enabled) | 
| -    { | 
| -      // Nothing changed, looks like we merely got enabled/disabled | 
| -      if (Prefs.enabled && !ElemHide.applied) | 
| -      { | 
| -        try | 
| -        { | 
| -          Utils.styleService.loadAndRegisterSheet(styleURL, Ci.nsIStyleSheetService.USER_SHEET); | 
| -          ElemHide.applied = true; | 
| -        } | 
| -        catch (e) | 
| -        { | 
| -          Cu.reportError(e); | 
| -        } | 
| -      } | 
| -      else if (!Prefs.enabled && ElemHide.applied) | 
| -      { | 
| -        ElemHide.unapply(); | 
| -      } | 
| - | 
| -      return; | 
| -    } | 
| - | 
| -    IO.writeToFile(styleURL.file, this._generateCSSContent(), function(e) | 
| -    { | 
| -      this._applying = false; | 
| - | 
| -      // _generateCSSContent is throwing NS_ERROR_NOT_AVAILABLE to indicate that | 
| -      // there are no filters. If that exception is passed through XPCOM we will | 
| -      // see a proper exception here, otherwise a number. | 
| -      let noFilters = (e == Cr.NS_ERROR_NOT_AVAILABLE || (e && e.result == Cr.NS_ERROR_NOT_AVAILABLE)); | 
| -      if (noFilters) | 
| -      { | 
| -        e = null; | 
| -        IO.removeFile(styleURL.file, function(e) {}); | 
| -      } | 
| -      else if (e) | 
| -        Cu.reportError(e); | 
| - | 
| -      if (this._needsApply) | 
| -      { | 
| -        this._needsApply = false; | 
| -        this.apply(); | 
| -      } | 
| -      else if (!e) | 
| -      { | 
| -        ElemHide.isDirty = false; | 
| - | 
| -        ElemHide.unapply(); | 
| - | 
| -        if (!noFilters) | 
| -        { | 
| -          try | 
| -          { | 
| -            Utils.styleService.loadAndRegisterSheet(styleURL, Ci.nsIStyleSheetService.USER_SHEET); | 
| -            ElemHide.applied = true; | 
| -          } | 
| -          catch (e) | 
| -          { | 
| -            Cu.reportError(e); | 
| -          } | 
| -        } | 
| - | 
| -        FilterNotifier.triggerListeners("elemhideupdate"); | 
| -      } | 
| -    }.bind(this)); | 
| - | 
| -    this._applying = true; | 
| -  }, | 
| - | 
| -  _generateCSSContent: function*() | 
| -  { | 
| -    // Grouping selectors by domains | 
| -    let domains = Object.create(null); | 
| -    let hasFilters = false; | 
| -    for (let key in filterByKey) | 
| -    { | 
| -      let filter = filterByKey[key]; | 
| -      let domain = filter.selectorDomain || ""; | 
| - | 
| -      let list; | 
| -      if (domain in domains) | 
| -        list = domains[domain]; | 
| -      else | 
| -      { | 
| -        list = Object.create(null); | 
| -        domains[domain] = list; | 
| -      } | 
| -      list[filter.selector] = key; | 
| -      hasFilters = true; | 
| -    } | 
| - | 
| -    if (!hasFilters) | 
| -      throw Cr.NS_ERROR_NOT_AVAILABLE; | 
| - | 
| -    function escapeChar(match) | 
| -    { | 
| -      return "\\" + match.charCodeAt(0).toString(16) + " "; | 
| -    } | 
| - | 
| -    // Return CSS data | 
| -    let cssTemplate = "-moz-binding: url(about:abp-elemhidehit?%ID%#dummy) !important;"; | 
| -    for (let domain in domains) | 
| -    { | 
| -      let rules = []; | 
| -      let list = domains[domain]; | 
| - | 
| -      if (domain) | 
| -        yield ('@-moz-document domain("' + domain.split(",").join('"),domain("') + '"){').replace(/[^\x01-\x7F]/g, escapeChar); | 
| -      else | 
| -      { | 
| -        // Only allow unqualified rules on a few protocols to prevent them from blocking chrome | 
| -        yield '@-moz-document url-prefix("http://"),url-prefix("https://"),' | 
| -                  + 'url-prefix("mailbox://"),url-prefix("imap://"),' | 
| -                  + 'url-prefix("news://"),url-prefix("snews://"){'; | 
| -      } | 
| - | 
| -      for (let selector in list) | 
| -        yield selector.replace(/[^\x01-\x7F]/g, escapeChar) + "{" + cssTemplate.replace("%ID%", list[selector]) + "}"; | 
| -      yield '}'; | 
| -    } | 
| -  }, | 
| - | 
| -  /** | 
| -   * Unapplies current stylesheet URL | 
| -   */ | 
| -  unapply: function() | 
| -  { | 
| -    if (ElemHide.applied) | 
| -    { | 
| -      try | 
| -      { | 
| -        Utils.styleService.unregisterSheet(styleURL, Ci.nsIStyleSheetService.USER_SHEET); | 
| -      } | 
| -      catch (e) | 
| -      { | 
| -        Cu.reportError(e); | 
| -      } | 
| -      ElemHide.applied = false; | 
| -    } | 
| -  }, | 
| - | 
| -  /** | 
| -   * Retrieves the currently applied stylesheet URL | 
| -   * @type String | 
| -   */ | 
| -  get styleURL() | 
| -  { | 
| -    return ElemHide.applied ? styleURL.spec : null; | 
| -  }, | 
| - | 
| -  /** | 
| -   * Retrieves an element hiding filter by the corresponding protocol key | 
| -   */ | 
| -  getFilterByKey: function(/**String*/ key) /**Filter*/ | 
| -  { | 
| -    return (key in filterByKey ? filterByKey[key] : null); | 
| -  }, | 
| - | 
| -  /** | 
| -   * Returns a list of all selectors active on a particular domain (currently | 
| -   * used only in Chrome, Opera and Safari). | 
| -   */ | 
| -  getSelectorsForDomain: function(/**String*/ domain, /**Boolean*/ specificOnly) | 
| -  { | 
| -    let result = []; | 
| -    let keys = Object.getOwnPropertyNames(filterByKey); | 
| -    for (let key of keys) | 
| -    { | 
| -      let filter = filterByKey[key]; | 
| -      if (specificOnly && (!filter.domains || filter.domains[""])) | 
| -        continue; | 
| - | 
| -      if (filter.isActiveOnDomain(domain) && !this.getException(filter, domain)) | 
| -        result.push(filter.selector); | 
| -    } | 
| -    return result; | 
| -  } | 
| -}; | 
|  |