|
1814 | 1814 | function __variableDynamicImportRuntime0__(path) {
|
1815 | 1815 | switch (path) {
|
1816 | 1816 | case './features/cookie.js': return Promise.resolve().then(function () { return cookie; });
|
| 1817 | + case './features/element-hiding.js': return Promise.resolve().then(function () { return elementHiding; }); |
1817 | 1818 | case './features/fingerprinting-audio.js': return Promise.resolve().then(function () { return fingerprintingAudio; });
|
1818 | 1819 | case './features/fingerprinting-battery.js': return Promise.resolve().then(function () { return fingerprintingBattery; });
|
1819 | 1820 | case './features/fingerprinting-canvas.js': return Promise.resolve().then(function () { return fingerprintingCanvas; });
|
|
1863 | 1864 | 'referrer',
|
1864 | 1865 | 'fingerprintingScreenSize',
|
1865 | 1866 | 'fingerprintingTemporaryStorage',
|
1866 |
| - 'navigatorInterface' |
| 1867 | + 'navigatorInterface', |
| 1868 | + 'elementHiding' |
1867 | 1869 | ];
|
1868 | 1870 |
|
1869 | 1871 | for (const featureName of featureNames) {
|
|
1878 | 1880 | }
|
1879 | 1881 | }
|
1880 | 1882 |
|
1881 |
| - async function init$d (args) { |
| 1883 | + async function init$e (args) { |
1882 | 1884 | initArgs = args;
|
1883 | 1885 | if (!shouldRun()) {
|
1884 | 1886 | return
|
|
2234 | 2236 | });
|
2235 | 2237 | }
|
2236 | 2238 |
|
2237 |
| - function init$c (args) { |
| 2239 | + function init$d (args) { |
2238 | 2240 | args.cookie.debug = args.debug;
|
2239 | 2241 | cookiePolicy = args.cookie;
|
2240 | 2242 |
|
|
2258 | 2260 | var cookie = /*#__PURE__*/Object.freeze({
|
2259 | 2261 | __proto__: null,
|
2260 | 2262 | load: load,
|
2261 |
| - init: init$c, |
| 2263 | + init: init$d, |
2262 | 2264 | update: update
|
2263 | 2265 | });
|
2264 | 2266 |
|
| 2267 | + let adLabelStrings = []; |
| 2268 | + |
| 2269 | + function collapseDomNode (element, type) { |
| 2270 | + if (!element) { |
| 2271 | + return |
| 2272 | + } |
| 2273 | + |
| 2274 | + switch (type) { |
| 2275 | + case 'hide': |
| 2276 | + if (!element.hidden) { |
| 2277 | + hideNode(element); |
| 2278 | + } |
| 2279 | + break |
| 2280 | + case 'hide-empty': |
| 2281 | + if (!element.hidden && isDomNodeEmpty(element)) { |
| 2282 | + hideNode(element); |
| 2283 | + } |
| 2284 | + break |
| 2285 | + case 'closest-empty': |
| 2286 | + // if element already hidden, continue onto parent element |
| 2287 | + if (element.hidden) { |
| 2288 | + collapseDomNode(element.parentNode, type); |
| 2289 | + break |
| 2290 | + } |
| 2291 | + |
| 2292 | + if (isDomNodeEmpty(element)) { |
| 2293 | + hideNode(element); |
| 2294 | + collapseDomNode(element.parentNode, type); |
| 2295 | + } |
| 2296 | + break |
| 2297 | + default: |
| 2298 | + console.log(`Unsupported rule: ${type}`); |
| 2299 | + } |
| 2300 | + } |
| 2301 | + |
| 2302 | + function hideNode (element) { |
| 2303 | + element.style.setProperty('display', 'none', 'important'); |
| 2304 | + element.hidden = true; |
| 2305 | + } |
| 2306 | + |
| 2307 | + function isDomNodeEmpty (node) { |
| 2308 | + const visibleText = node.innerText.trim().toLocaleLowerCase(); |
| 2309 | + const mediaContent = node.querySelector('video,canvas'); |
| 2310 | + const frameElements = [...node.querySelectorAll('iframe')]; |
| 2311 | + // about:blank iframes don't count as content, return true if: |
| 2312 | + // - node doesn't contain any iframes |
| 2313 | + // - node contains iframes, all of which are hidden or have src='about:blank' |
| 2314 | + const noFramesWithContent = frameElements.every((frame) => { |
| 2315 | + return (frame.hidden || frame.src === 'about:blank') |
| 2316 | + }); |
| 2317 | + if ((visibleText === '' || adLabelStrings.includes(visibleText)) && |
| 2318 | + noFramesWithContent && mediaContent === null) { |
| 2319 | + return true |
| 2320 | + } |
| 2321 | + return false |
| 2322 | + } |
| 2323 | + |
| 2324 | + function hideMatchingDomNodes (rules) { |
| 2325 | + const document = globalThis.document; |
| 2326 | + |
| 2327 | + function hideMatchingNodesInner () { |
| 2328 | + rules.forEach((rule) => { |
| 2329 | + const matchingElementArray = [...document.querySelectorAll(rule.selector)]; |
| 2330 | + matchingElementArray.forEach((element) => { |
| 2331 | + collapseDomNode(element, rule.type); |
| 2332 | + }); |
| 2333 | + }); |
| 2334 | + } |
| 2335 | + // wait 300ms before hiding ad containers so ads have a chance to load |
| 2336 | + setTimeout(hideMatchingNodesInner, 300); |
| 2337 | + |
| 2338 | + // handle any ad containers that weren't added to the page within 300ms of page load |
| 2339 | + setTimeout(hideMatchingNodesInner, 1000); |
| 2340 | + } |
| 2341 | + |
| 2342 | + function init$c (args) { |
| 2343 | + if (isBeingFramed()) { |
| 2344 | + return |
| 2345 | + } |
| 2346 | + |
| 2347 | + const featureName = 'elementHiding'; |
| 2348 | + const domain = args.site.domain; |
| 2349 | + const domainRules = getFeatureSetting(featureName, args, 'domains'); |
| 2350 | + const globalRules = getFeatureSetting(featureName, args, 'rules'); |
| 2351 | + adLabelStrings = getFeatureSetting(featureName, args, 'adLabelStrings'); |
| 2352 | + |
| 2353 | + // collect all matching rules for domain |
| 2354 | + const activeDomainRules = domainRules.filter((rule) => { |
| 2355 | + return matchHostname(domain, rule.domain) |
| 2356 | + }).flatMap((item) => item.rules); |
| 2357 | + |
| 2358 | + const overrideRules = activeDomainRules.filter((rule) => { |
| 2359 | + return rule.type === 'override' |
| 2360 | + }); |
| 2361 | + |
| 2362 | + let activeRules = activeDomainRules.concat(globalRules); |
| 2363 | + |
| 2364 | + // remove overrides and rules that match overrides from array of rules to be applied to page |
| 2365 | + overrideRules.forEach((override) => { |
| 2366 | + activeRules = activeRules.filter((rule) => { |
| 2367 | + return rule.selector !== override.selector |
| 2368 | + }); |
| 2369 | + }); |
| 2370 | + |
| 2371 | + // now have the final list of rules to apply, so we apply them when document is loaded |
| 2372 | + if (document.readyState === 'loading') { |
| 2373 | + window.addEventListener('DOMContentLoaded', (event) => { |
| 2374 | + hideMatchingDomNodes(activeRules); |
| 2375 | + }); |
| 2376 | + } else { |
| 2377 | + hideMatchingDomNodes(activeRules); |
| 2378 | + } |
| 2379 | + // single page applications don't have a DOMContentLoaded event on navigations, so |
| 2380 | + // we use proxy/reflect on history.pushState and history.replaceState to call hideMatchingDomNodes |
| 2381 | + // on page navigations, and listen for popstate events that indicate a back/forward navigation |
| 2382 | + const methods = ['pushState', 'replaceState']; |
| 2383 | + for (const methodName of methods) { |
| 2384 | + const historyMethodProxy = new DDGProxy(featureName, History.prototype, methodName, { |
| 2385 | + apply (target, thisArg, args) { |
| 2386 | + hideMatchingDomNodes(activeRules); |
| 2387 | + return DDGReflect.apply(target, thisArg, args) |
| 2388 | + } |
| 2389 | + }); |
| 2390 | + historyMethodProxy.overload(); |
| 2391 | + } |
| 2392 | + window.addEventListener('popstate', (event) => { |
| 2393 | + hideMatchingDomNodes(activeRules); |
| 2394 | + }); |
| 2395 | + } |
| 2396 | + |
| 2397 | + var elementHiding = /*#__PURE__*/Object.freeze({ |
| 2398 | + __proto__: null, |
| 2399 | + init: init$c |
| 2400 | + }); |
| 2401 | + |
2265 | 2402 | function init$b (args) {
|
2266 | 2403 | const { sessionKey, site } = args;
|
2267 | 2404 | const domainKey = site.domain;
|
|
4459 | 4596 | init: init
|
4460 | 4597 | });
|
4461 | 4598 |
|
4462 |
| - exports.init = init$d; |
| 4599 | + exports.init = init$e; |
4463 | 4600 | exports.load = load$1;
|
4464 | 4601 | exports.update = update$1;
|
4465 | 4602 |
|
|
0 commit comments