@eyeo/snippets
Version:
eye/o snippets for Ads blocker
1,681 lines (1,440 loc) • 69.6 kB
JavaScript
(environment, ...filters) => {
/*!
* This file is part of eyeo's Anti-Circumvention Snippets module (@eyeo/snippets),
* Copyright (C) 2006-present eyeo GmbH
*
* @eyeo/snippets 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.
*
* @eyeo/snippets 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 @eyeo/snippets. If not, see <http://www.gnu.org/licenses/>.
*/
const $$1 = Proxy;
const {apply: a, bind: b, call: c} = Function;
const apply$2 = c.bind(a);
const bind = c.bind(b);
const call = c.bind(c);
const callerHandler = {
get(target, name) {
return bind(c, target[name]);
}
};
const caller = target => new $$1(target, callerHandler);
const handler$2 = {
get(target, name) {
return bind(target[name], target);
}
};
const bound = target => new $$1(target, handler$2);
const {
assign: assign$1,
defineProperties: defineProperties$1,
freeze: freeze$1,
getOwnPropertyDescriptor: getOwnPropertyDescriptor$2,
getOwnPropertyDescriptors: getOwnPropertyDescriptors$1,
getPrototypeOf
} = bound(Object);
const {hasOwnProperty} = caller({});
const {species} = Symbol;
const handler$1 = {
get(target, name) {
const Native = target[name];
class Secure extends Native {}
const proto = getOwnPropertyDescriptors$1(Native.prototype);
delete proto.constructor;
freeze$1(defineProperties$1(Secure.prototype, proto));
const statics = getOwnPropertyDescriptors$1(Native);
delete statics.length;
delete statics.prototype;
statics[species] = {value: Secure};
return freeze$1(defineProperties$1(Secure, statics));
}
};
const secure = target => new $$1(target, handler$1);
const libEnvironment = typeof environment !== "undefined" ? environment :
{};
if (typeof globalThis === "undefined")
window.globalThis = window;
const {apply: apply$1, ownKeys} = bound(Reflect);
const worldEnvDefined = "world" in libEnvironment;
const isIsolatedWorld = worldEnvDefined && libEnvironment.world === "ISOLATED";
const isMainWorld = worldEnvDefined && libEnvironment.world === "MAIN";
const chromeObjAvailable = typeof chrome === "object" && !!chrome.runtime;
const browserObjAvailable = typeof browser === "object" && !!browser.runtime;
const isExtensionContext$2 = !isMainWorld &&
(isIsolatedWorld || chromeObjAvailable || browserObjAvailable);
const copyIfExtension = value => isExtensionContext$2 ?
value :
create(value, getOwnPropertyDescriptors(value));
const {
create,
defineProperties,
defineProperty,
freeze,
getOwnPropertyDescriptor: getOwnPropertyDescriptor$1,
getOwnPropertyDescriptors
} = bound(Object);
const invokes = bound(globalThis);
const classes = isExtensionContext$2 ? globalThis : secure(globalThis);
const {Map: Map$6, RegExp: RegExp$1, Set, WeakMap: WeakMap$3, WeakSet: WeakSet$a} = classes;
const augment = (source, target, method = null) => {
const known = ownKeys(target);
for (const key of ownKeys(source)) {
if (known.includes(key))
continue;
const descriptor = getOwnPropertyDescriptor$1(source, key);
if (method && "value" in descriptor) {
const {value} = descriptor;
if (typeof value === "function")
descriptor.value = method(value);
}
defineProperty(target, key, descriptor);
}
};
const primitive = name => {
const Super = classes[name];
class Class extends Super {}
const {toString, valueOf} = Super.prototype;
defineProperties(Class.prototype, {
toString: {value: toString},
valueOf: {value: valueOf}
});
const type = name.toLowerCase();
const method = callback => function() {
const result = apply$1(callback, this, arguments);
return typeof result === type ? new Class(result) : result;
};
augment(Super, Class, method);
augment(Super.prototype, Class.prototype, method);
return Class;
};
const variables$1 = freeze({
frozen: new WeakMap$3(),
hidden: new WeakSet$a(),
iframePropertiesToAbort: {
read: new Set(),
write: new Set()
},
abortedIframes: new WeakMap$3()
});
const startsCapitalized = new RegExp$1("^[A-Z]");
const extensionApi = (
isExtensionContext$2 && (
(chromeObjAvailable && chrome) ||
(browserObjAvailable && browser)
)
) || void 0;
var env = new Proxy(new Map$6([
["chrome", extensionApi],
["browser", extensionApi],
["isExtensionContext", isExtensionContext$2],
["variables", variables$1],
["console", copyIfExtension(console)],
["document", globalThis.document],
["JSON", copyIfExtension(JSON)],
["Map", Map$6],
["Math", copyIfExtension(Math)],
["Number", isExtensionContext$2 ? Number : primitive("Number")],
["RegExp", RegExp$1],
["Set", Set],
["String", isExtensionContext$2 ? String : primitive("String")],
["WeakMap", WeakMap$3],
["WeakSet", WeakSet$a],
["MouseEvent", MouseEvent]
]), {
get(map, key) {
if (map.has(key))
return map.get(key);
let value = globalThis[key];
if (typeof value === "function")
value = (startsCapitalized.test(key) ? classes : invokes)[key];
map.set(key, value);
return value;
},
has(map, key) {
return map.has(key);
}
});
class WeakValue {
has() { return false; }
set() {}
}
const helpers = {WeakSet, WeakMap, WeakValue};
const {apply} = Reflect;
function transformOnce (callback) { const {WeakSet, WeakMap, WeakValue} = (this || helpers);
const ws = new WeakSet;
const wm = new WeakMap;
const wv = new WeakValue;
return function (any) {
if (ws.has(any))
return any;
if (wm.has(any))
return wm.get(any);
if (wv.has(any))
return wv.get(any);
const value = apply(callback, this, arguments);
ws.add(value);
if (value !== any)
(typeof any === 'object' && any ? wm : wv).set(any, value);
return value;
};
}
const {Map: Map$5, WeakMap: WeakMap$2, WeakSet: WeakSet$9, setTimeout: setTimeout$3} = env;
let cleanup = true;
let cleanUpCallback = map => {
map.clear();
cleanup = !cleanup;
};
var transformer = transformOnce.bind({
WeakMap: WeakMap$2,
WeakSet: WeakSet$9,
WeakValue: class extends Map$5 {
set(key, value) {
if (cleanup) {
cleanup = !cleanup;
setTimeout$3(cleanUpCallback, 0, this);
}
return super.set(key, value);
}
}
});
const {concat, includes, join, reduce, unshift} = caller([]);
const globals = secure(globalThis);
const {
Map: Map$4,
WeakMap: WeakMap$1
} = globals;
const map = new Map$4;
const descriptors = target => {
const chain = [];
let current = target;
while (current) {
if (map.has(current))
unshift(chain, map.get(current));
else {
const descriptors = getOwnPropertyDescriptors$1(current);
map.set(current, descriptors);
unshift(chain, descriptors);
}
current = getPrototypeOf(current);
}
unshift(chain, {});
return apply$2(assign$1, null, chain);
};
const chain = source => {
const target = typeof source === 'function' ? source.prototype : source;
const chained = descriptors(target);
const handler = {
get(target, key) {
if (key in chained) {
const {value, get} = chained[key];
if (get)
return call(get, target);
if (typeof value === 'function')
return bind(value, target);
}
return target[key];
},
set(target, key, value) {
if (key in chained) {
const {set} = chained[key];
if (set) {
call(set, target, value);
return true;
}
}
target[key] = value;
return true;
}
};
return target => new $$1(target, handler);
};
const {
isExtensionContext: isExtensionContext$1,
Array: Array$3,
Number: Number$1,
String: String$1,
Object: Object$2
} = env;
const {isArray} = Array$3;
const {getOwnPropertyDescriptor, setPrototypeOf: setPrototypeOf$1} = Object$2;
const {toString} = Object$2.prototype;
const {slice} = String$1.prototype;
const getBrand = value => call(slice, call(toString, value), 8, -1);
const {get: nodeType} = getOwnPropertyDescriptor(Node.prototype, "nodeType");
const chained = isExtensionContext$1 ? {} : {
Attr: chain(Attr),
CanvasRenderingContext2D: chain(CanvasRenderingContext2D),
CSSStyleDeclaration: chain(CSSStyleDeclaration),
Document: chain(Document),
Element: chain(Element),
HTMLCanvasElement: chain(HTMLCanvasElement),
HTMLElement: chain(HTMLElement),
HTMLImageElement: chain(HTMLImageElement),
HTMLScriptElement: chain(HTMLScriptElement),
MutationRecord: chain(MutationRecord),
Node: chain(Node),
ShadowRoot: chain(ShadowRoot),
get CSS2Properties() {
return chained.CSSStyleDeclaration;
}
};
const upgrade = (value, hint) => {
if (hint !== "Element" && hint in chained)
return chained[hint](value);
if (isArray(value))
return setPrototypeOf$1(value, Array$3.prototype);
const brand = getBrand(value);
if (brand in chained)
return chained[brand](value);
if (brand in env)
return setPrototypeOf$1(value, env[brand].prototype);
if ("nodeType" in value) {
switch (call(nodeType, value)) {
case 1:
if (!(hint in chained))
throw new Error("unknown hint " + hint);
return chained[hint](value);
case 2:
return chained.Attr(value);
case 3:
return chained.Node(value);
case 9:
return chained.Document(value);
}
}
throw new Error("unknown brand " + brand);
};
var $ = isExtensionContext$1 ?
value => (value === window || value === globalThis ? env : value) :
transformer((value, hint = "Element") => {
if (value === window || value === globalThis)
return env;
switch (typeof value) {
case "object":
return value && upgrade(value, hint);
case "string":
return new String$1(value);
case "number":
return new Number$1(value);
default:
throw new Error("unsupported value");
}
});
let debugging = false;
function debug() {
return debugging;
}
function setDebug() {
debugging = true;
}
let {
console: console$2,
document: document$1,
getComputedStyle: getComputedStyle$5,
isExtensionContext,
variables,
Array: Array$2,
MutationObserver: MutationObserver$9,
Object: Object$1,
XPathEvaluator,
XPathExpression,
XPathResult
} = $(window);
const {querySelectorAll} = document$1;
const document$$ = querySelectorAll && bind(querySelectorAll, document$1);
function $openOrClosedShadowRoot(element, failSilently = false) {
try {
const shadowRoot = (navigator.userAgent.includes("Firefox")) ?
element.openOrClosedShadowRoot :
browser.dom.openOrClosedShadowRoot(element);
if (shadowRoot === null && ((debug() && !failSilently)))
console$2.log("Shadow root not found or not added in element yet", element);
return shadowRoot;
}
catch (error) {
if (debug() && !failSilently)
console$2.log("Error while accessing shadow root", element, error);
return null;
}
}
function $$(selector, returnRoots = false) {
return $$recursion(
selector,
document$$.bind(document$1),
document$1,
returnRoots
);
}
function isArrayEmptyStrings(arr) {
return !arr || arr.length === 0 || arr.every(item => item.trim() === "");
}
function executeSvgCommand(
nestedCommands,
rootParent,
resultNodes,
rootParents
) {
const xlinkHref = rootParent.getAttribute("xlink:href") ||
rootParent.getAttribute("href");
if (xlinkHref) {
const matchingElement = document$$(xlinkHref)[0];
if (!matchingElement && debug()) {
console$2.log("No elements found matching", xlinkHref);
return false;
}
if (isArrayEmptyStrings(nestedCommands)) {
const oldRootParents = rootParents.length > 0 ? rootParents : [];
resultNodes.push({
element: matchingElement,
rootParents: [...oldRootParents, rootParent]
});
return false;
}
const next$$ = matchingElement.querySelectorAll.bind(matchingElement);
return {
nextBoundElement: matchingElement,
nestedSelectorsString: nestedCommands.join("^^"),
next$$
};
}
}
function executeShadowRootCommand(nestedCommands, rootParent) {
const shadowRoot = $openOrClosedShadowRoot(rootParent);
if (shadowRoot) {
const {querySelectorAll: shadowRootQuerySelectorAll} = shadowRoot;
const next$$ = shadowRootQuerySelectorAll &&
bind(shadowRootQuerySelectorAll, shadowRoot).bind(shadowRoot);
return {
nextBoundElement: rootParent,
nestedSelectorsString: ":host " + nestedCommands.join("^^"),
next$$
};
}
return false;
}
function $$recursion(
selector,
bound$$,
boundElement,
returnRoots,
rootParents = []
) {
if (selector.includes("^^")) {
const [currentSelector, currentCommand, ...nestedCommands] =
selector.split("^^");
let newRootParents;
let commandFn;
switch (currentCommand) {
case "svg": {
commandFn = executeSvgCommand;
break;
}
case "sh": {
commandFn = executeShadowRootCommand;
break;
}
default: {
if (debug()) {
console$2.log(
currentCommand,
" is not supported. Supported commands are: \n^^sh^^\n^^svg^^"
);
}
return [];
}
}
if (currentSelector.trim() === "")
newRootParents = [boundElement];
else
newRootParents = bound$$(currentSelector);
const resultNodes = [];
for (const rootParent of newRootParents) {
const res =
commandFn(nestedCommands, rootParent, resultNodes, rootParents);
if (!res)
continue;
const {next$$, nestedSelectorsString, nextBoundElement} = res;
const nestedElements = $$recursion(
nestedSelectorsString,
next$$,
nextBoundElement,
returnRoots,
[...rootParents, rootParent]
);
if (nestedElements)
resultNodes.push(...nestedElements);
}
return resultNodes;
}
const foundElements = bound$$(selector);
if (returnRoots) {
return [...foundElements].map(element => (
{element, rootParents: rootParents.length > 0 ? rootParents : []})
);
}
return foundElements;
}
function $closest(element, selector, shadowRootParents = []) {
if (selector.includes("^^svg^^"))
selector = selector.split("^^svg^^")[0];
if (selector.includes("^^sh^^")) {
const splitSelector = selector.split("^^sh^^");
const numShadowRootsToCross = splitSelector.length - 1;
selector = `:host ${splitSelector[numShadowRootsToCross]}`;
if (numShadowRootsToCross === shadowRootParents.length) {
return element.closest(selector);
}
const shadowRootParent = shadowRootParents[numShadowRootsToCross];
return shadowRootParent.closest(selector);
}
if (shadowRootParents[0])
return shadowRootParents[0].closest(selector);
return element.closest(selector);
}
function $childNodes(element, failSilently = true) {
const shadowRoot = $openOrClosedShadowRoot(element, failSilently);
if (shadowRoot)
return shadowRoot.childNodes;
return $(element).childNodes;
}
const {assign, setPrototypeOf} = Object$1;
class $XPathExpression extends XPathExpression {
evaluate(...args) {
return setPrototypeOf(
apply$2(super.evaluate, this, args),
XPathResult.prototype
);
}
}
class $XPathEvaluator extends XPathEvaluator {
createExpression(...args) {
return setPrototypeOf(
apply$2(super.createExpression, this, args),
$XPathExpression.prototype
);
}
}
function hideElement(element) {
if (variables.hidden.has(element))
return false;
notifyElementHidden(element);
variables.hidden.add(element);
let {style} = $(element);
let $style = $(style, "CSSStyleDeclaration");
let properties = $([]);
let {debugCSSProperties} = libEnvironment;
for (let [key, value] of (debugCSSProperties || [["display", "none"]])) {
$style.setProperty(key, value, "important");
properties.push([key, $style.getPropertyValue(key)]);
}
new MutationObserver$9(() => {
for (let [key, value] of properties) {
let propertyValue = $style.getPropertyValue(key);
let propertyPriority = $style.getPropertyPriority(key);
if (propertyValue != value || propertyPriority != "important")
$style.setProperty(key, value, "important");
}
}).observe(element, {attributes: true,
attributeFilter: ["style"]});
return true;
}
function notifyElementHidden(element) {
if (isExtensionContext && typeof checkElement === "function")
checkElement(element);
}
function initQueryAndApply(selector) {
let $selector = selector;
if ($selector.startsWith("xpath(") &&
$selector.endsWith(")")) {
let xpathQuery = $selector.slice(6, -1);
let evaluator = new $XPathEvaluator();
let expression = evaluator.createExpression(xpathQuery, null);
let flag = XPathResult.ORDERED_NODE_SNAPSHOT_TYPE;
return cb => {
if (!cb)
return;
let result = expression.evaluate(document$1, flag, null);
let {snapshotLength} = result;
for (let i = 0; i < snapshotLength; i++)
cb(result.snapshotItem(i));
};
}
return cb => $$(selector).forEach(cb);
}
function initQueryAll(selector) {
let $selector = selector;
if ($selector.startsWith("xpath(") &&
$selector.endsWith(")")) {
let queryAndApply = initQueryAndApply(selector);
return () => {
let elements = $([]);
queryAndApply(e => elements.push(e));
return elements;
};
}
return () => Array$2.from($$(selector));
}
function hideIfMatches(match, selector, searchSelector, onHideCallback) {
if (searchSelector == null)
searchSelector = selector;
let won;
const callback = () => {
for (const {element, rootParents} of $$(searchSelector, true)) {
const closest = $closest($(element), selector, rootParents);
if (closest && match(element, closest, rootParents)) {
won();
if (hideElement(closest) && typeof onHideCallback === "function")
onHideCallback(closest);
}
}
};
return assign(
new MutationObserver$9(callback),
{
race(win) {
won = win;
this.observe(document$1, {childList: true,
characterData: true,
subtree: true});
callback();
}
}
);
}
function isVisible(element, style, closest, shadowRootParents) {
let $style = $(style, "CSSStyleDeclaration");
if ($style.getPropertyValue("display") == "none")
return false;
let visibility = $style.getPropertyValue("visibility");
if (visibility == "hidden" || visibility == "collapse")
return false;
if (!closest || element == closest)
return true;
let parent = $(element).parentElement;
if (!parent) {
if (shadowRootParents && shadowRootParents.length) {
parent = shadowRootParents[shadowRootParents.length - 1];
shadowRootParents = shadowRootParents.slice(0, -1);
}
else {
return true;
}
}
return isVisible(
parent, getComputedStyle$5(parent), closest, shadowRootParents
);
}
function getComputedCSSText(element) {
let style = getComputedStyle$5(element);
let {cssText} = style;
if (cssText)
return cssText;
for (let property of style)
cssText += `${property}: ${style[property]}; `;
return $(cssText).trim();
}
let {Array: Array$1, Math: Math$4, RegExp} = $(window);
function regexEscape(string) {
return $(string).replace(/[-/\\^$*+?.()|[\]{}]/g, "\\$&");
}
function toRegExp(pattern) {
let {length} = pattern;
if (length > 1 && pattern[0] === "/") {
let isCaseSensitive = pattern[length - 1] === "/";
if (isCaseSensitive || (length > 2 && $(pattern).endsWith("/i"))) {
let args = [$(pattern).slice(1, isCaseSensitive ? -1 : -2)];
if (!isCaseSensitive)
args.push("i");
return new RegExp(...args);
}
}
return new RegExp(regexEscape(pattern));
}
function formatArguments(args) {
return $(Array$1.from(args)).map(arg => `'${arg}'`).join(" ");
}
let {Math: Math$3, setInterval: setInterval$1, performance} = $(window);
const noopProfile = {
mark() {},
end() {},
toString() {
return "{mark(){},end(){}}";
}
};
let inactive = true;
function setProfile() {
inactive = false;
}
function profile(id, rate = 10) {
if (inactive)
return noopProfile;
function processSamples() {
let samples = $([]);
for (let {name, duration} of performance.getEntriesByType("measure"))
samples.push({name, duration});
if (samples.length)
performance.clearMeasures();
}
if (!profile[id]) {
profile[id] = setInterval$1(processSamples,
Math$3.round(60000 / Math$3.min(60, rate)));
}
return {
mark() {
performance.mark(id);
},
end(clear = false) {
performance.measure(id, id);
const measures = performance.getEntriesByName(id, "measure");
const measureObj = measures.length > 0 ?
measures[measures.length - 1] : null;
console.log("PROFILER:", measureObj);
performance.clearMarks(id);
if (clear) {
clearInterval(profile[id]);
delete profile[id];
processSamples();
}
}
};
}
const {console: console$1} = $(window);
const noop = () => {};
function log(...args) {
let {mark, end} = profile("log");
if (debug()) {
const logArgs = ["%c DEBUG", "font-weight: bold;"];
const isErrorIndex = args.indexOf("error");
const isWarnIndex = args.indexOf("warn");
const isSuccessIndex = args.indexOf("success");
const isInfoIndex = args.indexOf("info");
if (isErrorIndex !== -1) {
logArgs[0] += " - ERROR";
logArgs[1] += "color: red; border:2px solid red";
$(args).splice(isErrorIndex, 1);
}
else if (isWarnIndex !== -1) {
logArgs[0] += " - WARNING";
logArgs[1] += "color: orange; border:2px solid orange ";
$(args).splice(isWarnIndex, 1);
}
else if (isSuccessIndex !== -1) {
logArgs[0] += " - SUCCESS";
logArgs[1] += "color: green; border:2px solid green";
$(args).splice(isSuccessIndex, 1);
}
else if (isInfoIndex !== -1) {
logArgs[1] += "color: black;";
$(args).splice(isInfoIndex, 1);
}
$(args).unshift(...logArgs);
}
mark();
console$1.log(...args);
end();
}
function getDebugger(name) {
return bind(debug() ? log : noop, null, name);
}
let {Array, Error: Error$2, Map: Map$3, parseInt: parseInt$2} = $(window);
let stack = null;
let won = null;
function race(action, winners = "1") {
switch (action) {
case "start":
stack = {
winners: parseInt$2(winners, 10) || 1,
participants: new Map$3()
};
won = new Array();
break;
case "end":
case "finish":
case "stop":
stack = null;
for (let win of won)
win();
won = null;
break;
default:
throw new Error$2(`Invalid action: ${action}`);
}
}
function raceWinner(name, lose) {
if (stack === null)
return noop;
let current = stack;
let {participants} = current;
participants.set(win, lose);
return win;
function win() {
if (current.winners < 1)
return;
let debugLog = getDebugger("race");
debugLog("success", `${name} won the race`);
if (current === stack) {
won.push(win);
}
else {
participants.delete(win);
if (--current.winners < 1) {
for (let looser of participants.values())
looser();
participants.clear();
}
}
}
}
function hideIfContains(search, selector = "*", searchSelector = null) {
const formattedArguments = formatArguments(arguments);
const debugLog = getDebugger("hide-if-contains");
const {mark, end} = profile("hide-if-contains");
const onHideCallback = node => {
mark();
debugLog("success",
"Matched: ",
node,
"\nFILTER: hide-if-contains",
formattedArguments);
end();
};
let re = toRegExp(search);
const mo = hideIfMatches(element => re.test($(element).textContent),
selector,
searchSelector,
onHideCallback);
mo.race(raceWinner(
"hide-if-contains",
() => {
mo.disconnect();
}
));
}
const handler = {
get(target, name) {
const context = target;
while (!hasOwnProperty(target, name))
target = getPrototypeOf(target);
const {get, set} = getOwnPropertyDescriptor$2(target, name);
return function () {
return arguments.length ?
apply$2(set, context, arguments) :
call(get, context);
};
}
};
const accessor = target => new $$1(target, handler);
$(window);
accessor(window);
$(/^\d+$/);
function getPromiseFromEvent(item, event) {
return new Promise(
resolve => {
const listener = () => {
item.removeEventListener(event, listener);
resolve();
};
item.addEventListener(event, listener);
}
);
}
function waitUntilEvent(
debugLog,
mainLogic,
waitUntil) {
if (waitUntil) {
if (waitUntil === "load") {
debugLog("info", "Waiting until window.load");
window.addEventListener("load", () => {
debugLog("info", "Window.load fired.");
mainLogic();
});
}
else if (waitUntil === "loading" ||
waitUntil === "interactive" ||
waitUntil === "complete") {
debugLog("info", "Waiting document state until :", waitUntil);
document.addEventListener("readystatechange", () => {
debugLog("info", "Document state changed:", document.readyState);
if (document.readyState === waitUntil)
mainLogic();
});
}
else {
debugLog("info",
"Waiting until ",
waitUntil,
" event is triggered on document");
getPromiseFromEvent(document, waitUntil).then(() => {
debugLog("info",
waitUntil,
" is triggered on document, starting the snippet");
mainLogic();
}).catch(err => {
debugLog("error",
"There was an error while waiting for the event.",
err);
});
}
}
else {
mainLogic();
}
}
let {MutationObserver: MutationObserver$8, WeakSet: WeakSet$8, getComputedStyle: getComputedStyle$4} = $(window);
function hideIfContainsAndMatchesStyle(search,
selector = "*",
searchSelector = null,
style = null,
searchStyle = null,
waitUntil,
windowWidthMin = null,
windowWidthMax = null
) {
const formattedArguments = formatArguments(arguments);
const debugLog = getDebugger("hide-if-contains-and-matches-style");
const {mark, end} = profile("hide-if-contains-and-matches-style");
const hiddenMap = new WeakSet$8();
const logMap = debug() && new WeakSet$8();
if (searchSelector == null)
searchSelector = selector;
const searchRegExp = toRegExp(search);
const styleRegExp = style ? toRegExp(style) : null;
const searchStyleRegExp = searchStyle ? toRegExp(searchStyle) : null;
const mainLogic = () => {
const callback = () => {
mark();
if ((windowWidthMin && window.innerWidth < windowWidthMin) ||
(windowWidthMax && window.innerWidth > windowWidthMax)
)
return;
for (const {element, rootParents} of $$(searchSelector, true)) {
if (hiddenMap.has(element))
continue;
if (searchRegExp.test($(element).textContent)) {
if (!searchStyleRegExp ||
searchStyleRegExp.test(getComputedCSSText(element))) {
const closest = $closest($(element), selector, rootParents);
if (!closest)
continue;
if (!styleRegExp || styleRegExp.test(getComputedCSSText(closest))) {
win();
hideElement(closest);
hiddenMap.add(element);
debugLog("success",
"Matched: ",
closest,
"which contains: ",
element,
"\nFILTER: hide-if-contains-and-matches-style",
formattedArguments);
}
else {
if (!logMap || logMap.has(closest))
continue;
debugLog("info",
"In this element the searchStyle matched " +
"but style didn't:\n",
closest,
getComputedStyle$4(closest),
formattedArguments);
logMap.add(closest);
}
}
else {
if (!logMap || logMap.has(element))
continue;
debugLog("info",
"In this element the searchStyle didn't match:\n",
element,
getComputedStyle$4(element),
formattedArguments);
logMap.add(element);
}
}
}
end();
};
const mo = new MutationObserver$8(callback);
const win = raceWinner(
"hide-if-contains-and-matches-style",
() => mo.disconnect()
);
mo.observe(document, {childList: true, characterData: true, subtree: true});
callback();
};
waitUntilEvent(debugLog, mainLogic, waitUntil);
}
let {
clearTimeout,
fetch,
getComputedStyle: getComputedStyle$3,
setTimeout: setTimeout$2,
Map: Map$2,
MutationObserver: MutationObserver$7,
Uint8Array
} = $(window);
function hideIfContainsImage(search, selector, searchSelector) {
if (searchSelector == null)
searchSelector = selector;
let searchRegExp = toRegExp(search);
const formattedArguments = formatArguments(arguments);
const debugLog = getDebugger("hide-if-contains-image");
const {mark, end} = profile("hide-if-contains-image");
let callback = () => {
mark();
for (const {element, rootParents} of $$(searchSelector, true)) {
let style = getComputedStyle$3(element);
let match = $(style["background-image"]).match(/^url\("(.*)"\)$/);
if (match) {
fetchContent(match[1]).then(content => {
if (searchRegExp.test(uint8ArrayToHex(new Uint8Array(content)))) {
let closest = $closest($(element), selector, rootParents);
if (closest) {
win();
hideElement(closest);
debugLog("success",
"Matched: ",
closest,
"\nFILTER: hide-if-contains-image",
formattedArguments);
}
}
});
}
}
end();
};
let mo = new MutationObserver$7(callback);
let win = raceWinner(
"hide-if-contains-image",
() => mo.disconnect()
);
mo.observe(document, {childList: true, subtree: true});
callback();
}
let fetchContentMap = new Map$2();
function fetchContent(url, {as = "arrayBuffer", cleanup = 60000} = {}) {
let uid = as + ":" + url;
let details = fetchContentMap.get(uid) || {
remove: () => fetchContentMap.delete(uid),
result: null,
timer: 0
};
clearTimeout(details.timer);
details.timer = setTimeout$2(details.remove, cleanup);
if (!details.result) {
details.result = fetch(url).then(res => res[as]()).catch(details.remove);
fetchContentMap.set(uid, details);
}
return details.result;
}
function toHex(number, length = 2) {
let hex = $(number).toString(16);
if (hex.length < length)
hex = $("0").repeat(length - hex.length) + hex;
return hex;
}
function uint8ArrayToHex(uint8Array) {
return uint8Array.reduce((hex, byte) => hex + toHex(byte), "");
}
const {parseFloat: parseFloat$2, Math: Math$2, MutationObserver: MutationObserver$6, WeakSet: WeakSet$7} = $(window);
const {min} = Math$2;
const ld = (a, b) => {
const len1 = a.length + 1;
const len2 = b.length + 1;
const d = [[0]];
let i = 0;
let I = 0;
while (++i < len2)
d[0][i] = i;
i = 0;
while (++i < len1) {
const c = a[I];
let j = 0;
let J = 0;
d[i] = [i];
while (++j < len2) {
d[i][j] = min(d[I][j] + 1, d[i][J] + 1, d[I][J] + (c != b[J]));
++J;
}
++I;
}
return d[len1 - 1][len2 - 1];
};
function hideIfContainsSimilarText(
search, selector,
searchSelector = null,
ignoreChars = 0,
maxSearches = 0
) {
const visitedNodes = new WeakSet$7();
const formattedArguments = formatArguments(arguments);
const debugLog = getDebugger("hide-if-contains-similar-text");
const {mark, end} = profile("hide-if-contains-similar-text");
const $search = $(search);
const {length} = $search;
const chars = length + parseFloat$2(ignoreChars) || 0;
const find = $([...$search]).sort();
const guard = parseFloat$2(maxSearches) || Infinity;
if (searchSelector == null)
searchSelector = selector;
debugLog("info", "Looking for similar text: " + $search);
const callback = () => {
mark();
for (const {element, rootParents} of $$(searchSelector, true)) {
if (visitedNodes.has(element))
continue;
visitedNodes.add(element);
const {innerText} = $(element);
const loop = min(guard, innerText.length - chars + 1);
for (let i = 0; i < loop; i++) {
const str = $(innerText).substr(i, chars);
const distance = ld(find, $([...str]).sort()) - ignoreChars;
if (distance <= 0) {
const closest = $closest($(element), selector, rootParents);
debugLog("success",
"Found similar text: " + $search,
closest,
"\nFILTER: hide-if-contains-similar-text",
formattedArguments);
if (closest) {
win();
hideElement(closest);
break;
}
}
}
}
end();
};
let mo = new MutationObserver$6(callback);
let win = raceWinner(
"hide-if-contains-similar-text",
() => mo.disconnect()
);
mo.observe(document, {childList: true, characterData: true, subtree: true});
callback();
}
let {getComputedStyle: getComputedStyle$2, Map: Map$1, WeakSet: WeakSet$6, parseFloat: parseFloat$1, DOMMatrix, Math: Math$1} = $(window);
const {ELEMENT_NODE: ELEMENT_NODE$2, TEXT_NODE} = Node;
function hideIfContainsVisibleText(search, selector,
searchSelector = null,
...attributes) {
const {mark, end} = profile("hide-if-contains-visible-text");
const formattedArguments = formatArguments(arguments);
let entries = $([]);
const optionalParameters = new Map$1([
["-snippet-box-margin", "2"],
["-disable-bg-color-check", "false"],
["-check-is-contained", "false"],
["-pseudo-box-margin", "2"],
["-ignore-padding", "false"]
]);
for (let attr of attributes) {
attr = $(attr);
let markerIndex = attr.indexOf(":");
if (markerIndex < 0)
continue;
let key = attr.slice(0, markerIndex).trim().toString();
let value = attr.slice(markerIndex + 1).trim().toString();
if (key && value) {
if (optionalParameters.has(key))
optionalParameters.set(key, value);
else
entries.push([key, value]);
}
}
let defaultEntries = $([
["opacity", "0"],
["font-size", "0px"],
["color", "rgba(0, 0, 0, 0)"]
]);
let attributesMap = new Map$1(defaultEntries.concat(entries));
function isTextVisible(element,
style,
{bgColorCheck = true, pseudoElemCheck = false} = {}) {
if (!style)
style = getComputedStyle$2(element);
style = $(style);
for (const [key, value] of attributesMap) {
let valueAsRegex = toRegExp(value);
if (valueAsRegex.test(style.getPropertyValue(key)))
return false;
}
const color = style.getPropertyValue("color");
if (bgColorCheck && style.getPropertyValue("background-color") === color)
return false;
if (!pseudoElemCheck) {
const firstLineStyle = getComputedStyle$2(element, "::first-line");
if (firstLineStyle) {
return isTextVisible(element,
firstLineStyle,
{bgColorCheck, pseudoElemCheck: true});
}
}
const textShadow = style.getPropertyValue("text-shadow");
if (color.includes("rgba(0, 0, 0, 0)") &&
(textShadow === "none" ||
textShadow.includes("rgba(0, 0, 0, 0)"))
)
return false;
return true;
}
function getTransformMatrix(element, pseudo = null) {
const style = getComputedStyle$2(element, pseudo);
let transform = style.transform;
if (transform === "none")
transform = "matrix(1, 0, 0, 1, 0, 0)";
return new DOMMatrix(transform);
}
function getPseudoContent(element, pseudo, parentMatrix,
{bgColorCheck = true, translateThresh = 2} = {}) {
let style = getComputedStyle$2(element, pseudo);
if (!isVisible(element, style) ||
!isTextVisible(element, style, {bgColorCheck}))
return "";
let {content} = $(style);
if (content && content !== "none") {
let strings = $([]);
const domMatrix = getTransformMatrix(element, pseudo);
const resultMatrix = parentMatrix.multiply(domMatrix);
const angle = Math$1.atan2(resultMatrix.b, resultMatrix.a);
const angleDegrees = angle * (180 / Math$1.PI);
const rotated = Math$1.abs(angleDegrees) > 5;
if (rotated)
return "";
const translated = Math$1.abs(resultMatrix.e) > translateThresh ||
Math$1.abs(resultMatrix.f) > translateThresh;
if (translated)
return "";
content = $(content).trim().replace(
/(["'])(?:(?=(\\?))\2.)*?\1/g,
value => `\x01${strings.push($(value).slice(1, -1)) - 1}`
);
content = content.replace(
/\s*attr\(\s*([^\s,)]+)[^)]*?\)\s*/g,
(_, name) => $(element).getAttribute(name) || ""
);
return content.replace(
/\x01(\d+)/g,
(_, index) => strings[index]);
}
return "";
}
function isContained(childNode, parentNode, {
boxMargin = 2,
ignorePadding = false
} = {}) {
let child = $(childNode).getBoundingClientRect();
if (ignorePadding) {
const style = getComputedStyle$2(childNode);
const paddingTop = parseFloat$1(style.paddingTop) || 0;
const paddingRight = parseFloat$1(style.paddingRight) || 0;
const paddingBottom = parseFloat$1(style.paddingBottom) || 0;
const paddingLeft = parseFloat$1(style.paddingLeft) || 0;
child = {
left: child.left + paddingLeft,
right: child.right - paddingRight,
top: child.top + paddingTop,
bottom: child.bottom - paddingBottom
};
}
const parent = $(parentNode).getBoundingClientRect();
const stretchedParent = {
left: parent.left - boxMargin,
right: parent.right + boxMargin,
top: parent.top - boxMargin,
bottom: parent.bottom + boxMargin
};
return (
(stretchedParent.left <= child.left &&
child.left <= stretchedParent.right &&
stretchedParent.top <= child.top &&
child.top <= stretchedParent.bottom) &&
(stretchedParent.top <= child.bottom &&
child.bottom <= stretchedParent.bottom &&
stretchedParent.left <= child.right &&
child.right <= stretchedParent.right)
);
}
function getVisibleContent(element,
closest,
style,
parentOverflowNode,
originalElement,
shadowRootParents,
domMatrix,
{
boxMargin = 2,
bgColorCheck,
checkIsContained,
translateThresh
} = {}) {
let checkClosest = !style;
if (checkClosest)
style = getComputedStyle$2(element);
if (!isVisible(element, style, checkClosest && closest, shadowRootParents))
return "";
if (!parentOverflowNode &&
(
$(style).getPropertyValue("overflow-x") === "hidden" ||
$(style).getPropertyValue("overflow-y") === "hidden"
)
)
parentOverflowNode = element;
if (!domMatrix)
domMatrix = getTransformMatrix(element);
else
domMatrix = domMatrix.multiply(getTransformMatrix(element));
let text = getPseudoContent(element,
":before",
domMatrix,
{bgColorCheck, translateThresh});
for (let node of $childNodes($(element))) {
switch ($(node).nodeType) {
case ELEMENT_NODE$2:
text += getVisibleContent(node,
element,
getComputedStyle$2(node),
parentOverflowNode,
originalElement,
shadowRootParents,
domMatrix,
{
boxMargin,
bgColorCheck,
checkIsContained,
translateThresh
}
);
break;
case TEXT_NODE:
if (parentOverflowNode) {
if (isContained(element, parentOverflowNode, {
boxMargin,
ignorePadding
}) && isTextVisible(element, style, {bgColorCheck}))
text += $(node).nodeValue;
}
else if (isTextVisible(element, style, {bgColorCheck})) {
if (checkIsContained && !isContained(element, originalElement, {
boxMargin,
ignorePadding
}))
continue;
text += $(node).nodeValue;
}
break;
}
}
text += getPseudoContent(element,
":after",
domMatrix,
{bgColorCheck, translateThresh});
return text;
}
const boxMarginStr = optionalParameters.get("-snippet-box-margin");
const boxMargin = parseFloat$1(boxMarginStr) || 0;
const bgColorCheckStr = optionalParameters.get("-disable-bg-color-check");
const bgColorCheck = !(bgColorCheckStr === "true");
const checkIsContainedStr = optionalParameters.get("-check-is-contained");
const checkIsContained = (checkIsContainedStr === "true");
const ignorePaddingStr = optionalParameters.get("-ignore-padding");
const ignorePadding = (ignorePaddingStr === "true");
const translateThreshStr = optionalParameters.get("-pseudo-box-margin");
const translateThresh = parseFloat$1(translateThreshStr) || 0;
let re = toRegExp(search);
let seen = new WeakSet$6();
const mo = hideIfMatches(
(element, closest, rootParents) => {
mark();
if (seen.has(element))
return false;
seen.add(element);
let text = getVisibleContent(
element, closest, null, null, element, rootParents, null, {
boxMargin,
bgColorCheck,
checkIsContained,
translateThresh
}
);
let result = re.test(text);
if (debug() && text.length) {
result ?
log("success", result, re, text, "\nFILTER: hide-if-contains-visible-text", formattedArguments) :
log("info", result, re, text);
}
end();
return result;
},
selector,
searchSelector
);
mo.race(raceWinner(
"hide-if-contains-visible-text",
() => {
mo.disconnect();
}
));
}
let {MutationObserver: MutationObserver$5, WeakSet: WeakSet$5, getComputedStyle: getComputedStyle$1} = $(window);
function hideIfHasAndMatchesStyle(search,
selector = "*",
searchSelector = null,
style = null,
searchStyle = null,
waitUntil = null,
windowWidthMin = null,
windowWidthMax = null
) {
const formattedArguments = formatArguments(arguments);
const debugLog = getDebugger("hide-if-has-and-matches-style");
const {mark, end} = profile("hide-if-has-and-matches-style");
const hiddenMap = new WeakSet$5();
const logMap = debug() && new WeakSet$5();
if (searchSelector == null)
searchSelector = selector;
const styleRegExp = style ? toRegExp(style) : null;
const searchStyleRegExp = searchStyle ? toRegExp(searchStyle) : null;
const mainLogic = () => {
const callback = () => {
mark();
if ((windowWidthMin && window.innerWidth < windowWidthMin) ||
(windowWidthMax && window.innerWidth > windowWidthMax)
)
return;
for (const {element, rootParents} of $$(searchSelector, true)) {
if (hiddenMap.has(element))
continue;
if ($(element).querySelector(search) &&
(!searchStyleRegExp ||
searchStyleRegExp.test(getComputedCSSText(element)))) {
const closest = $closest($(element), selector, rootParents);
if (closest && (!styleRegExp ||
styleRegExp.test(getComputedCSSText(closest)))) {
win();
hideElement(closest);
hiddenMap.add(element);
debugLog("success",
"Matched: ",
closest,
"which contains: ",
element,
"\nFILTER: hide-if-has-and-matches-style",
formattedArguments);
}
else {
if (!logMap || logMap.has(closest))
continue;
debugLog("info",
"In this element the searchStyle matched" +
"but style didn't:\n",