| OLD | NEW | 
|---|
| (Empty) |  | 
|  | 1 /* | 
|  | 2  * This file is part of Adblock Plus <https://adblockplus.org/>, | 
|  | 3  * Copyright (C) 2006-2015 Eyeo GmbH | 
|  | 4  * | 
|  | 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 | 
|  | 7  * published by the Free Software Foundation. | 
|  | 8  * | 
|  | 9  * Adblock Plus is distributed in the hope that it will be useful, | 
|  | 10  * but WITHOUT ANY WARRANTY; without even the implied warranty of | 
|  | 11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the | 
|  | 12  * GNU General Public License for more details. | 
|  | 13  * | 
|  | 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/>. | 
|  | 16  */ | 
|  | 17 | 
|  | 18 let {getDecodedHostname, stringifyURL} = require("url"); | 
|  | 19 | 
|  | 20 function escapeChar(chr) | 
|  | 21 { | 
|  | 22   let code = chr.charCodeAt(0); | 
|  | 23 | 
|  | 24   // Control characters and leading digits must be escaped based on | 
|  | 25   // their char code in CSS. Moreover, curly brackets aren't allowed | 
|  | 26   // in elemhide filters, and therefore must be escaped based on their | 
|  | 27   // char code as well. | 
|  | 28   if (code <= 0x1F || code == 0x7F || /[\d\{\}]/.test(chr)) | 
|  | 29     return "\\" + code.toString(16) + " "; | 
|  | 30 | 
|  | 31   return "\\" + chr; | 
|  | 32 } | 
|  | 33 | 
|  | 34 /** | 
|  | 35  * Escapes a token (e.g. tag, id, class or attribute) to be used in CSS selector
     s. | 
|  | 36  * | 
|  | 37  * @param {string} [s] | 
|  | 38  * @return {string} | 
|  | 39  */ | 
|  | 40 function escapeCSS(s) | 
|  | 41 { | 
|  | 42   return s.replace(/^[\d\-]|[^\w\-\u0080-\uFFFF]/g, escapeChar); | 
|  | 43 } | 
|  | 44 exports.escapeCSS = escapeCSS; | 
|  | 45 | 
|  | 46 /** | 
|  | 47  * Quotes a string to be used as attribute value in CSS selectors. | 
|  | 48  * | 
|  | 49  * @param {string} [value] | 
|  | 50  * @return {string} | 
|  | 51  */ | 
|  | 52 function quoteCSS(value) | 
|  | 53 { | 
|  | 54   return '"' + value.replace(/["\\\{\}\x00-\x1F\x7F]/g, escapeChar) + '"'; | 
|  | 55 } | 
|  | 56 exports.quoteCSS = quoteCSS; | 
|  | 57 | 
|  | 58 function canBlockURL(url) | 
|  | 59 { | 
|  | 60   return url.protocol == "http:" || url.protocol == "https:"; | 
|  | 61 } | 
|  | 62 | 
|  | 63 /** | 
|  | 64  * Generates filters to block an element. | 
|  | 65  * | 
|  | 66  * @param {string}   [tagName] The element's tag name | 
|  | 67  * @param {string}   [src]     The element's "src" attribute (can be null) | 
|  | 68  * @param {string}   [id]      The element's "id" attribute (can be null) | 
|  | 69  * @param {string}   [style]   The element's "style" attribute (can be null) | 
|  | 70  * @param {string[]} [classes] The classes given by the element's "class" attrib
     ute | 
|  | 71  * @param {string[]} [urls]    The URLs considered when loading the element | 
|  | 72  * @param {URL}      [baseURL] The URL of the document containing the element | 
|  | 73  * | 
|  | 74  * @return {object} An object holding the list of generated filters and | 
|  | 75  *                  the list of CSS selectors for the included element | 
|  | 76  *                  hiding filters: {filters: [...], selectors: [...]} | 
|  | 77  */ | 
|  | 78 function composeFilters(tagName, id, src, style, classes, urls, baseURL) | 
|  | 79 { | 
|  | 80   // Add a blocking filter for each HTTP(S) URL associated with the element | 
|  | 81   let filters = []; | 
|  | 82   for (let url of urls) | 
|  | 83   { | 
|  | 84     let urlObj = new URL(url, baseURL); | 
|  | 85     if (canBlockURL(urlObj)) | 
|  | 86     { | 
|  | 87       let filter = stringifyURL(urlObj).replace(/^[\w\-]+:\/+(?:www\.)?/, "||"); | 
|  | 88 | 
|  | 89       if (filters.indexOf(filter) == -1) | 
|  | 90         filters.push(filter); | 
|  | 91     } | 
|  | 92   } | 
|  | 93 | 
|  | 94   // Generate CSS selectors based on the element's "id" and "class" attribute | 
|  | 95   let selectors = []; | 
|  | 96   if (id) | 
|  | 97     selectors.push("#" + escapeCSS(id)); | 
|  | 98   if (classes.length > 0) | 
|  | 99     selectors.push(classes.map(c => "." + escapeCSS(c)).join("")); | 
|  | 100 | 
|  | 101   // If there is a "src" attribute, specifiying a URL that we can't block, | 
|  | 102   // generate a CSS selector matching the "src" attribute | 
|  | 103   if (src && !canBlockURL(new URL(src, baseURL))) | 
|  | 104     selectors.push(escapeCSS(tagName) + "[src=" + quoteCSS(src) + "]"); | 
|  | 105 | 
|  | 106   // As last resort, if there is a "style" attribute, and we couldn't generate | 
|  | 107   // any filters so far, generate a CSS selector matching the "style" attribute | 
|  | 108   if (style && selectors.length == 0 && filters.length == 0) | 
|  | 109     selectors.push(escapeCSS(tagName) + "[style=" + quoteCSS(style) + "]"); | 
|  | 110 | 
|  | 111   // Add an element hiding filter for each generated CSS selector | 
|  | 112   if (selectors.length > 0) | 
|  | 113   { | 
|  | 114     let domain = getDecodedHostname(baseURL).replace(/^www\./, ""); | 
|  | 115 | 
|  | 116     for (let selector of selectors) | 
|  | 117       filters.push(domain + "##" + selector); | 
|  | 118   } | 
|  | 119 | 
|  | 120   return {filters: filters, selectors: selectors}; | 
|  | 121 } | 
|  | 122 exports.composeFilters = composeFilters; | 
| OLD | NEW | 
|---|