| Index: lib/elemHideExceptions.js | 
| =================================================================== | 
| new file mode 100644 | 
| --- /dev/null | 
| +++ b/lib/elemHideExceptions.js | 
| @@ -0,0 +1,130 @@ | 
| +/* | 
| + * This file is part of Adblock Plus <https://adblockplus.org/>, | 
| + * Copyright (C) 2006-present 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/>. | 
| + */ | 
| + | 
| +"use strict"; | 
| + | 
| +/** | 
| + * @fileOverview Element hiding exceptions implementation. | 
| + */ | 
| + | 
| +const {EventEmitter} = require("./events"); | 
| +const {FilterNotifier} = require("./filterNotifier"); | 
| + | 
| +/** | 
| + * Lookup table, lists of element hiding exceptions by selector | 
| + * @type {Map.<string,ElemHideException[]>} | 
| + */ | 
| +let exceptions = new Map(); | 
| + | 
| +/** | 
| + * Set containing known element exceptions | 
| + * @type {Set.<ElemHideException>} | 
| + */ | 
| +let knownExceptions = new Set(); | 
| + | 
| +/** | 
| + * Container for element hiding exceptions | 
| + * @class | 
| + */ | 
| +exports.ElemHideExceptions = Object.assign(Object.create(new EventEmitter()), { | 
| +  /** | 
| +   * Removes all known exceptions | 
| +   */ | 
| +  clear() | 
| +  { | 
| +    exceptions.clear(); | 
| +    knownExceptions.clear(); | 
| + | 
| +    FilterNotifier.emit("elemhideupdate"); | 
| +  }, | 
| + | 
| +  /** | 
| +   * Add a new element hiding exception | 
| +   * @param {ElemHideException} exception | 
| +   */ | 
| +  add(exception) | 
| +  { | 
| +    if (knownExceptions.has(exception)) | 
| +      return; | 
| + | 
| +    let {selector} = exception; | 
| +    let list = exceptions.get(selector); | 
| +    if (list) | 
| +      list.push(exception); | 
| +    else | 
| +      exceptions.set(selector, [exception]); | 
| + | 
| +    knownExceptions.add(exception); | 
| + | 
| +    this.emit("added", exception); | 
| + | 
| +    FilterNotifier.emit("elemhideupdate"); | 
| +  }, | 
| + | 
| +  /** | 
| +   * Removes an element hiding exception | 
| +   * @param {ElemHideException} exception | 
| +   */ | 
| +  remove(exception) | 
| +  { | 
| +    if (!knownExceptions.has(exception)) | 
| +      return; | 
| + | 
| +    let list = exceptions.get(exception.selector); | 
| +    let index = list.indexOf(exception); | 
| +    if (index >= 0) | 
| +      list.splice(index, 1); | 
| + | 
| +    knownExceptions.delete(exception); | 
| + | 
| +    this.emit("removed", exception); | 
| + | 
| +    FilterNotifier.emit("elemhideupdate"); | 
| +  }, | 
| + | 
| +  /** | 
| +   * Checks whether any exception rules are registered for a selector | 
| +   * @param {string} selector | 
| +   * @returns {boolean} | 
| +   */ | 
| +  hasExceptions(selector) | 
| +  { | 
| +    return exceptions.has(selector); | 
| +  }, | 
| + | 
| +  /** | 
| +   * Checks whether an exception rule is registered for a selector on a | 
| +   * particular domain. | 
| +   * @param {string} selector | 
| +   * @param {?string} docDomain | 
| +   * @return {?ElemHideException} | 
| +   */ | 
| +  getException(selector, docDomain) | 
| +  { | 
| +    let list = exceptions.get(selector); | 
| +    if (!list) | 
| +      return null; | 
| + | 
| +    for (let i = list.length - 1; i >= 0; i--) | 
| +    { | 
| +      if (list[i].isActiveOnDomain(docDomain)) | 
| +        return list[i]; | 
| +    } | 
| + | 
| +    return null; | 
| +  } | 
| +}); | 
|  |