| OLD | NEW | 
|---|
| 1 /* | 1 /* | 
| 2  * This file is part of Adblock Plus <https://adblockplus.org/>, | 2  * This file is part of Adblock Plus <https://adblockplus.org/>, | 
| 3  * Copyright (C) 2006-2017 eyeo GmbH | 3  * Copyright (C) 2006-2017 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 30 matching lines...) Expand all  Loading... | 
| 41   } | 41   } | 
| 42 | 42 | 
| 43   callback(); | 43   callback(); | 
| 44 }; | 44 }; | 
| 45 | 45 | 
| 46 exports.tearDown = function(callback) | 46 exports.tearDown = function(callback) | 
| 47 { | 47 { | 
| 48   var styleElements = document.head.getElementsByTagName("style"); | 48   var styleElements = document.head.getElementsByTagName("style"); | 
| 49   while (styleElements.length) | 49   while (styleElements.length) | 
| 50     styleElements[0].parentNode.removeChild(styleElements[0]); | 50     styleElements[0].parentNode.removeChild(styleElements[0]); | 
|  | 51   var child; | 
|  | 52   while(child = document.body.firstChild) | 
|  | 53   { | 
|  | 54     document.body.removeChild(child); | 
|  | 55   } | 
| 51   callback(); | 56   callback(); | 
| 52 }; | 57 }; | 
| 53 | 58 | 
| 54 function expectHidden(test, element) | 59 function expectHidden(test, element) | 
| 55 { | 60 { | 
| 56   test.equal(window.getComputedStyle(element).display, "none", | 61   test.equal(window.getComputedStyle(element).display, "none", | 
| 57              "The element's display property should be set to 'none'"); | 62              "The element's display property should be set to 'none'"); | 
| 58 } | 63 } | 
| 59 | 64 | 
| 60 function expectVisible(test, element) | 65 function expectVisible(test, element) | 
| (...skipping 17 matching lines...) Expand all  Loading... | 
| 78   if (styleElements.length) | 83   if (styleElements.length) | 
| 79     styleElement = styleElements[0]; | 84     styleElement = styleElements[0]; | 
| 80   else | 85   else | 
| 81   { | 86   { | 
| 82     styleElement = document.createElement("style"); | 87     styleElement = document.createElement("style"); | 
| 83     document.head.appendChild(styleElement); | 88     document.head.appendChild(styleElement); | 
| 84   } | 89   } | 
| 85   styleElement.sheet.insertRule(rule, styleElement.sheet.cssRules.length); | 90   styleElement.sheet.insertRule(rule, styleElement.sheet.cssRules.length); | 
| 86 } | 91 } | 
| 87 | 92 | 
| 88 function createElementWithStyle(styleBlock) | 93 // insert a <div> with a unique id and and empty CSS rule | 
|  | 94 // for the the selector matching the id. | 
|  | 95 function createElementWithStyle(styleBlock, parent) | 
| 89 { | 96 { | 
| 90   var element = document.createElement("div"); | 97   var element = document.createElement("div"); | 
| 91   element.id = findUniqueId(); | 98   element.id = findUniqueId(); | 
| 92   document.body.appendChild(element); | 99   if (!parent) | 
|  | 100     document.body.appendChild(element); | 
|  | 101   else | 
|  | 102     parent.appendChild(element); | 
| 93   insertStyleRule("#" + element.id + " " + styleBlock); | 103   insertStyleRule("#" + element.id + " " + styleBlock); | 
| 94   return element; | 104   return element; | 
| 95 } | 105 } | 
| 96 | 106 | 
| 97 function applyElemHideEmulation(selectors, callback) | 107 // Will ensure the class ElemHideEmulation is loaded | 
|  | 108 // and then will call the callback. | 
|  | 109 // NOTE: if it never loads, this will probably hang in an infinite | 
|  | 110 // loop | 
|  | 111 function loadElemHideEmulation(callback) | 
| 98 { | 112 { | 
| 99   if (typeof ElemHideEmulation == "undefined") | 113   if (typeof ElemHideEmulation == "undefined") | 
| 100   { | 114   { | 
| 101     loadScript(myUrl + "/../../../lib/common.js", function() | 115     loadScript(myUrl + "/../../../lib/common.js", function() | 
| 102     { | 116     { | 
| 103       loadScript(myUrl + "/../../../chrome/content/elemHideEmulation.js", | 117       loadScript(myUrl + "/../../../chrome/content/elemHideEmulation.js", | 
| 104           function() | 118           function() | 
| 105           { | 119           { | 
| 106             applyElemHideEmulation(selectors, callback); | 120             loadElemHideEmulation(callback); | 
| 107           }); | 121           }); | 
| 108     }); | 122     }); | 
| 109     return; | 123     return; | 
| 110   } | 124   } | 
| 111 | 125 | 
| 112   var elemHideEmulation = new ElemHideEmulation( | 126   callback(); | 
| 113     window, | 127 } | 
| 114     function(callback) | 128 | 
| 115     { | 129 // instantiate a ElemHideEmulation with @selectors. | 
| 116       var patterns = []; | 130 function applyElemHideEmulation(selectors, callback) | 
| 117       selectors.forEach(function(selector) | 131 { | 
|  | 132   loadElemHideEmulation(function() | 
|  | 133   { | 
|  | 134     var elemHideEmulation = new ElemHideEmulation( | 
|  | 135       window, | 
|  | 136       function(callback) | 
| 118       { | 137       { | 
| 119         patterns.push({selector: selector}); | 138         var patterns = []; | 
| 120       }); | 139         selectors.forEach(function(selector) | 
| 121       callback(patterns); | 140         { | 
| 122     }, | 141           patterns.push({selector: selector}); | 
| 123     function(selectors) | 142         }); | 
| 124     { | 143         callback(patterns); | 
| 125       if (!selectors.length) | 144       }, | 
| 126         return; | 145       function(selectors) | 
| 127       var selector = selectors.join(", "); | 146       { | 
| 128       insertStyleRule(selector + "{display: none !important;}"); | 147         if (!selectors.length) | 
| 129     } | 148           return; | 
| 130   ); | 149         var selector = selectors.join(", "); | 
| 131 | 150         insertStyleRule(selector + "{display: none !important;}"); | 
| 132   elemHideEmulation.apply(); | 151       }, | 
| 133   callback(); | 152       function(elements) | 
| 134 } | 153       { | 
|  | 154         if (!elements.length) | 
|  | 155           return; | 
|  | 156         for (var i = 0; i < elements.length; i++) | 
|  | 157           elements[i].style.display = "none"; | 
|  | 158       } | 
|  | 159     ); | 
|  | 160 | 
|  | 161     elemHideEmulation.apply(); | 
|  | 162     callback(); | 
|  | 163   }.bind(this)); | 
|  | 164 } | 
|  | 165 | 
|  | 166 exports.testPseudoHasRule = function(test) | 
|  | 167 { | 
|  | 168   loadElemHideEmulation(function() | 
|  | 169   { | 
|  | 170     var selectors = ["div:has(span)"]; | 
|  | 171     // testing the regexp | 
|  | 172     var match = pseudoClassHasSelectorRegExp.exec(selectors[0]); | 
|  | 173     test.ok(match); | 
|  | 174     test.equal(match[1], "span"); | 
|  | 175 | 
|  | 176     selectors = [":has(div.inside)"]; | 
|  | 177     match = pseudoClassHasSelectorRegExp.exec(selectors[0]); | 
|  | 178     test.ok(match); | 
|  | 179     test.equal(match[1], "div.inside"); | 
|  | 180 | 
|  | 181     test.done(); | 
|  | 182   }); | 
|  | 183 }; | 
|  | 184 | 
|  | 185 exports.testExtraFirstSelector = function(test) | 
|  | 186 { | 
|  | 187   loadElemHideEmulation(function() | 
|  | 188   { | 
|  | 189     var myselector = "elem.class1.class2"; | 
|  | 190     var shortSel = extractFirstSelector(myselector); | 
|  | 191 | 
|  | 192     test.equal(shortSel, myselector); | 
|  | 193 | 
|  | 194     myselector = "elem > elem2"; | 
|  | 195     shortSel = extractFirstSelector(myselector); | 
|  | 196 | 
|  | 197     test.equal(shortSel, "elem"); | 
|  | 198 | 
|  | 199     myselector = "elem+elem2 > elem3"; | 
|  | 200     shortSel = extractFirstSelector(myselector); | 
|  | 201 | 
|  | 202     test.equal(shortSel, "elem"); | 
|  | 203 | 
|  | 204     myselector = "elem~elem2 > elem3"; | 
|  | 205     shortSel = extractFirstSelector(myselector); | 
|  | 206 | 
|  | 207     test.equal(shortSel, "elem"); | 
|  | 208 | 
|  | 209     test.done(); | 
|  | 210   }); | 
|  | 211 }; | 
|  | 212 | 
|  | 213 exports.testSplitStyleRule = function(test) | 
|  | 214 { | 
|  | 215   loadElemHideEmulation(function() | 
|  | 216   { | 
|  | 217     var selectors = splitSelector("div:has(div) > [-abp-properties='background-c
     olor: rgb(0, 0, 0)'] > span"); | 
|  | 218     test.ok(selectors); | 
|  | 219     test.equal(selectors.length, 1, "There is only one selector"); | 
|  | 220 | 
|  | 221     selectors = splitSelector("div:has(div), [-abp-properties='background-color:
      rgb(0, 0, 0)']"); | 
|  | 222     test.ok(selectors); | 
|  | 223     test.equal(selectors.length, 2, "There are two selectors"); | 
|  | 224 | 
|  | 225     test.done(); | 
|  | 226   }); | 
|  | 227 }; | 
| 135 | 228 | 
| 136 exports.testVerbatimPropertySelector = function(test) | 229 exports.testVerbatimPropertySelector = function(test) | 
| 137 { | 230 { | 
| 138   var toHide = createElementWithStyle("{background-color: #000}"); | 231   var toHide = createElementWithStyle("{background-color: #000}"); | 
| 139   applyElemHideEmulation( | 232   applyElemHideEmulation( | 
| 140     ["[-abp-properties='background-color: rgb(0, 0, 0)']"], | 233     ["[-abp-properties='background-color: rgb(0, 0, 0)']"], | 
| 141     function() | 234     function() | 
| 142     { | 235     { | 
| 143       expectHidden(test, toHide); | 236       expectHidden(test, toHide); | 
| 144       test.done(); | 237       test.done(); | 
| 145     } | 238     } | 
| 146   ); | 239   ); | 
| 147 }; | 240 }; | 
| 148 | 241 | 
|  | 242 exports.testVerbatimPropertySelectorWithPrefix = function(test) | 
|  | 243 { | 
|  | 244   var parent = createElementWithStyle("{background-color: #000}"); | 
|  | 245   var toHide = createElementWithStyle("{background-color: #000}", parent); | 
|  | 246   applyElemHideEmulation( | 
|  | 247     ["div > [-abp-properties='background-color: rgb(0, 0, 0)']"], | 
|  | 248     function() | 
|  | 249     { | 
|  | 250       expectVisible(test, parent); | 
|  | 251       expectHidden(test, toHide); | 
|  | 252       test.done(); | 
|  | 253     } | 
|  | 254   ); | 
|  | 255 }; | 
|  | 256 | 
|  | 257 exports.testVerbatimPropertySelectorWithPrefixNoMatch = function(test) | 
|  | 258 { | 
|  | 259   var parent = createElementWithStyle("{background-color: #000}"); | 
|  | 260   var toHide = createElementWithStyle("{background-color: #fff}", parent); | 
|  | 261   applyElemHideEmulation( | 
|  | 262     ["div > [-abp-properties='background-color: rgb(0, 0, 0)']"], | 
|  | 263     function() | 
|  | 264     { | 
|  | 265       expectVisible(test, parent); | 
|  | 266       expectVisible(test, toHide); | 
|  | 267       test.done(); | 
|  | 268     } | 
|  | 269   ); | 
|  | 270 }; | 
|  | 271 | 
|  | 272 exports.testVerbatimPropertySelectorWithSuffix = function(test) | 
|  | 273 { | 
|  | 274   var parent = createElementWithStyle("{background-color: #000}"); | 
|  | 275   var toHide = createElementWithStyle("{background-color: #000}", parent); | 
|  | 276   applyElemHideEmulation( | 
|  | 277     ["[-abp-properties='background-color: rgb(0, 0, 0)'] > div"], | 
|  | 278     function() | 
|  | 279     { | 
|  | 280       expectVisible(test, parent); | 
|  | 281       expectHidden(test, toHide); | 
|  | 282       test.done(); | 
|  | 283     } | 
|  | 284   ); | 
|  | 285 }; | 
|  | 286 | 
|  | 287 exports.testVerbatimPropertySelectorWithPrefixAndSuffix = function(test) | 
|  | 288 { | 
|  | 289   var parent = createElementWithStyle("{background-color: #000}"); | 
|  | 290   var middle = createElementWithStyle("{background-color: #000}", parent); | 
|  | 291   var toHide = createElementWithStyle("{background-color: #000}", middle); | 
|  | 292   applyElemHideEmulation( | 
|  | 293     ["div > [-abp-properties='background-color: rgb(0, 0, 0)'] > div"], | 
|  | 294     function() | 
|  | 295     { | 
|  | 296       expectVisible(test, parent); | 
|  | 297       expectVisible(test, middle); | 
|  | 298       expectHidden(test, toHide); | 
|  | 299       test.done(); | 
|  | 300     } | 
|  | 301   ); | 
|  | 302 }; | 
|  | 303 | 
| 149 exports.testPropertySelectorWithWildcard = function(test) | 304 exports.testPropertySelectorWithWildcard = function(test) | 
| 150 { | 305 { | 
| 151   var toHide = createElementWithStyle("{background-color: #000}"); | 306   var toHide = createElementWithStyle("{background-color: #000}"); | 
| 152   applyElemHideEmulation( | 307   applyElemHideEmulation( | 
| 153     ["[-abp-properties='*color: rgb(0, 0, 0)']"], | 308     ["[-abp-properties='*color: rgb(0, 0, 0)']"], | 
| 154     function() | 309     function() | 
| 155     { | 310     { | 
| 156       expectHidden(test, toHide); | 311       expectHidden(test, toHide); | 
| 157       test.done(); | 312       test.done(); | 
| 158     } | 313     } | 
| (...skipping 49 matching lines...) Expand 10 before | Expand all | Expand 10 after  Loading... | 
| 208       expectVisible(test, toHide); | 363       expectVisible(test, toHide); | 
| 209       insertStyleRule("#" + toHide.id + " {background-color: #000}"); | 364       insertStyleRule("#" + toHide.id + " {background-color: #000}"); | 
| 210       window.setTimeout(function() | 365       window.setTimeout(function() | 
| 211       { | 366       { | 
| 212         expectHidden(test, toHide); | 367         expectHidden(test, toHide); | 
| 213         test.done(); | 368         test.done(); | 
| 214       }, 0); | 369       }, 0); | 
| 215     } | 370     } | 
| 216   ); | 371   ); | 
| 217 }; | 372 }; | 
|  | 373 | 
|  | 374 exports.testPseudoClassHasMatcher = function(test) | 
|  | 375 { | 
|  | 376   var parent = createElementWithStyle("{}"); | 
|  | 377   var child = createElementWithStyle("{}", parent); | 
|  | 378   loadElemHideEmulation(function() | 
|  | 379   { | 
|  | 380     var matcher = new PseudoHasMatcher("div"); | 
|  | 381     test.equal(matcher.match(parent).length, 1, "Parent should contain what is e
     xpected"); | 
|  | 382     test.equal(matcher.match(child).length, 0, "Child shouldn't match"); | 
|  | 383 | 
|  | 384     var matcher2 = new PseudoHasMatcher("span"); | 
|  | 385     test.equal(matcher2.match(parent), 0, "Doesn't have a <span> child, shouldn'
     t mactch"); | 
|  | 386     test.equal(matcher2.match(child), 0, "Child shouldn't match"); | 
|  | 387 | 
|  | 388     test.done(); | 
|  | 389   }); | 
|  | 390 }; | 
|  | 391 | 
|  | 392 exports.testPseudoClassHasSelector = function(test) | 
|  | 393 { | 
|  | 394   var toHide = createElementWithStyle("{}"); | 
|  | 395   applyElemHideEmulation( | 
|  | 396     ["div:has(div)"], | 
|  | 397     function() | 
|  | 398     { | 
|  | 399       expectVisible(test, toHide); | 
|  | 400       test.done(); | 
|  | 401     } | 
|  | 402   ); | 
|  | 403 }; | 
|  | 404 | 
|  | 405 exports.testPseudoClassHasSelectorWithPrefix = function(test) | 
|  | 406 { | 
|  | 407   var parent = createElementWithStyle("{}"); | 
|  | 408   var child = createElementWithStyle("{}", parent); | 
|  | 409   applyElemHideEmulation( | 
|  | 410     ["div:has(div)"], | 
|  | 411     function() | 
|  | 412     { | 
|  | 413       expectHidden(test, parent); | 
|  | 414       expectVisible(test, child); | 
|  | 415       test.done(); | 
|  | 416     } | 
|  | 417   ); | 
|  | 418 }; | 
|  | 419 | 
|  | 420 exports.testPseudoClassHasSelectorWithSuffix = function(test) | 
|  | 421 { | 
|  | 422   var parent = createElementWithStyle("{}"); | 
|  | 423   var middle = createElementWithStyle("{}", parent); | 
|  | 424   var child = createElementWithStyle("{}", middle); | 
|  | 425   applyElemHideEmulation( | 
|  | 426     ["div:has(div) > div"], | 
|  | 427     function() | 
|  | 428     { | 
|  | 429       expectVisible(test, parent); | 
|  | 430       expectVisible(test, middle); | 
|  | 431       expectHidden(test, child); | 
|  | 432       test.done(); | 
|  | 433     } | 
|  | 434   ); | 
|  | 435 }; | 
|  | 436 | 
|  | 437 exports.testPseudoClassHasSelectorWithSuffixSibling = function(test) | 
|  | 438 { | 
|  | 439   var parent = createElementWithStyle("{}"); | 
|  | 440   var middle = createElementWithStyle("{}", parent); | 
|  | 441   var toHide = createElementWithStyle("{}", parent); | 
|  | 442   applyElemHideEmulation( | 
|  | 443     ["div:has(div) + div"], | 
|  | 444     function() | 
|  | 445     { | 
|  | 446       expectVisible(test, parent); | 
|  | 447       expectVisible(test, middle); | 
|  | 448       expectHidden(test, toHide); | 
|  | 449       test.done(); | 
|  | 450     } | 
|  | 451   ); | 
|  | 452 }; | 
|  | 453 | 
|  | 454 exports.testPseudoClassHasSelectorWithSuffixSibling = function(test) | 
|  | 455 { | 
|  | 456   //  <div> | 
|  | 457   //    <div></div> | 
|  | 458   //    <div> | 
|  | 459   //      <div>to hide</div> | 
|  | 460   //    </div> | 
|  | 461   //  </div> | 
|  | 462   var parent = createElementWithStyle("{}"); | 
|  | 463   var middle = createElementWithStyle("{}", parent); | 
|  | 464   var sibling = createElementWithStyle("{}", parent); | 
|  | 465   var toHide = createElementWithStyle("{}", sibling); | 
|  | 466   applyElemHideEmulation( | 
|  | 467     ["div:has(div) + div > div"], | 
|  | 468     function() | 
|  | 469     { | 
|  | 470       expectVisible(test, parent); | 
|  | 471       expectVisible(test, middle); | 
|  | 472       expectVisible(test, sibling); | 
|  | 473       expectHidden(test, toHide); | 
|  | 474       test.done(); | 
|  | 475     } | 
|  | 476   ); | 
|  | 477 }; | 
|  | 478 | 
|  | 479 exports.testPseudoClassHasSelectorWithHasAndWithSuffixSibling = function(test) | 
|  | 480 { | 
|  | 481   //  <div> | 
|  | 482   //    <div><div class="inside"></div></div> | 
|  | 483   //    <div> | 
|  | 484   //      <div>to hide</div> | 
|  | 485   //    </div> | 
|  | 486   //  </div> | 
|  | 487   var parent = createElementWithStyle("{}"); | 
|  | 488   var middle = createElementWithStyle("{}", parent); | 
|  | 489   var inside = createElementWithStyle("{}", middle); | 
|  | 490   inside.className = "inside"; | 
|  | 491   var sibling = createElementWithStyle("{}", parent); | 
|  | 492   var toHide = createElementWithStyle("{}", sibling); | 
|  | 493   applyElemHideEmulation( | 
|  | 494     ["div:has(:has(div.inside)) + div > div"], | 
|  | 495     function() | 
|  | 496     { | 
|  | 497       expectVisible(test, parent); | 
|  | 498       expectVisible(test, middle); | 
|  | 499       expectVisible(test, inside); | 
|  | 500       expectVisible(test, sibling); | 
|  | 501       expectHidden(test, toHide); | 
|  | 502       test.done(); | 
|  | 503     } | 
|  | 504   ); | 
|  | 505 }; | 
|  | 506 | 
|  | 507 | 
|  | 508 exports.testPseudoClassHasSelectorWithPropSelector = function(test) | 
|  | 509 { | 
|  | 510   var parent = createElementWithStyle("{}"); | 
|  | 511   var child = createElementWithStyle("{background-color: #000}", parent); | 
|  | 512   applyElemHideEmulation( | 
|  | 513     ["div:has([-abp-properties='background-color: rgb(0, 0, 0)'])"], | 
|  | 514     function() | 
|  | 515     { | 
|  | 516       expectVisible(test, child); | 
|  | 517       expectHidden(test, parent); | 
|  | 518       test.done(); | 
|  | 519     } | 
|  | 520   ); | 
|  | 521 }; | 
| OLD | NEW | 
|---|