| OLD | NEW |
| 1 // We are currently limited to ECMAScript 5 in this file, because it is being | 1 /* |
| 2 // used in the browser tests. See https://issues.adblockplus.org/ticket/4796 | 2 * This file is part of Adblock Plus <https://adblockplus.org/>, |
| 3 * Copyright (C) 2006-2017 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 */ |
| 3 | 17 |
| 4 var propertySelectorRegExp = /\[\-abp\-properties=(["'])([^"']+)\1\]/; | 18 /* globals filterToRegExp */ |
| 19 |
| 20 "use strict"; |
| 21 |
| 22 let propertySelectorRegExp = /\[-abp-properties=(["'])([^"']+)\1\]/; |
| 5 | 23 |
| 6 function splitSelector(selector) | 24 function splitSelector(selector) |
| 7 { | 25 { |
| 8 if (selector.indexOf(",") == -1) | 26 if (selector.indexOf(",") == -1) |
| 9 return [selector]; | 27 return [selector]; |
| 10 | 28 |
| 11 var selectors = []; | 29 let selectors = []; |
| 12 var start = 0; | 30 let start = 0; |
| 13 var level = 0; | 31 let level = 0; |
| 14 var sep = ""; | 32 let sep = ""; |
| 15 | 33 |
| 16 for (var i = 0; i < selector.length; i++) | 34 for (let i = 0; i < selector.length; i++) |
| 17 { | 35 { |
| 18 var chr = selector[i]; | 36 let chr = selector[i]; |
| 19 | 37 |
| 20 if (chr == "\\") // ignore escaped characters | 38 if (chr == "\\") // ignore escaped characters |
| 21 i++; | 39 i++; |
| 22 else if (chr == sep) // don't split within quoted text | 40 else if (chr == sep) // don't split within quoted text |
| 23 sep = ""; // e.g. [attr=","] | 41 sep = ""; // e.g. [attr=","] |
| 24 else if (sep == "") | 42 else if (sep == "") |
| 25 { | 43 { |
| 26 if (chr == '"' || chr == "'") | 44 if (chr == '"' || chr == "'") |
| 27 sep = chr; | 45 sep = chr; |
| 28 else if (chr == "(") // don't split between parentheses | 46 else if (chr == "(") // don't split between parentheses |
| (...skipping 13 matching lines...) Expand all Loading... |
| 42 } | 60 } |
| 43 | 61 |
| 44 function ElemHideEmulation(window, getFiltersFunc, addSelectorsFunc) | 62 function ElemHideEmulation(window, getFiltersFunc, addSelectorsFunc) |
| 45 { | 63 { |
| 46 this.window = window; | 64 this.window = window; |
| 47 this.getFiltersFunc = getFiltersFunc; | 65 this.getFiltersFunc = getFiltersFunc; |
| 48 this.addSelectorsFunc = addSelectorsFunc; | 66 this.addSelectorsFunc = addSelectorsFunc; |
| 49 } | 67 } |
| 50 | 68 |
| 51 ElemHideEmulation.prototype = { | 69 ElemHideEmulation.prototype = { |
| 52 stringifyStyle: function(style) | 70 stringifyStyle(style) |
| 53 { | 71 { |
| 54 var styles = []; | 72 let styles = []; |
| 55 for (var i = 0; i < style.length; i++) | 73 for (let i = 0; i < style.length; i++) |
| 56 { | 74 { |
| 57 var property = style.item(i); | 75 let property = style.item(i); |
| 58 var value = style.getPropertyValue(property); | 76 let value = style.getPropertyValue(property); |
| 59 var priority = style.getPropertyPriority(property); | 77 let priority = style.getPropertyPriority(property); |
| 60 styles.push(property + ": " + value + (priority ? " !" + priority : "") +
";"); | 78 styles.push(property + ": " + value + (priority ? " !" + priority : "") + |
| 79 ";"); |
| 61 } | 80 } |
| 62 styles.sort(); | 81 styles.sort(); |
| 63 return styles.join(" "); | 82 return styles.join(" "); |
| 64 }, | 83 }, |
| 65 | 84 |
| 66 isSameOrigin: function(stylesheet) | 85 isSameOrigin(stylesheet) |
| 67 { | 86 { |
| 68 try | 87 try |
| 69 { | 88 { |
| 70 return new URL(stylesheet.href).origin == this.window.location.origin; | 89 return new URL(stylesheet.href).origin == this.window.location.origin; |
| 71 } | 90 } |
| 72 catch (e) | 91 catch (e) |
| 73 { | 92 { |
| 74 // Invalid URL, assume that it is first-party. | 93 // Invalid URL, assume that it is first-party. |
| 75 return true; | 94 return true; |
| 76 } | 95 } |
| 77 }, | 96 }, |
| 78 | 97 |
| 79 findSelectors: function(stylesheet, selectors, filters) | 98 findSelectors(stylesheet, selectors, filters) |
| 80 { | 99 { |
| 81 // Explicitly ignore third-party stylesheets to ensure consistent behavior | 100 // Explicitly ignore third-party stylesheets to ensure consistent behavior |
| 82 // between Firefox and Chrome. | 101 // between Firefox and Chrome. |
| 83 if (!this.isSameOrigin(stylesheet)) | 102 if (!this.isSameOrigin(stylesheet)) |
| 84 return; | 103 return; |
| 85 | 104 |
| 86 var rules = stylesheet.cssRules; | 105 let rules = stylesheet.cssRules; |
| 87 if (!rules) | 106 if (!rules) |
| 88 return; | 107 return; |
| 89 | 108 |
| 90 for (var i = 0; i < rules.length; i++) | 109 for (let rule of rules) |
| 91 { | 110 { |
| 92 var rule = rules[i]; | |
| 93 if (rule.type != rule.STYLE_RULE) | 111 if (rule.type != rule.STYLE_RULE) |
| 94 continue; | 112 continue; |
| 95 | 113 |
| 96 var style = this.stringifyStyle(rule.style); | 114 let style = this.stringifyStyle(rule.style); |
| 97 for (var j = 0; j < this.patterns.length; j++) | 115 for (let pattern of this.patterns) |
| 98 { | 116 { |
| 99 var pattern = this.patterns[j]; | |
| 100 if (pattern.regexp.test(style)) | 117 if (pattern.regexp.test(style)) |
| 101 { | 118 { |
| 102 var subSelectors = splitSelector(rule.selectorText); | 119 let subSelectors = splitSelector(rule.selectorText); |
| 103 for (var k = 0; k < subSelectors.length; k++) | 120 for (let subSelector of subSelectors) |
| 104 { | 121 { |
| 105 var subSelector = subSelectors[k]; | |
| 106 selectors.push(pattern.prefix + subSelector + pattern.suffix); | 122 selectors.push(pattern.prefix + subSelector + pattern.suffix); |
| 107 filters.push(pattern.text); | 123 filters.push(pattern.text); |
| 108 } | 124 } |
| 109 } | 125 } |
| 110 } | 126 } |
| 111 } | 127 } |
| 112 }, | 128 }, |
| 113 | 129 |
| 114 addSelectors: function(stylesheets) | 130 addSelectors(stylesheets) |
| 115 { | 131 { |
| 116 var selectors = []; | 132 let selectors = []; |
| 117 var filters = []; | 133 let filters = []; |
| 118 for (var i = 0; i < stylesheets.length; i++) | 134 for (let stylesheet of stylesheets) |
| 119 this.findSelectors(stylesheets[i], selectors, filters); | 135 this.findSelectors(stylesheet, selectors, filters); |
| 120 this.addSelectorsFunc(selectors, filters); | 136 this.addSelectorsFunc(selectors, filters); |
| 121 }, | 137 }, |
| 122 | 138 |
| 123 onLoad: function(event) | 139 onLoad(event) |
| 124 { | 140 { |
| 125 var stylesheet = event.target.sheet; | 141 let stylesheet = event.target.sheet; |
| 126 if (stylesheet) | 142 if (stylesheet) |
| 127 this.addSelectors([stylesheet]); | 143 this.addSelectors([stylesheet]); |
| 128 }, | 144 }, |
| 129 | 145 |
| 130 apply: function() | 146 apply() |
| 131 { | 147 { |
| 132 this.getFiltersFunc(function(patterns) | 148 this.getFiltersFunc(patterns => |
| 133 { | 149 { |
| 134 this.patterns = []; | 150 this.patterns = []; |
| 135 for (var i = 0; i < patterns.length; i++) | 151 for (let pattern of patterns) |
| 136 { | 152 { |
| 137 var pattern = patterns[i]; | 153 let match = propertySelectorRegExp.exec(pattern.selector); |
| 138 var match = propertySelectorRegExp.exec(pattern.selector); | |
| 139 if (!match) | 154 if (!match) |
| 140 continue; | 155 continue; |
| 141 | 156 |
| 142 var propertyExpression = match[2]; | 157 let propertyExpression = match[2]; |
| 143 var regexpString; | 158 let regexpString; |
| 144 if (propertyExpression.length >= 2 && propertyExpression[0] == "/" && | 159 if (propertyExpression.length >= 2 && propertyExpression[0] == "/" && |
| 145 propertyExpression[propertyExpression.length - 1] == "/") | 160 propertyExpression[propertyExpression.length - 1] == "/") |
| 161 { |
| 146 regexpString = propertyExpression.slice(1, -1) | 162 regexpString = propertyExpression.slice(1, -1) |
| 147 .replace("\\x7B ", "{").replace("\\x7D ", "}"); | 163 .replace("\\x7B ", "{").replace("\\x7D ", "}"); |
| 164 } |
| 148 else | 165 else |
| 149 regexpString = filterToRegExp(propertyExpression); | 166 regexpString = filterToRegExp(propertyExpression); |
| 150 | 167 |
| 151 this.patterns.push({ | 168 this.patterns.push({ |
| 152 text: pattern.text, | 169 text: pattern.text, |
| 153 regexp: new RegExp(regexpString, "i"), | 170 regexp: new RegExp(regexpString, "i"), |
| 154 prefix: pattern.selector.substr(0, match.index), | 171 prefix: pattern.selector.substr(0, match.index), |
| 155 suffix: pattern.selector.substr(match.index + match[0].length) | 172 suffix: pattern.selector.substr(match.index + match[0].length) |
| 156 }); | 173 }); |
| 157 } | 174 } |
| 158 | 175 |
| 159 if (this.patterns.length > 0) | 176 if (this.patterns.length > 0) |
| 160 { | 177 { |
| 161 var document = this.window.document; | 178 let {document} = this.window; |
| 162 this.addSelectors(document.styleSheets); | 179 this.addSelectors(document.styleSheets); |
| 163 document.addEventListener("load", this.onLoad.bind(this), true); | 180 document.addEventListener("load", this.onLoad.bind(this), true); |
| 164 } | 181 } |
| 165 }.bind(this)); | 182 }); |
| 166 } | 183 } |
| 167 }; | 184 }; |
| OLD | NEW |