mirror of
https://github.com/gorhill/uBlock.git
synced 2024-11-10 01:02:08 +01:00
[mv3] Refactor content scripts related to specific cosmetic filtering
Specifically, avoid long list of hostnames for the `matches` property[1] when registering the content scripts, as this was causing whole browser freeze for long seconds in Chromium-based browsers (reason unknown). The content scripts themselves will sort out which cosmetic filters to apply on which websites. This change makes it now possible to support annoyances-related lists, and thus two lists have been added: - EasyList -- Annoyances - EasyList -- Cookies Related issue: - https://github.com/uBlockOrigin/uBOL-issues/issues/5 These annoyances-related lists contains many thousands of specific cosmetic filters and as a result, before the above change this was causing long seconds of whole browser freeze when simply modifying the blocking mode of a specific site via the slider in the popup panel. It is now virtually instantaneous, at the cost of injecting larger cosmetic filtering-related content scripts (which typically should be garbage-collected within single-digit milliseconds). Also, added support for entity-based cosmetic filters. (They were previously discarded). --- [1] https://developer.mozilla.org/en-US/docs/Mozilla/Add-ons/WebExtensions/API/scripting/RegisteredContentScript
This commit is contained in:
parent
ec230be331
commit
72726a4759
14 changed files with 567 additions and 761 deletions
|
@ -307,9 +307,14 @@ async function init() {
|
|||
ruleCount += rules.removeparam + rules.redirect + rules.csp;
|
||||
}
|
||||
let specificCount = 0;
|
||||
if ( css.specific instanceof Object ) {
|
||||
specificCount += css.specific.domainBased;
|
||||
specificCount += css.specific.entityBased;
|
||||
if ( typeof css.specific === 'number' ) {
|
||||
specificCount += css.specific;
|
||||
}
|
||||
if ( typeof css.declarative === 'number' ) {
|
||||
specificCount += css.declarative;
|
||||
}
|
||||
if ( typeof css.procedural === 'number' ) {
|
||||
specificCount += css.procedural;
|
||||
}
|
||||
dom.text(
|
||||
qs$(div, 'p'),
|
||||
|
|
|
@ -394,10 +394,10 @@ async function updateCspRules() {
|
|||
if ( addRules.length === 0 && removeRuleIds.length === 0 ) { return; }
|
||||
|
||||
if ( removeRuleIds.length !== 0 ) {
|
||||
console.info(`Remove ${removeRuleIds.length} DNR redirect rules`);
|
||||
console.info(`Remove ${removeRuleIds.length} DNR csp rules`);
|
||||
}
|
||||
if ( addRules.length !== 0 ) {
|
||||
console.info(`Add ${addRules.length} DNR redirect rules`);
|
||||
console.info(`Add ${addRules.length} DNR csp rules`);
|
||||
}
|
||||
|
||||
return dnr.updateDynamicRules({ addRules, removeRuleIds });
|
||||
|
|
|
@ -38,40 +38,6 @@ const isGecko = browser.runtime.getURL('').startsWith('moz-extension://');
|
|||
|
||||
const resourceDetailPromises = new Map();
|
||||
|
||||
function getSpecificDetails() {
|
||||
let promise = resourceDetailPromises.get('specific');
|
||||
if ( promise !== undefined ) { return promise; }
|
||||
promise = fetchJSON('/rulesets/specific-details').then(entries => {
|
||||
const out = new Map();
|
||||
for ( const entry of entries ) {
|
||||
out.set(entry[0], new Map(entry[1]));
|
||||
}
|
||||
return out;
|
||||
});
|
||||
resourceDetailPromises.set('specific', promise);
|
||||
return promise;
|
||||
}
|
||||
|
||||
function getDeclarativeDetails() {
|
||||
let promise = resourceDetailPromises.get('declarative');
|
||||
if ( promise !== undefined ) { return promise; }
|
||||
promise = fetchJSON('/rulesets/declarative-details').then(
|
||||
entries => new Map(entries)
|
||||
);
|
||||
resourceDetailPromises.set('declarative', promise);
|
||||
return promise;
|
||||
}
|
||||
|
||||
function getProceduralDetails() {
|
||||
let promise = resourceDetailPromises.get('procedural');
|
||||
if ( promise !== undefined ) { return promise; }
|
||||
promise = fetchJSON('/rulesets/procedural-details').then(
|
||||
entries => new Map(entries)
|
||||
);
|
||||
resourceDetailPromises.set('procedural', promise);
|
||||
return promise;
|
||||
}
|
||||
|
||||
function getScriptletDetails() {
|
||||
let promise = resourceDetailPromises.get('scriptlet');
|
||||
if ( promise !== undefined ) { return promise; }
|
||||
|
@ -135,8 +101,8 @@ function registerGeneric(context, genericDetails) {
|
|||
if ( hostnames !== undefined ) {
|
||||
excludeHostnames.push(...hostnames);
|
||||
}
|
||||
if ( details.css.generic instanceof Object === false ) { continue; }
|
||||
if ( details.css.generic.count === 0 ) { continue; }
|
||||
const count = details.css?.generic || 0;
|
||||
if ( count === 0 ) { continue; }
|
||||
js.push(`/rulesets/scripting/generic/${details.id}.js`);
|
||||
}
|
||||
|
||||
|
@ -144,19 +110,20 @@ function registerGeneric(context, genericDetails) {
|
|||
|
||||
js.push('/js/scripting/css-generic.js');
|
||||
|
||||
const { none, network, extendedSpecific, extendedGeneric } = filteringModeDetails;
|
||||
const matches = [];
|
||||
const excludeMatches = [];
|
||||
if ( filteringModeDetails.extendedGeneric.has('all-urls') ) {
|
||||
excludeMatches.push(...ut.matchesFromHostnames(filteringModeDetails.none));
|
||||
excludeMatches.push(...ut.matchesFromHostnames(filteringModeDetails.network));
|
||||
excludeMatches.push(...ut.matchesFromHostnames(filteringModeDetails.extendedSpecific));
|
||||
if ( extendedGeneric.has('all-urls') ) {
|
||||
excludeMatches.push(...ut.matchesFromHostnames(none));
|
||||
excludeMatches.push(...ut.matchesFromHostnames(network));
|
||||
excludeMatches.push(...ut.matchesFromHostnames(extendedSpecific));
|
||||
excludeMatches.push(...ut.matchesFromHostnames(excludeHostnames));
|
||||
matches.push('<all_urls>');
|
||||
} else {
|
||||
matches.push(
|
||||
...ut.matchesFromHostnames(
|
||||
ut.subtractHostnameIters(
|
||||
Array.from(filteringModeDetails.extendedGeneric),
|
||||
Array.from(extendedGeneric),
|
||||
excludeHostnames
|
||||
)
|
||||
)
|
||||
|
@ -198,50 +165,33 @@ function registerGeneric(context, genericDetails) {
|
|||
|
||||
/******************************************************************************/
|
||||
|
||||
function registerProcedural(context, proceduralDetails) {
|
||||
function registerProcedural(context) {
|
||||
const { before, filteringModeDetails, rulesetsDetails } = context;
|
||||
|
||||
const js = [];
|
||||
const hostnameMatches = new Set();
|
||||
for ( const details of rulesetsDetails ) {
|
||||
if ( details.css.procedural === 0 ) { continue; }
|
||||
js.push(`/rulesets/scripting/procedural/${details.id}.js`);
|
||||
if ( proceduralDetails.has(details.id) ) {
|
||||
for ( const hn of proceduralDetails.get(details.id) ) {
|
||||
hostnameMatches.add(hn);
|
||||
}
|
||||
}
|
||||
for ( const rulesetDetails of rulesetsDetails ) {
|
||||
const count = rulesetDetails.css?.procedural || 0;
|
||||
if ( count === 0 ) { continue; }
|
||||
js.push(`/rulesets/scripting/procedural/${rulesetDetails.id}.js`);
|
||||
}
|
||||
|
||||
if ( js.length === 0 ) { return; }
|
||||
|
||||
const { none, network, extendedSpecific, extendedGeneric } = filteringModeDetails;
|
||||
const matches = [
|
||||
...ut.matchesFromHostnames(extendedSpecific),
|
||||
...ut.matchesFromHostnames(extendedGeneric),
|
||||
];
|
||||
if ( matches.length === 0 ) { return; }
|
||||
|
||||
js.push('/js/scripting/css-procedural.js');
|
||||
|
||||
const {
|
||||
none,
|
||||
network,
|
||||
extendedSpecific,
|
||||
extendedGeneric,
|
||||
} = filteringModeDetails;
|
||||
|
||||
const matches = [];
|
||||
const excludeMatches = [];
|
||||
if ( extendedSpecific.has('all-urls') || extendedGeneric.has('all-urls') ) {
|
||||
if ( none.has('all-urls') === false ) {
|
||||
excludeMatches.push(...ut.matchesFromHostnames(none));
|
||||
excludeMatches.push(...ut.matchesFromHostnames(network));
|
||||
matches.push(...ut.matchesFromHostnames(hostnameMatches));
|
||||
} else if ( extendedSpecific.size !== 0 || extendedGeneric.size !== 0 ) {
|
||||
matches.push(
|
||||
...ut.matchesFromHostnames(
|
||||
ut.intersectHostnameIters(
|
||||
[ ...extendedSpecific, ...extendedGeneric ],
|
||||
hostnameMatches
|
||||
)
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
if ( matches.length === 0 ) { return; }
|
||||
if ( network.has('all-urls') === false ) {
|
||||
excludeMatches.push(...ut.matchesFromHostnames(network));
|
||||
}
|
||||
|
||||
const registered = before.get('css-procedural');
|
||||
before.delete('css-procedural'); // Important!
|
||||
|
@ -277,48 +227,33 @@ function registerProcedural(context, proceduralDetails) {
|
|||
|
||||
/******************************************************************************/
|
||||
|
||||
function registerDeclarative(context, declarativeDetails) {
|
||||
function registerDeclarative(context) {
|
||||
const { before, filteringModeDetails, rulesetsDetails } = context;
|
||||
|
||||
const js = [];
|
||||
const hostnameMatches = [];
|
||||
for ( const details of rulesetsDetails ) {
|
||||
if ( details.css.declarative === 0 ) { continue; }
|
||||
js.push(`/rulesets/scripting/declarative/${details.id}.js`);
|
||||
if ( declarativeDetails.has(details.id) ) {
|
||||
hostnameMatches.push(...declarativeDetails.get(details.id));
|
||||
}
|
||||
for ( const rulesetDetails of rulesetsDetails ) {
|
||||
const count = rulesetDetails.css?.declarative || 0;
|
||||
if ( count === 0 ) { continue; }
|
||||
js.push(`/rulesets/scripting/declarative/${rulesetDetails.id}.js`);
|
||||
}
|
||||
|
||||
if ( js.length === 0 ) { return; }
|
||||
|
||||
const { none, network, extendedSpecific, extendedGeneric } = filteringModeDetails;
|
||||
const matches = [
|
||||
...ut.matchesFromHostnames(extendedSpecific),
|
||||
...ut.matchesFromHostnames(extendedGeneric),
|
||||
];
|
||||
if ( matches.length === 0 ) { return; }
|
||||
|
||||
js.push('/js/scripting/css-declarative.js');
|
||||
|
||||
const {
|
||||
none,
|
||||
network,
|
||||
extendedSpecific,
|
||||
extendedGeneric,
|
||||
} = filteringModeDetails;
|
||||
|
||||
const matches = [];
|
||||
const excludeMatches = [];
|
||||
if ( extendedSpecific.has('all-urls') || extendedGeneric.has('all-urls') ) {
|
||||
if ( none.has('all-urls') === false ) {
|
||||
excludeMatches.push(...ut.matchesFromHostnames(none));
|
||||
excludeMatches.push(...ut.matchesFromHostnames(network));
|
||||
matches.push(...ut.matchesFromHostnames(hostnameMatches));
|
||||
} else if ( extendedSpecific.size !== 0 || extendedGeneric.size !== 0 ) {
|
||||
matches.push(
|
||||
...ut.matchesFromHostnames(
|
||||
ut.intersectHostnameIters(
|
||||
[ ...extendedSpecific, ...extendedGeneric ],
|
||||
hostnameMatches
|
||||
)
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
if ( matches.length === 0 ) { return; }
|
||||
if ( network.has('all-urls') === false ) {
|
||||
excludeMatches.push(...ut.matchesFromHostnames(network));
|
||||
}
|
||||
|
||||
const registered = before.get('css-declarative');
|
||||
before.delete('css-declarative'); // Important!
|
||||
|
@ -354,6 +289,68 @@ function registerDeclarative(context, declarativeDetails) {
|
|||
|
||||
/******************************************************************************/
|
||||
|
||||
function registerSpecific(context) {
|
||||
const { before, filteringModeDetails, rulesetsDetails } = context;
|
||||
|
||||
const js = [];
|
||||
for ( const rulesetDetails of rulesetsDetails ) {
|
||||
const count = rulesetDetails.css?.specific || 0;
|
||||
if ( count === 0 ) { continue; }
|
||||
js.push(`/rulesets/scripting/specific/${rulesetDetails.id}.js`);
|
||||
}
|
||||
if ( js.length === 0 ) { return; }
|
||||
|
||||
const { none, network, extendedSpecific, extendedGeneric } = filteringModeDetails;
|
||||
const matches = [
|
||||
...ut.matchesFromHostnames(extendedSpecific),
|
||||
...ut.matchesFromHostnames(extendedGeneric),
|
||||
];
|
||||
if ( matches.length === 0 ) { return; }
|
||||
|
||||
js.push('/js/scripting/css-specific.js');
|
||||
|
||||
const excludeMatches = [];
|
||||
if ( none.has('all-urls') === false ) {
|
||||
excludeMatches.push(...ut.matchesFromHostnames(none));
|
||||
}
|
||||
if ( network.has('all-urls') === false ) {
|
||||
excludeMatches.push(...ut.matchesFromHostnames(network));
|
||||
}
|
||||
|
||||
const registered = before.get('css-specific');
|
||||
before.delete('css-specific'); // Important!
|
||||
|
||||
// register
|
||||
if ( registered === undefined ) {
|
||||
context.toAdd.push({
|
||||
id: 'css-specific',
|
||||
js,
|
||||
allFrames: true,
|
||||
matches,
|
||||
excludeMatches,
|
||||
runAt: 'document_start',
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
// update
|
||||
const directive = { id: 'css-specific' };
|
||||
if ( arrayEq(registered.js, js, false) === false ) {
|
||||
directive.js = js;
|
||||
}
|
||||
if ( arrayEq(registered.matches, matches) === false ) {
|
||||
directive.matches = matches;
|
||||
}
|
||||
if ( arrayEq(registered.excludeMatches, excludeMatches) === false ) {
|
||||
directive.excludeMatches = excludeMatches;
|
||||
}
|
||||
if ( directive.js || directive.matches || directive.excludeMatches ) {
|
||||
context.toUpdate.push(directive);
|
||||
}
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
function registerScriptlet(context, scriptletDetails) {
|
||||
// https://bugzilla.mozilla.org/show_bug.cgi?id=1736575
|
||||
// `MAIN` world not yet supported in Firefox
|
||||
|
@ -432,210 +429,6 @@ function registerScriptlet(context, scriptletDetails) {
|
|||
|
||||
/******************************************************************************/
|
||||
|
||||
function registerSpecific(context, specificDetails) {
|
||||
const { filteringModeDetails } = context;
|
||||
|
||||
let toRegisterMap;
|
||||
if (
|
||||
filteringModeDetails.extendedSpecific.has('all-urls') ||
|
||||
filteringModeDetails.extendedGeneric.has('all-urls')
|
||||
) {
|
||||
toRegisterMap = registerSpecificAll(context, specificDetails);
|
||||
} else {
|
||||
toRegisterMap = registerSpecificSome(context, specificDetails);
|
||||
}
|
||||
|
||||
for ( const [ fname, hostnames ] of toRegisterMap ) {
|
||||
toRegisterableScript(context, fname, hostnames);
|
||||
}
|
||||
}
|
||||
|
||||
function registerSpecificSome(context, specificDetails) {
|
||||
const { filteringModeDetails, rulesetsDetails } = context;
|
||||
const toRegisterMap = new Map();
|
||||
|
||||
const targetHostnames = [
|
||||
...filteringModeDetails.extendedSpecific,
|
||||
...filteringModeDetails.extendedGeneric,
|
||||
];
|
||||
|
||||
const checkMatches = (hostnamesToFidsMap, hn) => {
|
||||
let fids = hostnamesToFidsMap.get(hn);
|
||||
if ( fids === undefined ) { return; }
|
||||
if ( typeof fids === 'number' ) { fids = [ fids ]; }
|
||||
for ( const fid of fids ) {
|
||||
const fname = ut.fnameFromFileId(fid);
|
||||
let existing = toRegisterMap.get(fname);
|
||||
if ( existing ) {
|
||||
if ( existing[0] === '*' ) { continue; }
|
||||
existing.push(hn);
|
||||
} else {
|
||||
toRegisterMap.set(fname, existing = [ hn ]);
|
||||
}
|
||||
if ( hn !== '*' ) { continue; }
|
||||
existing.length = 0;
|
||||
existing.push('*');
|
||||
break;
|
||||
}
|
||||
};
|
||||
|
||||
for ( const rulesetDetails of rulesetsDetails ) {
|
||||
const hostnamesToFidsMap = specificDetails.get(rulesetDetails.id);
|
||||
if ( hostnamesToFidsMap === undefined ) { continue; }
|
||||
for ( let hn of targetHostnames ) {
|
||||
while ( hn ) {
|
||||
checkMatches(hostnamesToFidsMap, hn);
|
||||
hn = ut.toBroaderHostname(hn);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return toRegisterMap;
|
||||
}
|
||||
|
||||
function registerSpecificAll(context, specificDetails) {
|
||||
const { filteringModeDetails, rulesetsDetails } = context;
|
||||
const toRegisterMap = new Map();
|
||||
|
||||
const excludeSet = new Set([
|
||||
...filteringModeDetails.network,
|
||||
...filteringModeDetails.none,
|
||||
]);
|
||||
|
||||
for ( const rulesetDetails of rulesetsDetails ) {
|
||||
const hostnamesToFidsMap = specificDetails.get(rulesetDetails.id);
|
||||
if ( hostnamesToFidsMap === undefined ) { continue; }
|
||||
for ( let [ hn, fids ] of hostnamesToFidsMap ) {
|
||||
if ( excludeSet.has(hn) ) { continue; }
|
||||
if ( ut.isDescendantHostnameOfIter(hn, excludeSet) ) { continue; }
|
||||
if ( typeof fids === 'number' ) { fids = [ fids ]; }
|
||||
for ( const fid of fids ) {
|
||||
const fname = ut.fnameFromFileId(fid);
|
||||
let existing = toRegisterMap.get(fname);
|
||||
if ( existing ) {
|
||||
if ( existing[0] === '*' ) { continue; }
|
||||
existing.push(hn);
|
||||
} else {
|
||||
toRegisterMap.set(fname, existing = [ hn ]);
|
||||
}
|
||||
if ( hn !== '*' ) { continue; }
|
||||
existing.length = 0;
|
||||
existing.push('*');
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return toRegisterMap;
|
||||
}
|
||||
|
||||
const toRegisterableScript = (context, fname, hostnames) => {
|
||||
if ( context.before.has(fname) ) {
|
||||
return toUpdatableScript(context, fname, hostnames);
|
||||
}
|
||||
const matches = hostnames
|
||||
? ut.matchesFromHostnames(hostnames)
|
||||
: [ '<all_urls>' ];
|
||||
const excludeMatches = matches.length === 1 && matches[0] === '<all_urls>'
|
||||
? ut.matchesFromHostnames(context.filteringModeDetails.none)
|
||||
: [];
|
||||
const directive = {
|
||||
id: fname,
|
||||
allFrames: true,
|
||||
matches,
|
||||
excludeMatches,
|
||||
js: [ `/rulesets/scripting/specific/${fname.slice(-1)}/${fname.slice(0,-1)}.js` ],
|
||||
runAt: 'document_start',
|
||||
};
|
||||
context.toAdd.push(directive);
|
||||
};
|
||||
|
||||
const toUpdatableScript = (context, fname, hostnames) => {
|
||||
const registered = context.before.get(fname);
|
||||
context.before.delete(fname); // Important!
|
||||
const directive = { id: fname };
|
||||
const matches = hostnames
|
||||
? ut.matchesFromHostnames(hostnames)
|
||||
: [ '<all_urls>' ];
|
||||
if ( arrayEq(registered.matches, matches) === false ) {
|
||||
directive.matches = matches;
|
||||
}
|
||||
const excludeMatches = matches.length === 1 && matches[0] === '<all_urls>'
|
||||
? ut.matchesFromHostnames(context.filteringModeDetails.none)
|
||||
: [];
|
||||
if ( arrayEq(registered.excludeMatches, excludeMatches) === false ) {
|
||||
directive.excludeMatches = excludeMatches;
|
||||
}
|
||||
if ( directive.matches || directive.excludeMatches ) {
|
||||
context.toUpdate.push(directive);
|
||||
}
|
||||
};
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
function registerSpecificEntity(context) {
|
||||
const { before, filteringModeDetails, rulesetsDetails } = context;
|
||||
|
||||
const js = [];
|
||||
for ( const details of rulesetsDetails ) {
|
||||
if ( details.css.specific instanceof Object === false ) { continue; }
|
||||
if ( details.css.specific.entityBased === 0 ) { continue; }
|
||||
js.push(`/rulesets/scripting/specific-entity/${details.id}.js`);
|
||||
}
|
||||
|
||||
if ( js.length === 0 ) { return; }
|
||||
|
||||
const matches = [];
|
||||
const excludeMatches = [];
|
||||
if ( filteringModeDetails.extendedGeneric.has('all-urls') ) {
|
||||
excludeMatches.push(...ut.matchesFromHostnames(filteringModeDetails.none));
|
||||
excludeMatches.push(...ut.matchesFromHostnames(filteringModeDetails.network));
|
||||
excludeMatches.push(...ut.matchesFromHostnames(filteringModeDetails.extendedSpecific));
|
||||
matches.push('<all_urls>');
|
||||
} else {
|
||||
matches.push(
|
||||
...ut.matchesFromHostnames(filteringModeDetails.extendedGeneric)
|
||||
);
|
||||
}
|
||||
|
||||
if ( matches.length === 0 ) { return; }
|
||||
|
||||
js.push('/js/scripting/css-specific.entity.js');
|
||||
|
||||
const registered = before.get('css-specific.entity');
|
||||
before.delete('css-specific.entity'); // Important!
|
||||
|
||||
// register
|
||||
if ( registered === undefined ) {
|
||||
context.toAdd.push({
|
||||
id: 'css-specific.entity',
|
||||
js,
|
||||
allFrames: true,
|
||||
matches,
|
||||
excludeMatches,
|
||||
runAt: 'document_start',
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
// update
|
||||
const directive = { id: 'css-specific.entity' };
|
||||
if ( arrayEq(registered.js, js, false) === false ) {
|
||||
directive.js = js;
|
||||
}
|
||||
if ( arrayEq(registered.matches, matches) === false ) {
|
||||
directive.matches = matches;
|
||||
}
|
||||
if ( arrayEq(registered.excludeMatches, excludeMatches) === false ) {
|
||||
directive.excludeMatches = excludeMatches;
|
||||
}
|
||||
if ( directive.js || directive.matches || directive.excludeMatches ) {
|
||||
context.toUpdate.push(directive);
|
||||
}
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
async function registerInjectables(origins) {
|
||||
void origins;
|
||||
|
||||
|
@ -644,19 +437,13 @@ async function registerInjectables(origins) {
|
|||
const [
|
||||
filteringModeDetails,
|
||||
rulesetsDetails,
|
||||
declarativeDetails,
|
||||
proceduralDetails,
|
||||
scriptletDetails,
|
||||
specificDetails,
|
||||
genericDetails,
|
||||
registered,
|
||||
] = await Promise.all([
|
||||
getFilteringModeDetails(),
|
||||
getEnabledRulesetsDetails(),
|
||||
getDeclarativeDetails(),
|
||||
getProceduralDetails(),
|
||||
getScriptletDetails(),
|
||||
getSpecificDetails(),
|
||||
getGenericDetails(),
|
||||
browser.scripting.getRegisteredContentScripts(),
|
||||
]);
|
||||
|
@ -676,11 +463,10 @@ async function registerInjectables(origins) {
|
|||
toRemove,
|
||||
};
|
||||
|
||||
registerDeclarative(context, declarativeDetails);
|
||||
registerProcedural(context, proceduralDetails);
|
||||
registerDeclarative(context);
|
||||
registerProcedural(context);
|
||||
registerScriptlet(context, scriptletDetails);
|
||||
registerSpecific(context, specificDetails);
|
||||
registerSpecificEntity(context);
|
||||
registerSpecific(context);
|
||||
registerGeneric(context, genericDetails);
|
||||
|
||||
toRemove.push(...Array.from(before.keys()));
|
||||
|
|
|
@ -32,41 +32,77 @@
|
|||
/******************************************************************************/
|
||||
|
||||
const declarativeImports = self.declarativeImports || [];
|
||||
self.declarativeImports = undefined;
|
||||
delete self.declarativeImports;
|
||||
|
||||
const lookupSelectors = (hn, out) => {
|
||||
for ( const { argsList, hostnamesMap } of declarativeImports ) {
|
||||
let argsIndices = hostnamesMap.get(hn);
|
||||
if ( argsIndices === undefined ) { continue; }
|
||||
if ( typeof argsIndices === 'number' ) { argsIndices = [ argsIndices ]; }
|
||||
for ( const argsIndex of argsIndices ) {
|
||||
const details = argsList[argsIndex];
|
||||
if ( details.n && details.n.includes(hn) ) { continue; }
|
||||
out.push(...details.a.map(json => JSON.parse(json)));
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
let hn;
|
||||
try { hn = document.location.hostname; } catch(ex) { }
|
||||
const selectors = [];
|
||||
while ( hn ) {
|
||||
lookupSelectors(hn, selectors);
|
||||
if ( hn === '*' ) { break; }
|
||||
const pos = hn.indexOf('.');
|
||||
if ( pos !== -1 ) {
|
||||
hn = hn.slice(pos + 1);
|
||||
} else {
|
||||
hn = '*';
|
||||
}
|
||||
}
|
||||
|
||||
declarativeImports.length = 0;
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
const hnParts = [];
|
||||
try { hnParts.push(...document.location.hostname.split('.')); }
|
||||
catch(ex) { }
|
||||
const hnpartslen = hnParts.length;
|
||||
if ( hnpartslen === 0 ) { return; }
|
||||
|
||||
const selectors = [];
|
||||
|
||||
for ( const { argsList, exceptionsMap, hostnamesMap, entitiesMap } of declarativeImports ) {
|
||||
const todoIndices = new Set();
|
||||
const tonotdoIndices = [];
|
||||
// Exceptions
|
||||
if ( exceptionsMap.size !== 0 ) {
|
||||
for ( let i = 0; i < hnpartslen; i++ ) {
|
||||
const hn = hnParts.slice(i).join('.');
|
||||
const excepted = exceptionsMap.get(hn);
|
||||
if ( excepted ) { tonotdoIndices.push(...excepted); }
|
||||
}
|
||||
exceptionsMap.clear();
|
||||
}
|
||||
// Hostname-based
|
||||
if ( hostnamesMap.size !== 0 ) {
|
||||
const collectArgIndices = hn => {
|
||||
let argsIndices = hostnamesMap.get(hn);
|
||||
if ( argsIndices === undefined ) { return; }
|
||||
if ( typeof argsIndices === 'number' ) { argsIndices = [ argsIndices ]; }
|
||||
for ( const argsIndex of argsIndices ) {
|
||||
if ( tonotdoIndices.includes(argsIndex) ) { continue; }
|
||||
todoIndices.add(argsIndex);
|
||||
}
|
||||
};
|
||||
for ( let i = 0; i < hnpartslen; i++ ) {
|
||||
const hn = hnParts.slice(i).join('.');
|
||||
collectArgIndices(hn);
|
||||
}
|
||||
collectArgIndices('*');
|
||||
hostnamesMap.clear();
|
||||
}
|
||||
// Entity-based
|
||||
if ( entitiesMap.size !== 0 ) {
|
||||
const n = hnpartslen - 1;
|
||||
for ( let i = 0; i < n; i++ ) {
|
||||
for ( let j = n; j > i; j-- ) {
|
||||
const en = hnParts.slice(i,j).join('.');
|
||||
let argsIndices = entitiesMap.get(en);
|
||||
if ( argsIndices === undefined ) { continue; }
|
||||
if ( typeof argsIndices === 'number' ) { argsIndices = [ argsIndices ]; }
|
||||
for ( const argsIndex of argsIndices ) {
|
||||
if ( tonotdoIndices.includes(argsIndex) ) { continue; }
|
||||
todoIndices.add(argsIndex);
|
||||
}
|
||||
}
|
||||
}
|
||||
entitiesMap.clear();
|
||||
}
|
||||
for ( const i of todoIndices ) {
|
||||
selectors.push(...argsList[i].map(json => JSON.parse(json)));
|
||||
}
|
||||
argsList.length = 0;
|
||||
}
|
||||
declarativeImports.length = 0;
|
||||
|
||||
if ( selectors.length === 0 ) { return; }
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
const cssRuleFromProcedural = details => {
|
||||
const { tasks, action } = details;
|
||||
let mq;
|
||||
|
@ -114,3 +150,5 @@ try {
|
|||
})();
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
void 0;
|
||||
|
|
|
@ -31,7 +31,75 @@
|
|||
|
||||
/******************************************************************************/
|
||||
|
||||
let proceduralFilterer;
|
||||
const proceduralImports = self.proceduralImports || [];
|
||||
self.proceduralImports = undefined;
|
||||
delete self.proceduralImports;
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
const hnParts = [];
|
||||
try { hnParts.push(...document.location.hostname.split('.')); }
|
||||
catch(ex) { }
|
||||
const hnpartslen = hnParts.length;
|
||||
if ( hnpartslen === 0 ) { return; }
|
||||
|
||||
const selectors = [];
|
||||
|
||||
for ( const { argsList, exceptionsMap, hostnamesMap, entitiesMap } of proceduralImports ) {
|
||||
const todoIndices = new Set();
|
||||
const tonotdoIndices = [];
|
||||
// Exceptions
|
||||
if ( exceptionsMap.size !== 0 ) {
|
||||
for ( let i = 0; i < hnpartslen; i++ ) {
|
||||
const hn = hnParts.slice(i).join('.');
|
||||
const excepted = exceptionsMap.get(hn);
|
||||
if ( excepted ) { tonotdoIndices.push(...excepted); }
|
||||
}
|
||||
exceptionsMap.clear();
|
||||
}
|
||||
// Hostname-based
|
||||
if ( hostnamesMap.size !== 0 ) {
|
||||
const collectArgIndices = hn => {
|
||||
let argsIndices = hostnamesMap.get(hn);
|
||||
if ( argsIndices === undefined ) { return; }
|
||||
if ( typeof argsIndices === 'number' ) { argsIndices = [ argsIndices ]; }
|
||||
for ( const argsIndex of argsIndices ) {
|
||||
if ( tonotdoIndices.includes(argsIndex) ) { continue; }
|
||||
todoIndices.add(argsIndex);
|
||||
}
|
||||
};
|
||||
for ( let i = 0; i < hnpartslen; i++ ) {
|
||||
const hn = hnParts.slice(i).join('.');
|
||||
collectArgIndices(hn);
|
||||
}
|
||||
collectArgIndices('*');
|
||||
hostnamesMap.clear();
|
||||
}
|
||||
// Entity-based
|
||||
if ( entitiesMap.size !== 0 ) {
|
||||
const n = hnpartslen - 1;
|
||||
for ( let i = 0; i < n; i++ ) {
|
||||
for ( let j = n; j > i; j-- ) {
|
||||
const en = hnParts.slice(i,j).join('.');
|
||||
let argsIndices = entitiesMap.get(en);
|
||||
if ( argsIndices === undefined ) { continue; }
|
||||
if ( typeof argsIndices === 'number' ) { argsIndices = [ argsIndices ]; }
|
||||
for ( const argsIndex of argsIndices ) {
|
||||
if ( tonotdoIndices.includes(argsIndex) ) { continue; }
|
||||
todoIndices.add(argsIndex);
|
||||
}
|
||||
}
|
||||
}
|
||||
entitiesMap.clear();
|
||||
}
|
||||
for ( const i of todoIndices ) {
|
||||
selectors.push(...argsList[i].map(json => JSON.parse(json)));
|
||||
}
|
||||
argsList.length = 0;
|
||||
}
|
||||
proceduralImports.length = 0;
|
||||
|
||||
if ( selectors.length === 0 ) { return; }
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
|
@ -658,43 +726,7 @@ class ProceduralFilterer {
|
|||
|
||||
/******************************************************************************/
|
||||
|
||||
const proceduralImports = self.proceduralImports || [];
|
||||
delete self.proceduralImports;
|
||||
|
||||
const lookupSelectors = (hn, out) => {
|
||||
for ( const { argsList, hostnamesMap } of proceduralImports ) {
|
||||
let argsIndices = hostnamesMap.get(hn);
|
||||
if ( argsIndices === undefined ) { continue; }
|
||||
if ( typeof argsIndices === 'number' ) { argsIndices = [ argsIndices ]; }
|
||||
for ( const argsIndex of argsIndices ) {
|
||||
const details = argsList[argsIndex];
|
||||
if ( details.n && details.n.includes(hn) ) { continue; }
|
||||
out.push(...details.a.map(json => JSON.parse(json)));
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
let hn;
|
||||
try { hn = document.location.hostname; } catch(ex) { }
|
||||
const selectors = [];
|
||||
while ( hn ) {
|
||||
lookupSelectors(hn, selectors);
|
||||
if ( hn === '*' ) { break; }
|
||||
const pos = hn.indexOf('.');
|
||||
if ( pos !== -1 ) {
|
||||
hn = hn.slice(pos + 1);
|
||||
} else {
|
||||
hn = '*';
|
||||
}
|
||||
}
|
||||
|
||||
proceduralImports.length = 0;
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
if ( selectors.length === 0 ) { return; }
|
||||
|
||||
proceduralFilterer = new ProceduralFilterer(selectors);
|
||||
const proceduralFilterer = new ProceduralFilterer(selectors);
|
||||
|
||||
const observer = new MutationObserver(mutations => {
|
||||
let domChanged = false;
|
||||
|
@ -727,3 +759,5 @@ observer.observe(document, {
|
|||
})();
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
void 0;
|
||||
|
|
|
@ -1,85 +0,0 @@
|
|||
/*******************************************************************************
|
||||
|
||||
uBlock Origin - a browser extension to block requests.
|
||||
Copyright (C) 2019-present Raymond Hill
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program 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 this program. If not, see {http://www.gnu.org/licenses/}.
|
||||
|
||||
Home: https://github.com/gorhill/uBlock
|
||||
*/
|
||||
|
||||
/* jshint esversion:11 */
|
||||
|
||||
'use strict';
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
// Important!
|
||||
// Isolate from global scope
|
||||
(function uBOL_cssSpecificEntity() {
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
// $rulesetId$
|
||||
|
||||
const specificEntityImports = self.specificEntityImports || [];
|
||||
delete self.specificEntityImports;
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
const lookupSelectors = (hn, entity, out) => {
|
||||
for ( const { argsList, entitiesMap } of specificEntityImports ) {
|
||||
let argsIndices = entitiesMap.get(entity);
|
||||
if ( argsIndices === undefined ) { continue; }
|
||||
if ( typeof argsIndices === 'number' ) { argsIndices = [ argsIndices ]; }
|
||||
for ( const argsIndex of argsIndices ) {
|
||||
const details = argsList[argsIndex];
|
||||
if ( details.n && details.n.includes(hn) ) { continue; }
|
||||
out.push(details.a);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
let hn = '';
|
||||
try { hn = document.location.hostname; } catch(ex) { }
|
||||
const selectors = [];
|
||||
const hnparts = hn.split('.');
|
||||
const hnpartslen = hnparts.length - 1;
|
||||
for ( let i = 0; i < hnpartslen; i++ ) {
|
||||
for ( let j = hnpartslen; j > i; j-- ) {
|
||||
lookupSelectors(
|
||||
hnparts.slice(i).join('.'),
|
||||
hnparts.slice(i,j).join('.'),
|
||||
selectors
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
if ( selectors.length === 0 ) { return; }
|
||||
|
||||
try {
|
||||
const sheet = new CSSStyleSheet();
|
||||
sheet.replace(`@layer{${selectors.join(',')}{display:none!important;}}`);
|
||||
document.adoptedStyleSheets = [
|
||||
...document.adoptedStyleSheets,
|
||||
sheet
|
||||
];
|
||||
} catch(ex) {
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
})();
|
||||
|
||||
/******************************************************************************/
|
122
platform/mv3/extension/js/scripting/css-specific.js
Normal file
122
platform/mv3/extension/js/scripting/css-specific.js
Normal file
|
@ -0,0 +1,122 @@
|
|||
/*******************************************************************************
|
||||
|
||||
uBlock Origin - a browser extension to block requests.
|
||||
Copyright (C) 2019-present Raymond Hill
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program 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 this program. If not, see {http://www.gnu.org/licenses/}.
|
||||
|
||||
Home: https://github.com/gorhill/uBlock
|
||||
*/
|
||||
|
||||
/* jshint esversion:11 */
|
||||
|
||||
'use strict';
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
// Important!
|
||||
// Isolate from global scope
|
||||
(function uBOL_cssSpecific() {
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
const specificImports = self.specificImports || [];
|
||||
self.specificImports = undefined;
|
||||
delete self.specificImports;
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
const hnParts = [];
|
||||
try { hnParts.push(...document.location.hostname.split('.')); }
|
||||
catch(ex) { }
|
||||
const hnpartslen = hnParts.length;
|
||||
if ( hnpartslen === 0 ) { return; }
|
||||
|
||||
const selectors = [];
|
||||
|
||||
for ( const { argsList, exceptionsMap, hostnamesMap, entitiesMap } of specificImports ) {
|
||||
const todoIndices = new Set();
|
||||
const tonotdoIndices = [];
|
||||
// Exceptions
|
||||
if ( exceptionsMap.size !== 0 ) {
|
||||
for ( let i = 0; i < hnpartslen; i++ ) {
|
||||
const hn = hnParts.slice(i).join('.');
|
||||
const excepted = exceptionsMap.get(hn);
|
||||
if ( excepted ) { tonotdoIndices.push(...excepted); }
|
||||
}
|
||||
exceptionsMap.clear();
|
||||
}
|
||||
// Hostname-based
|
||||
if ( hostnamesMap.size !== 0 ) {
|
||||
const collectArgIndices = hn => {
|
||||
let argsIndices = hostnamesMap.get(hn);
|
||||
if ( argsIndices === undefined ) { return; }
|
||||
if ( typeof argsIndices === 'number' ) { argsIndices = [ argsIndices ]; }
|
||||
for ( const argsIndex of argsIndices ) {
|
||||
if ( tonotdoIndices.includes(argsIndex) ) { continue; }
|
||||
todoIndices.add(argsIndex);
|
||||
}
|
||||
};
|
||||
for ( let i = 0; i < hnpartslen; i++ ) {
|
||||
const hn = hnParts.slice(i).join('.');
|
||||
collectArgIndices(hn);
|
||||
}
|
||||
collectArgIndices('*');
|
||||
hostnamesMap.clear();
|
||||
}
|
||||
// Entity-based
|
||||
if ( entitiesMap.size !== 0 ) {
|
||||
const n = hnpartslen - 1;
|
||||
for ( let i = 0; i < n; i++ ) {
|
||||
for ( let j = n; j > i; j-- ) {
|
||||
const en = hnParts.slice(i,j).join('.');
|
||||
let argsIndices = entitiesMap.get(en);
|
||||
if ( argsIndices === undefined ) { continue; }
|
||||
if ( typeof argsIndices === 'number' ) { argsIndices = [ argsIndices ]; }
|
||||
for ( const argsIndex of argsIndices ) {
|
||||
if ( tonotdoIndices.includes(argsIndex) ) { continue; }
|
||||
todoIndices.add(argsIndex);
|
||||
}
|
||||
}
|
||||
}
|
||||
entitiesMap.clear();
|
||||
}
|
||||
for ( const i of todoIndices ) {
|
||||
selectors.push(argsList[i]);
|
||||
}
|
||||
argsList.length = 0;
|
||||
}
|
||||
specificImports.length = 0;
|
||||
|
||||
if ( selectors.length === 0 ) { return; }
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
try {
|
||||
const sheet = new CSSStyleSheet();
|
||||
sheet.replace(`@layer{${selectors.join(',')}{display:none!important;}}`);
|
||||
document.adoptedStyleSheets = [
|
||||
...document.adoptedStyleSheets,
|
||||
sheet
|
||||
];
|
||||
} catch(ex) {
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
})();
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
void 0;
|
|
@ -163,7 +163,7 @@ function renderFilterLists(soft = false) {
|
|||
// DOM list entries.
|
||||
dom.cl.add('#lists .listEntries .listEntry[data-listkey]', 'discard');
|
||||
|
||||
// Visually split the filter lists in three groups
|
||||
// Visually split the filter lists in groups
|
||||
const ulLists = qs$('#lists');
|
||||
const groups = new Map([
|
||||
[
|
||||
|
@ -172,10 +172,18 @@ function renderFilterLists(soft = false) {
|
|||
ruleset.id === 'default'
|
||||
),
|
||||
],
|
||||
[
|
||||
'annoyances',
|
||||
rulesetDetails.filter(ruleset =>
|
||||
ruleset.group === 'annoyances'
|
||||
),
|
||||
],
|
||||
[
|
||||
'misc',
|
||||
rulesetDetails.filter(ruleset =>
|
||||
ruleset.id !== 'default' && typeof ruleset.lang !== 'string'
|
||||
ruleset.id !== 'default' &&
|
||||
ruleset.group === undefined &&
|
||||
typeof ruleset.lang !== 'string'
|
||||
),
|
||||
],
|
||||
[
|
||||
|
|
|
@ -119,14 +119,6 @@ const hostnamesFromMatches = origins => {
|
|||
|
||||
/******************************************************************************/
|
||||
|
||||
const fnameFromFileId = fid =>
|
||||
fid.toString(32).padStart(7, '0');
|
||||
|
||||
const fidFromFileName = fname =>
|
||||
parseInt(fname, 32);
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
export {
|
||||
parsedURLromOrigin,
|
||||
toBroaderHostname,
|
||||
|
@ -136,6 +128,4 @@ export {
|
|||
subtractHostnameIters,
|
||||
matchesFromHostnames,
|
||||
hostnamesFromMatches,
|
||||
fnameFromFileId,
|
||||
fidFromFileName,
|
||||
};
|
||||
|
|
|
@ -30,7 +30,6 @@ import process from 'process';
|
|||
import { createHash } from 'crypto';
|
||||
import redirectResourcesMap from './js/redirect-resources.js';
|
||||
import { dnrRulesetFromRawLists } from './js/static-dnr-filtering.js';
|
||||
import { fnameFromFileId } from './js/utils.js';
|
||||
import * as sfp from './js/static-filtering-parser.js';
|
||||
import * as makeScriptlet from './make-scriptlets.js';
|
||||
|
||||
|
@ -158,10 +157,7 @@ const writeOps = [];
|
|||
|
||||
const ruleResources = [];
|
||||
const rulesetDetails = [];
|
||||
const declarativeDetails = new Map();
|
||||
const proceduralDetails = new Map();
|
||||
const scriptletStats = new Map();
|
||||
const specificDetails = new Map();
|
||||
const genericDetails = new Map();
|
||||
const requiredRedirectResources = new Set();
|
||||
|
||||
|
@ -403,45 +399,12 @@ function loadAllSourceScriptlets() {
|
|||
|
||||
/******************************************************************************/
|
||||
|
||||
const globalPatchedScriptletsSet = new Set();
|
||||
|
||||
function addScriptingAPIResources(id, hostnames, fid) {
|
||||
if ( hostnames === undefined ) { return; }
|
||||
for ( const hn of hostnames ) {
|
||||
let hostnamesToFidMap = specificDetails.get(id);
|
||||
if ( hostnamesToFidMap === undefined ) {
|
||||
hostnamesToFidMap = new Map();
|
||||
specificDetails.set(id, hostnamesToFidMap);
|
||||
}
|
||||
let fids = hostnamesToFidMap.get(hn);
|
||||
if ( fids === undefined ) {
|
||||
hostnamesToFidMap.set(hn, fid);
|
||||
} else if ( fids instanceof Set ) {
|
||||
fids.add(fid);
|
||||
} else if ( fid !== fids ) {
|
||||
fids = new Set([ fids, fid ]);
|
||||
hostnamesToFidMap.set(hn, fids);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const toCSSSpecific = s => (uidint32(s) & ~0b11) | 0b00;
|
||||
|
||||
const pathFromFileName = fname => `${fname.slice(-1)}/${fname.slice(0,-1)}.js`;
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
async function processGenericCosmeticFilters(assetDetails, bucketsMap, exclusions) {
|
||||
const out = {
|
||||
count: 0,
|
||||
exclusionCount: 0,
|
||||
};
|
||||
if ( bucketsMap === undefined ) { return out; }
|
||||
if ( bucketsMap.size === 0 ) { return out; }
|
||||
if ( bucketsMap === undefined ) { return 0; }
|
||||
if ( bucketsMap.size === 0 ) { return 0; }
|
||||
const bucketsList = Array.from(bucketsMap);
|
||||
const count = bucketsList.reduce((a, v) => a += v[1].length, 0);
|
||||
if ( count === 0 ) { return out; }
|
||||
out.count = count;
|
||||
if ( count === 0 ) { return 0; }
|
||||
|
||||
const selectorLists = bucketsList.map(v => [ v[0], v[1].join(',') ]);
|
||||
const originalScriptletMap = await loadAllSourceScriptlets();
|
||||
|
@ -464,13 +427,11 @@ async function processGenericCosmeticFilters(assetDetails, bucketsMap, exclusion
|
|||
|
||||
log(`CSS-generic: ${count} plain CSS selectors`);
|
||||
|
||||
return out;
|
||||
return count;
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
const MAX_COSMETIC_FILTERS_PER_FILE = 256;
|
||||
|
||||
// This merges selectors which are used by the same hostnames
|
||||
|
||||
function groupSelectorsByHostnames(mapin) {
|
||||
|
@ -588,52 +549,13 @@ function argsMap2List(argsMap, hostnamesMap) {
|
|||
|
||||
/******************************************************************************/
|
||||
|
||||
function splitDomainAndEntity(mapin) {
|
||||
const domainBased = new Map();
|
||||
const entityBased = new Map();
|
||||
for ( const [ selector, domainDetails ] of mapin ) {
|
||||
domainBased.set(selector, domainDetails);
|
||||
if ( domainDetails.rejected ) { continue; }
|
||||
if ( Array.isArray(domainDetails.matches) === false ) { continue; }
|
||||
const domainMatches = [];
|
||||
const entityMatches = [];
|
||||
for ( const hn of domainDetails.matches ) {
|
||||
if ( hn.endsWith('.*') ) {
|
||||
entityMatches.push(hn.slice(0, -2));
|
||||
} else {
|
||||
domainMatches.push(hn);
|
||||
}
|
||||
}
|
||||
if ( entityMatches.length === 0 ) { continue; }
|
||||
if ( domainMatches.length !== 0 ) {
|
||||
domainDetails.matches = domainMatches;
|
||||
} else {
|
||||
domainBased.delete(selector);
|
||||
}
|
||||
const entityDetails = {
|
||||
matches: entityMatches,
|
||||
};
|
||||
if ( Array.isArray(domainDetails.excludeMatches) ) {
|
||||
entityDetails.excludeMatches = domainDetails.excludeMatches.slice();
|
||||
}
|
||||
entityBased.set(selector, entityDetails);
|
||||
}
|
||||
return { domainBased, entityBased };
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
async function processCosmeticFilters(assetDetails, mapin) {
|
||||
if ( mapin === undefined ) { return; }
|
||||
if ( mapin === undefined ) { return 0; }
|
||||
if ( mapin.size === 0 ) { return 0; }
|
||||
|
||||
const { domainBased, entityBased } = splitDomainAndEntity(mapin);
|
||||
const entityBasedEntries = groupHostnamesBySelectors(
|
||||
groupSelectorsByHostnames(entityBased)
|
||||
);
|
||||
const domainBasedEntries = groupHostnamesBySelectors(
|
||||
groupSelectorsByHostnames(domainBased)
|
||||
groupSelectorsByHostnames(mapin)
|
||||
);
|
||||
|
||||
// We do not want more than n CSS files per subscription, so we will
|
||||
// group multiple unrelated selectors in the same file, and distinct
|
||||
// css declarations will be injected programmatically according to the
|
||||
|
@ -645,89 +567,68 @@ async function processCosmeticFilters(assetDetails, mapin) {
|
|||
const originalScriptletMap = await loadAllSourceScriptlets();
|
||||
const generatedFiles = [];
|
||||
|
||||
for ( let i = 0; i < domainBasedEntries.length; i += MAX_COSMETIC_FILTERS_PER_FILE ) {
|
||||
const slice = domainBasedEntries.slice(i, i + MAX_COSMETIC_FILTERS_PER_FILE);
|
||||
const argsMap = slice.map(entry => [
|
||||
entry[0],
|
||||
{
|
||||
a: entry[1].a ? entry[1].a.join(',\n') : undefined,
|
||||
n: entry[1].n
|
||||
}
|
||||
]);
|
||||
const hostnamesMap = new Map();
|
||||
for ( const [ id, details ] of slice ) {
|
||||
if ( details.y === undefined ) { continue; }
|
||||
scriptletHostnameToIdMap(details.y, id, hostnamesMap);
|
||||
}
|
||||
const argsList = argsMap2List(argsMap, hostnamesMap);
|
||||
const patchedScriptlet = originalScriptletMap.get('css-specific')
|
||||
.replace(
|
||||
'$rulesetId$',
|
||||
assetDetails.id
|
||||
).replace(
|
||||
/\bself\.\$argsList\$/m,
|
||||
`${JSON.stringify(argsList, scriptletJsonReplacer)}`
|
||||
).replace(
|
||||
/\bself\.\$hostnamesMap\$/m,
|
||||
`${JSON.stringify(hostnamesMap, scriptletJsonReplacer)}`
|
||||
);
|
||||
const fid = toCSSSpecific(patchedScriptlet);
|
||||
if ( globalPatchedScriptletsSet.has(fid) === false ) {
|
||||
globalPatchedScriptletsSet.add(fid);
|
||||
const fname = fnameFromFileId(fid);
|
||||
writeFile(`${scriptletDir}/specific/${pathFromFileName(fname)}`, patchedScriptlet);
|
||||
generatedFiles.push(fname);
|
||||
}
|
||||
for ( const entry of slice ) {
|
||||
addScriptingAPIResources(assetDetails.id, entry[1].y, fid);
|
||||
const argsMap = domainBasedEntries.map(entry => [
|
||||
entry[0],
|
||||
{
|
||||
a: entry[1].a ? entry[1].a.join(',\n') : undefined,
|
||||
n: entry[1].n
|
||||
}
|
||||
]);
|
||||
const hostnamesMap = new Map();
|
||||
for ( const [ id, details ] of domainBasedEntries ) {
|
||||
if ( details.y === undefined ) { continue; }
|
||||
scriptletHostnameToIdMap(details.y, id, hostnamesMap);
|
||||
}
|
||||
const argsList = argsMap2List(argsMap, hostnamesMap);
|
||||
const entitiesMap = new Map();
|
||||
for ( const [ hn, details ] of hostnamesMap ) {
|
||||
if ( hn.endsWith('.*') === false ) { continue; }
|
||||
hostnamesMap.delete(hn);
|
||||
entitiesMap.set(hn.slice(0, -2), details);
|
||||
}
|
||||
|
||||
// For entity-based entries, we generate a single scriptlet which will be
|
||||
// injected only in Complete mode.
|
||||
if ( entityBasedEntries.length !== 0 ) {
|
||||
const argsMap = entityBasedEntries.map(entry => [
|
||||
entry[0],
|
||||
{
|
||||
a: entry[1].a ? entry[1].a.join(',') : undefined,
|
||||
n: entry[1].n,
|
||||
// Extract exceptions from argsList, simplify argsList entries
|
||||
const exceptionsMap = new Map();
|
||||
for ( let i = 0; i < argsList.length; i++ ) {
|
||||
const details = argsList[i];
|
||||
if ( details.n ) {
|
||||
for ( const hn of details.n ) {
|
||||
if ( exceptionsMap.has(hn) === false ) {
|
||||
exceptionsMap.set(hn, []);
|
||||
}
|
||||
exceptionsMap.get(hn).push(i);
|
||||
}
|
||||
]);
|
||||
const entitiesMap = new Map();
|
||||
for ( const [ id, details ] of entityBasedEntries ) {
|
||||
if ( details.y === undefined ) { continue; }
|
||||
scriptletHostnameToIdMap(details.y, id, entitiesMap);
|
||||
}
|
||||
const argsList = argsMap2List(argsMap, entitiesMap);
|
||||
const patchedScriptlet = originalScriptletMap.get('css-specific.entity')
|
||||
.replace(
|
||||
'$rulesetId$',
|
||||
assetDetails.id
|
||||
).replace(
|
||||
/\bself\.\$argsList\$/m,
|
||||
`${JSON.stringify(argsList, scriptletJsonReplacer)}`
|
||||
).replace(
|
||||
/\bself\.\$entitiesMap\$/m,
|
||||
`${JSON.stringify(entitiesMap, scriptletJsonReplacer)}`
|
||||
);
|
||||
const fname = `${assetDetails.id}`;
|
||||
writeFile(`${scriptletDir}/specific-entity/${fname}.js`, patchedScriptlet);
|
||||
generatedFiles.push(fname);
|
||||
argsList[i] = details.a;
|
||||
}
|
||||
|
||||
const patchedScriptlet = originalScriptletMap.get('css-specific')
|
||||
.replace(
|
||||
'$rulesetId$',
|
||||
assetDetails.id
|
||||
).replace(
|
||||
/\bself\.\$argsList\$/m,
|
||||
`${JSON.stringify(argsList, scriptletJsonReplacer)}`
|
||||
).replace(
|
||||
/\bself\.\$hostnamesMap\$/m,
|
||||
`${JSON.stringify(hostnamesMap, scriptletJsonReplacer)}`
|
||||
).replace(
|
||||
/\bself\.\$entitiesMap\$/m,
|
||||
`${JSON.stringify(entitiesMap, scriptletJsonReplacer)}`
|
||||
).replace(
|
||||
/\bself\.\$exceptionsMap\$/m,
|
||||
`${JSON.stringify(exceptionsMap, scriptletJsonReplacer)}`
|
||||
);
|
||||
writeFile(`${scriptletDir}/specific/${assetDetails.id}.js`, patchedScriptlet);
|
||||
generatedFiles.push(`${assetDetails.id}`);
|
||||
|
||||
if ( generatedFiles.length !== 0 ) {
|
||||
log(`CSS-specific domain-based: ${domainBased.size} distinct filters`);
|
||||
log(`\tCombined into ${domainBasedEntries.length} distinct entries`);
|
||||
log(`CSS-specific entity-based: ${entityBased.size} distinct filters`);
|
||||
log(`\tCombined into ${entityBasedEntries.length} distinct entries`);
|
||||
log(`CSS-specific injectable files: ${generatedFiles.length}`);
|
||||
log(`\t${generatedFiles.join(', ')}`);
|
||||
log(`CSS-specific: ${mapin.size} distinct filters`);
|
||||
log(`\tCombined into ${hostnamesMap.size} distinct hostnames`);
|
||||
log(`\tCombined into ${entitiesMap.size} distinct entities`);
|
||||
}
|
||||
|
||||
return {
|
||||
domainBased: domainBasedEntries.length,
|
||||
entityBased: entityBasedEntries.length,
|
||||
};
|
||||
return hostnamesMap.size + entitiesMap.size;
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
|
@ -761,8 +662,29 @@ async function processDeclarativeCosmeticFilters(assetDetails, mapin) {
|
|||
if ( details.y === undefined ) { continue; }
|
||||
scriptletHostnameToIdMap(details.y, id, hostnamesMap);
|
||||
}
|
||||
|
||||
const argsList = argsMap2List(argsMap, hostnamesMap);
|
||||
const entitiesMap = new Map();
|
||||
for ( const [ hn, details ] of hostnamesMap ) {
|
||||
if ( hn.endsWith('.*') === false ) { continue; }
|
||||
hostnamesMap.delete(hn);
|
||||
entitiesMap.set(hn.slice(0, -2), details);
|
||||
}
|
||||
|
||||
// Extract exceptions from argsList, simplify argsList entries
|
||||
const exceptionsMap = new Map();
|
||||
for ( let i = 0; i < argsList.length; i++ ) {
|
||||
const details = argsList[i];
|
||||
if ( details.n ) {
|
||||
for ( const hn of details.n ) {
|
||||
if ( exceptionsMap.has(hn) === false ) {
|
||||
exceptionsMap.set(hn, []);
|
||||
}
|
||||
exceptionsMap.get(hn).push(i);
|
||||
}
|
||||
}
|
||||
argsList[i] = details.a;
|
||||
}
|
||||
|
||||
const originalScriptletMap = await loadAllSourceScriptlets();
|
||||
const patchedScriptlet = originalScriptletMap.get('css-declarative')
|
||||
.replace(
|
||||
|
@ -774,29 +696,22 @@ async function processDeclarativeCosmeticFilters(assetDetails, mapin) {
|
|||
).replace(
|
||||
/\bself\.\$hostnamesMap\$/m,
|
||||
`${JSON.stringify(hostnamesMap, scriptletJsonReplacer)}`
|
||||
).replace(
|
||||
/\bself\.\$entitiesMap\$/m,
|
||||
`${JSON.stringify(entitiesMap, scriptletJsonReplacer)}`
|
||||
).replace(
|
||||
/\bself\.\$exceptionsMap\$/m,
|
||||
`${JSON.stringify(exceptionsMap, scriptletJsonReplacer)}`
|
||||
);
|
||||
writeFile(`${scriptletDir}/declarative/${assetDetails.id}.js`, patchedScriptlet);
|
||||
|
||||
{
|
||||
const hostnames = new Set();
|
||||
for ( const entry of contentArray ) {
|
||||
if ( Array.isArray(entry[1].y) === false ) { continue; }
|
||||
for ( const hn of entry[1].y ) {
|
||||
hostnames.add(hn);
|
||||
}
|
||||
}
|
||||
if ( hostnames.has('*') ) {
|
||||
hostnames.clear();
|
||||
hostnames.add('*');
|
||||
}
|
||||
declarativeDetails.set(assetDetails.id, Array.from(hostnames).sort());
|
||||
}
|
||||
|
||||
if ( contentArray.length !== 0 ) {
|
||||
log(`Declarative-related distinct filters: ${contentArray.length} distinct combined selectors`);
|
||||
log(`CSS-declarative: ${declaratives.size} distinct filters`);
|
||||
log(`\tCombined into ${hostnamesMap.size} distinct hostnames`);
|
||||
log(`\tCombined into ${entitiesMap.size} distinct entities`);
|
||||
}
|
||||
|
||||
return contentArray.length;
|
||||
return hostnamesMap.size + entitiesMap.size;
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
|
@ -830,8 +745,29 @@ async function processProceduralCosmeticFilters(assetDetails, mapin) {
|
|||
if ( details.y === undefined ) { continue; }
|
||||
scriptletHostnameToIdMap(details.y, id, hostnamesMap);
|
||||
}
|
||||
|
||||
const argsList = argsMap2List(argsMap, hostnamesMap);
|
||||
const entitiesMap = new Map();
|
||||
for ( const [ hn, details ] of hostnamesMap ) {
|
||||
if ( hn.endsWith('.*') === false ) { continue; }
|
||||
hostnamesMap.delete(hn);
|
||||
entitiesMap.set(hn.slice(0, -2), details);
|
||||
}
|
||||
|
||||
// Extract exceptions from argsList, simplify argsList entries
|
||||
const exceptionsMap = new Map();
|
||||
for ( let i = 0; i < argsList.length; i++ ) {
|
||||
const details = argsList[i];
|
||||
if ( details.n ) {
|
||||
for ( const hn of details.n ) {
|
||||
if ( exceptionsMap.has(hn) === false ) {
|
||||
exceptionsMap.set(hn, []);
|
||||
}
|
||||
exceptionsMap.get(hn).push(i);
|
||||
}
|
||||
}
|
||||
argsList[i] = details.a;
|
||||
}
|
||||
|
||||
const originalScriptletMap = await loadAllSourceScriptlets();
|
||||
const patchedScriptlet = originalScriptletMap.get('css-procedural')
|
||||
.replace(
|
||||
|
@ -843,35 +779,29 @@ async function processProceduralCosmeticFilters(assetDetails, mapin) {
|
|||
).replace(
|
||||
/\bself\.\$hostnamesMap\$/m,
|
||||
`${JSON.stringify(hostnamesMap, scriptletJsonReplacer)}`
|
||||
).replace(
|
||||
/\bself\.\$entitiesMap\$/m,
|
||||
`${JSON.stringify(entitiesMap, scriptletJsonReplacer)}`
|
||||
).replace(
|
||||
/\bself\.\$exceptionsMap\$/m,
|
||||
`${JSON.stringify(exceptionsMap, scriptletJsonReplacer)}`
|
||||
);
|
||||
writeFile(`${scriptletDir}/procedural/${assetDetails.id}.js`, patchedScriptlet);
|
||||
|
||||
{
|
||||
const hostnames = new Set();
|
||||
for ( const entry of contentArray ) {
|
||||
if ( Array.isArray(entry[1].y) === false ) { continue; }
|
||||
for ( const hn of entry[1].y ) {
|
||||
hostnames.add(hn);
|
||||
}
|
||||
}
|
||||
if ( hostnames.has('*') ) {
|
||||
hostnames.clear();
|
||||
hostnames.add('*');
|
||||
}
|
||||
proceduralDetails.set(assetDetails.id, Array.from(hostnames).sort());
|
||||
}
|
||||
|
||||
if ( contentArray.length !== 0 ) {
|
||||
log(`Procedural-related distinct filters: ${contentArray.length} distinct combined selectors`);
|
||||
log(`Procedural-related distinct filters: ${procedurals.size} distinct combined selectors`);
|
||||
log(`\tCombined into ${hostnamesMap.size} distinct hostnames`);
|
||||
log(`\tCombined into ${entitiesMap.size} distinct entities`);
|
||||
}
|
||||
|
||||
return contentArray.length;
|
||||
return hostnamesMap.size + entitiesMap.size;
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
async function processScriptletFilters(assetDetails, mapin) {
|
||||
if ( mapin === undefined ) { return; }
|
||||
if ( mapin === undefined ) { return 0; }
|
||||
if ( mapin.size === 0 ) { return 0; }
|
||||
|
||||
makeScriptlet.init();
|
||||
|
||||
|
@ -887,7 +817,7 @@ async function processScriptletFilters(assetDetails, mapin) {
|
|||
scriptletStats.set(assetDetails.id, stats);
|
||||
}
|
||||
makeScriptlet.reset();
|
||||
return { domainBasedTokens: stats.length };
|
||||
return stats.length;
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
|
@ -942,13 +872,6 @@ async function rulesetFromURLs(assetDetails) {
|
|||
continue;
|
||||
}
|
||||
const parsed = JSON.parse(selector);
|
||||
const matches =
|
||||
details.matches.filter(hn => hn.endsWith('.*') === false);
|
||||
if ( matches.length === 0 ) {
|
||||
rejectedCosmetic.push(`Entity-based filter not supported: ${parsed.raw}`);
|
||||
continue;
|
||||
}
|
||||
details.matches = matches;
|
||||
parsed.raw = undefined;
|
||||
proceduralCosmetic.set(JSON.stringify(parsed), details);
|
||||
}
|
||||
|
@ -983,6 +906,7 @@ async function rulesetFromURLs(assetDetails) {
|
|||
rulesetDetails.push({
|
||||
id: assetDetails.id,
|
||||
name: assetDetails.name,
|
||||
group: assetDetails.group,
|
||||
enabled: assetDetails.enabled,
|
||||
lang: assetDetails.lang,
|
||||
homeURL: assetDetails.homeURL,
|
||||
|
@ -1110,7 +1034,11 @@ async function main() {
|
|||
}
|
||||
|
||||
// Handpicked rulesets from assets.json
|
||||
const handpicked = [ 'block-lan', 'dpollock-0', 'adguard-spyware-url' ];
|
||||
const handpicked = [
|
||||
'block-lan',
|
||||
'dpollock-0',
|
||||
'adguard-spyware-url',
|
||||
];
|
||||
for ( const id of handpicked ) {
|
||||
const asset = assets[id];
|
||||
if ( asset.content !== 'filters' ) { continue; }
|
||||
|
@ -1127,6 +1055,33 @@ async function main() {
|
|||
});
|
||||
}
|
||||
|
||||
// Handpicked annoyance rulesets from assets.json
|
||||
await rulesetFromURLs({
|
||||
id: 'easylist-cookies',
|
||||
name: 'EasyList – Cookies Notices' ,
|
||||
group: 'annoyances',
|
||||
enabled: false,
|
||||
urls: [
|
||||
'https://ublockorigin.github.io/uAssets/thirdparties/easylist-cookies.txt',
|
||||
],
|
||||
homeURL: 'https://github.com/uBlockOrigin/uAssets',
|
||||
});
|
||||
await rulesetFromURLs({
|
||||
id: 'easylist-annoyances',
|
||||
name: 'EasyList – Annoyances' ,
|
||||
group: 'annoyances',
|
||||
enabled: false,
|
||||
urls: [
|
||||
'https://ublockorigin.github.io/uAssets/thirdparties/easylist-annoyances.txt',
|
||||
'https://ublockorigin.github.io/uAssets/thirdparties/easylist-chat.txt',
|
||||
'https://ublockorigin.github.io/uAssets/thirdparties/easylist-newsletters.txt',
|
||||
'https://ublockorigin.github.io/uAssets/thirdparties/easylist-notifications.txt',
|
||||
'https://ublockorigin.github.io/uAssets/thirdparties/easylist-social.txt',
|
||||
'https://ublockorigin.github.io/uAssets/filters/annoyances.txt',
|
||||
],
|
||||
homeURL: 'https://github.com/uBlockOrigin/uAssets',
|
||||
});
|
||||
|
||||
// Handpicked rulesets from abroad
|
||||
await rulesetFromURLs({
|
||||
id: 'stevenblack-hosts',
|
||||
|
@ -1141,29 +1096,6 @@ async function main() {
|
|||
`${JSON.stringify(rulesetDetails, null, 1)}\n`
|
||||
);
|
||||
|
||||
// We sort the hostnames for convenience/performance in the extension's
|
||||
// script manager -- the scripting API does a sort() internally.
|
||||
for ( const [ rulesetId, hostnamesToFidsMap ] of specificDetails ) {
|
||||
specificDetails.set(
|
||||
rulesetId,
|
||||
Array.from(hostnamesToFidsMap).sort()
|
||||
);
|
||||
}
|
||||
writeFile(
|
||||
`${rulesetDir}/specific-details.json`,
|
||||
`${JSON.stringify(specificDetails, jsonSetMapReplacer)}\n`
|
||||
);
|
||||
|
||||
writeFile(
|
||||
`${rulesetDir}/declarative-details.json`,
|
||||
`${JSON.stringify(declarativeDetails, jsonSetMapReplacer, 1)}\n`
|
||||
);
|
||||
|
||||
writeFile(
|
||||
`${rulesetDir}/procedural-details.json`,
|
||||
`${JSON.stringify(proceduralDetails, jsonSetMapReplacer, 1)}\n`
|
||||
);
|
||||
|
||||
writeFile(
|
||||
`${rulesetDir}/scriptlet-details.json`,
|
||||
`${JSON.stringify(scriptletStats, jsonSetMapReplacer, 1)}\n`
|
||||
|
|
|
@ -99,7 +99,7 @@ if ( entitiesMap.size !== 0 ) {
|
|||
if ( argsIndices === undefined ) { continue; }
|
||||
if ( typeof argsIndices === 'number' ) { argsIndices = [ argsIndices ]; }
|
||||
for ( const argsIndex of argsIndices ) {
|
||||
if ( tonotdoIndices(argsIndex) ) { continue; }
|
||||
if ( tonotdoIndices.includes(argsIndex) ) { continue; }
|
||||
todoIndices.add(argsIndex);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -23,6 +23,8 @@
|
|||
|
||||
'use strict';
|
||||
|
||||
// ruleset: $rulesetId$
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
/// name css-declarative
|
||||
|
@ -35,14 +37,16 @@
|
|||
|
||||
/******************************************************************************/
|
||||
|
||||
// $rulesetId$
|
||||
|
||||
const argsList = self.$argsList$;
|
||||
|
||||
const hostnamesMap = new Map(self.$hostnamesMap$);
|
||||
|
||||
const entitiesMap = new Map(self.$entitiesMap$);
|
||||
|
||||
const exceptionsMap = new Map(self.$exceptionsMap$);
|
||||
|
||||
self.declarativeImports = self.declarativeImports || [];
|
||||
self.declarativeImports.push({ argsList, hostnamesMap });
|
||||
self.declarativeImports.push({ argsList, hostnamesMap, entitiesMap, exceptionsMap });
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
|
|
|
@ -23,6 +23,8 @@
|
|||
|
||||
'use strict';
|
||||
|
||||
// ruleset: $rulesetId$
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
/// name css-procedural
|
||||
|
@ -35,14 +37,16 @@
|
|||
|
||||
/******************************************************************************/
|
||||
|
||||
// $rulesetId$
|
||||
|
||||
const argsList = self.$argsList$;
|
||||
|
||||
const hostnamesMap = new Map(self.$hostnamesMap$);
|
||||
|
||||
const entitiesMap = new Map(self.$entitiesMap$);
|
||||
|
||||
const exceptionsMap = new Map(self.$exceptionsMap$);
|
||||
|
||||
self.proceduralImports = self.proceduralImports || [];
|
||||
self.proceduralImports.push({ argsList, hostnamesMap });
|
||||
self.proceduralImports.push({ argsList, hostnamesMap, entitiesMap, exceptionsMap });
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
|
|
|
@ -23,6 +23,8 @@
|
|||
|
||||
'use strict';
|
||||
|
||||
// ruleset: $rulesetId$
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
/// name css-specific
|
||||
|
@ -31,54 +33,20 @@
|
|||
|
||||
// Important!
|
||||
// Isolate from global scope
|
||||
(function uBOL_cssSpecific() {
|
||||
(function uBOL_cssSpecificImports() {
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
// $rulesetId$
|
||||
|
||||
const argsList = self.$argsList$;
|
||||
|
||||
const hostnamesMap = new Map(self.$hostnamesMap$);
|
||||
|
||||
/******************************************************************************/
|
||||
const entitiesMap = new Map(self.$entitiesMap$);
|
||||
|
||||
let hn;
|
||||
try { hn = document.location.hostname; } catch(ex) { }
|
||||
const styles = [];
|
||||
while ( hn ) {
|
||||
if ( hostnamesMap.has(hn) ) {
|
||||
let argsIndices = hostnamesMap.get(hn);
|
||||
if ( typeof argsIndices === 'number' ) { argsIndices = [ argsIndices ]; }
|
||||
for ( const argsIndex of argsIndices ) {
|
||||
const details = argsList[argsIndex];
|
||||
if ( details.n && details.n.includes(hn) ) { continue; }
|
||||
styles.push(details.a);
|
||||
}
|
||||
}
|
||||
if ( hn === '*' ) { break; }
|
||||
const pos = hn.indexOf('.');
|
||||
if ( pos !== -1 ) {
|
||||
hn = hn.slice(pos + 1);
|
||||
} else {
|
||||
hn = '*';
|
||||
}
|
||||
}
|
||||
const exceptionsMap = new Map(self.$exceptionsMap$);
|
||||
|
||||
argsList.length = 0;
|
||||
hostnamesMap.clear();
|
||||
|
||||
if ( styles.length === 0 ) { return; }
|
||||
|
||||
try {
|
||||
const sheet = new CSSStyleSheet();
|
||||
sheet.replace(`@layer{${styles.join(',')}{display:none!important;}}`);
|
||||
document.adoptedStyleSheets = [
|
||||
...document.adoptedStyleSheets,
|
||||
sheet
|
||||
];
|
||||
} catch(ex) {
|
||||
}
|
||||
self.specificImports = self.specificImports || [];
|
||||
self.specificImports.push({ argsList, hostnamesMap, entitiesMap, exceptionsMap });
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
|
|
Loading…
Reference in a new issue