mirror of
https://github.com/gorhill/uBlock.git
synced 2026-03-11 09:04:36 +00:00
draft
This commit is contained in:
parent
7414e67505
commit
66a1c5347b
14 changed files with 105 additions and 194 deletions
|
|
@ -224,29 +224,28 @@ function onMessage(request, sender, callback) {
|
|||
|
||||
switch ( request.what ) {
|
||||
|
||||
case 'insertCSS': {
|
||||
case 'updateCSS': {
|
||||
if ( frameId === false ) { return false; }
|
||||
// https://bugs.webkit.org/show_bug.cgi?id=262491
|
||||
if ( frameId !== 0 && webextFlavor === 'safari' ) { return false; }
|
||||
browser.scripting.insertCSS({
|
||||
css: request.css,
|
||||
origin: 'USER',
|
||||
target: { tabId, frameIds: [ frameId ] },
|
||||
}).catch(reason => {
|
||||
ubolErr(`insertCSS/${reason}`);
|
||||
});
|
||||
return false;
|
||||
}
|
||||
|
||||
case 'removeCSS': {
|
||||
if ( frameId === false ) { return false; }
|
||||
browser.scripting.removeCSS({
|
||||
css: request.css,
|
||||
origin: 'USER',
|
||||
target: { tabId, frameIds: [ frameId ] },
|
||||
}).catch(reason => {
|
||||
ubolErr(`removeCSS/${reason}`);
|
||||
});
|
||||
if ( request.insert ) {
|
||||
browser.scripting.insertCSS({
|
||||
css: request.insert,
|
||||
origin: 'USER',
|
||||
target: { tabId, frameIds: [ frameId ] },
|
||||
}).catch(reason => {
|
||||
ubolErr(`insertCSS/${reason}`);
|
||||
});
|
||||
}
|
||||
if ( request.remove ) {
|
||||
browser.scripting.removeCSS({
|
||||
css: request.remove,
|
||||
origin: 'USER',
|
||||
target: { tabId, frameIds: [ frameId ] },
|
||||
}).catch(reason => {
|
||||
ubolErr(`removeCSS/${reason}`);
|
||||
});
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
@ -668,6 +667,8 @@ async function startSession() {
|
|||
// launch time whether content css/scripts are properly registered.
|
||||
registerInjectables();
|
||||
|
||||
// Cosmetic filtering-related content scripts cache fitlering data in
|
||||
// session storage.
|
||||
sessionAccessLevel({ accessLevel: 'TRUSTED_AND_UNTRUSTED_CONTEXTS' });
|
||||
|
||||
// https://developer.mozilla.org/en-US/docs/Mozilla/Add-ons/WebExtensions/API/declarativeNetRequest
|
||||
|
|
|
|||
|
|
@ -296,7 +296,7 @@ async function registerProcedural(context) {
|
|||
{
|
||||
const keys = await localKeys();
|
||||
for ( const key of keys ) {
|
||||
if ( key.startsWith('css.procedural.data.') === false ) { continue; }
|
||||
if ( key.startsWith('css.procedural.') === false ) { continue; }
|
||||
sessionRemove(key);
|
||||
localRemove(key);
|
||||
}
|
||||
|
|
@ -321,8 +321,8 @@ async function registerProcedural(context) {
|
|||
const promises = [];
|
||||
for ( const id of rulesetIds ) {
|
||||
promises.push(
|
||||
fetchJSON(`/rulesets/scripting/procedural/data/${id}`).then(data => {
|
||||
return localWrite(`css.procedural.data.${id}`, data);
|
||||
fetchJSON(`/rulesets/scripting/procedural/${id}`).then(data => {
|
||||
return localWrite(`css.procedural.json.${id}`, data);
|
||||
})
|
||||
);
|
||||
}
|
||||
|
|
@ -385,7 +385,7 @@ async function registerSpecific(context) {
|
|||
{
|
||||
const keys = await localKeys();
|
||||
for ( const key of keys ) {
|
||||
if ( key.startsWith('css.specific.data.') === false ) { continue; }
|
||||
if ( key.startsWith('css.specific.') === false ) { continue; }
|
||||
sessionRemove(key);
|
||||
localRemove(key);
|
||||
}
|
||||
|
|
@ -410,8 +410,8 @@ async function registerSpecific(context) {
|
|||
const promises = [];
|
||||
for ( const id of rulesetIds ) {
|
||||
promises.push(
|
||||
fetchJSON(`/rulesets/scripting/specific/data/${id}`).then(data => {
|
||||
return localWrite(`css.specific.data.${id}`, data);
|
||||
fetchJSON(`/rulesets/scripting/specific/${id}`).then(data => {
|
||||
return localWrite(`css.specific.json.${id}`, data);
|
||||
})
|
||||
);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -22,10 +22,11 @@
|
|||
(api => {
|
||||
if ( typeof api === 'object' ) { return; }
|
||||
self.cssAPI = {
|
||||
insert(css) {
|
||||
update(insert, remove) {
|
||||
chrome.runtime.sendMessage({
|
||||
what: 'insertCSS',
|
||||
css,
|
||||
what: 'updateCSS',
|
||||
insert,
|
||||
remove
|
||||
}).catch(( ) => {
|
||||
});
|
||||
},
|
||||
|
|
|
|||
|
|
@ -188,7 +188,7 @@ const uBOL_processNodes = ( ) => {
|
|||
if ( styleSheetTimer !== undefined ) { return; }
|
||||
styleSheetTimer = self.requestAnimationFrame(( ) => {
|
||||
styleSheetTimer = undefined;
|
||||
self.cssAPI.insert(`${styleSheetSelectors.join(',')}{display:none!important;}`);
|
||||
self.cssAPI.update(`${styleSheetSelectors.join(',')}{display:none!important;}`);
|
||||
styleSheetSelectors.length = 0;
|
||||
});
|
||||
};
|
||||
|
|
|
|||
|
|
@ -608,9 +608,11 @@ class ProceduralFilterer {
|
|||
for ( const elem of this.styledNodes ) {
|
||||
elem.removeAttribute(token);
|
||||
}
|
||||
const css = `[${token}]\n{${style}}\n`;
|
||||
promises.push(
|
||||
chrome.runtime.sendMessage({ what: 'removeCSS', css }).catch(( ) => { })
|
||||
chrome.runtime.sendMessage({
|
||||
what: 'updateCSS',
|
||||
remove: `[${token}]\n{${style}}\n`,
|
||||
}).catch(( ) => { })
|
||||
);
|
||||
}
|
||||
this.styleTokenMap.clear();
|
||||
|
|
@ -680,7 +682,7 @@ class ProceduralFilterer {
|
|||
if ( styleToken !== undefined ) { return styleToken; }
|
||||
styleToken = randomToken();
|
||||
this.styleTokenMap.set(style, styleToken);
|
||||
self.cssAPI.insert(`[${styleToken}]\n{${style}}\n`);
|
||||
self.cssAPI.update(`[${styleToken}]\n{${style}}\n`);
|
||||
return styleToken;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -32,66 +32,21 @@ self.proceduralImports = undefined;
|
|||
|
||||
const isolatedAPI = self.isolatedAPI;
|
||||
|
||||
const lookupHostname = (hostname, details) => {
|
||||
const listref = isolatedAPI.binarySearch(details.hostnames, hostname);
|
||||
if ( listref === -1 ) { return; }
|
||||
details.listrefs ||= [];
|
||||
details.listrefs.push(listref);
|
||||
};
|
||||
const selectors = [];
|
||||
|
||||
const lookupAll = hostname => {
|
||||
for ( const details of proceduralImports ) {
|
||||
lookupHostname(hostname, details);
|
||||
}
|
||||
};
|
||||
|
||||
isolatedAPI.forEachHostname(lookupAll, {
|
||||
hasEntities: proceduralImports.some(a => a.hasEntities)
|
||||
});
|
||||
|
||||
const toLookup = proceduralImports.filter(a => Array.isArray(a.listrefs));
|
||||
if ( toLookup.length === 0 ) { return; }
|
||||
|
||||
const selectors = new Set();
|
||||
const exceptions = new Set();
|
||||
|
||||
const lookupSelectors = async details => {
|
||||
const { rulesetId } = details;
|
||||
const key = `css.procedural.data.${rulesetId}`;
|
||||
const data = await isolatedAPI.storageGet(key);
|
||||
if ( Boolean(data) === false ) { return; }
|
||||
if ( data.signature !== details.signature ) { return; }
|
||||
for ( const listref of details.listrefs ) {
|
||||
const ilist = data.selectorListRefs[listref];
|
||||
const list = JSON.parse(`[${data.selectorLists[ilist]}]`);
|
||||
for ( const iselector of list ) {
|
||||
if ( iselector >= 0 ) {
|
||||
selectors.add(data.selectors[iselector]);
|
||||
} else {
|
||||
exceptions.add(data.selectors[~iselector]);
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
const promises = [];
|
||||
for ( const details of toLookup ) {
|
||||
promises.push(lookupSelectors(details));
|
||||
const cachedCSS = await isolatedAPI.sessionGet('css.procedural.cache') || {};
|
||||
if ( cachedCSS[isolatedAPI.docHostname] ) {
|
||||
selectors.push(...cachedCSS[isolatedAPI.docHostname]);
|
||||
} else {
|
||||
selectors.push(...await isolatedAPI.getSelectors('procedural', proceduralImports));
|
||||
cachedCSS[isolatedAPI.docHostname] = selectors;
|
||||
isolatedAPI.sessionSet('css.procedural.cache', cachedCSS);
|
||||
}
|
||||
|
||||
await Promise.all(promises);
|
||||
if ( selectors.length === 0 ) { return; }
|
||||
|
||||
proceduralImports.length = 0;
|
||||
|
||||
for ( const selector of exceptions ) {
|
||||
selectors.delete(selector);
|
||||
}
|
||||
|
||||
if ( selectors.size === 0 ) { return; }
|
||||
|
||||
const exceptedSelectors = Array.from(selectors).map(a => JSON.parse(a));
|
||||
|
||||
const declaratives = exceptedSelectors.filter(a => a.cssable);
|
||||
const declaratives = selectors.filter(a => a.cssable);
|
||||
if ( declaratives.length !== 0 ) {
|
||||
const cssRuleFromProcedural = details => {
|
||||
const { tasks, action } = details;
|
||||
|
|
@ -127,11 +82,11 @@ if ( declaratives.length !== 0 ) {
|
|||
sheetText.push(ruleText);
|
||||
}
|
||||
if ( sheetText.length !== 0 ) {
|
||||
self.cssAPI.insert(sheetText.join('\n'));
|
||||
self.cssAPI.update(sheetText.join('\n'));
|
||||
}
|
||||
}
|
||||
|
||||
const procedurals = exceptedSelectors.filter(a => a.cssable === undefined);
|
||||
const procedurals = selectors.filter(a => a.cssable === undefined);
|
||||
if ( procedurals.length !== 0 ) {
|
||||
const addSelectors = selectors => {
|
||||
if ( self.listsProceduralFiltererAPI instanceof Object === false ) { return; }
|
||||
|
|
|
|||
|
|
@ -32,63 +32,22 @@ self.specificImports = undefined;
|
|||
|
||||
const isolatedAPI = self.isolatedAPI;
|
||||
|
||||
const lookupHostname = (hostname, details) => {
|
||||
const listref = isolatedAPI.binarySearch(details.hostnames, hostname);
|
||||
if ( listref === -1 ) { return; }
|
||||
details.listrefs ||= [];
|
||||
details.listrefs.push(listref);
|
||||
};
|
||||
const selectors = [];
|
||||
|
||||
const lookupAll = hostname => {
|
||||
for ( const details of specificImports ) {
|
||||
lookupHostname(hostname, details);
|
||||
}
|
||||
};
|
||||
self.cssAPI.update('*{visibility:hidden!important;}');
|
||||
|
||||
isolatedAPI.forEachHostname(lookupAll, {
|
||||
hasEntities: specificImports.some(a => a.hasEntities)
|
||||
});
|
||||
|
||||
const toLookup = specificImports.filter(a => Array.isArray(a.listrefs));
|
||||
if ( toLookup.length === 0 ) { return; }
|
||||
|
||||
const selectors = new Set();
|
||||
const exceptions = new Set();
|
||||
|
||||
const lookupSelectors = async details => {
|
||||
const { rulesetId } = details;
|
||||
const key = `css.specific.data.${rulesetId}`;
|
||||
const data = await isolatedAPI.storageGet(key);
|
||||
if ( Boolean(data) === false ) { return; }
|
||||
if ( data.signature !== details.signature ) { return; }
|
||||
for ( const listref of details.listrefs ) {
|
||||
const ilist = data.selectorListRefs[listref];
|
||||
const list = JSON.parse(`[${data.selectorLists[ilist]}]`);
|
||||
for ( const iselector of list ) {
|
||||
if ( iselector >= 0 ) {
|
||||
selectors.add(data.selectors[iselector]);
|
||||
} else {
|
||||
exceptions.add(data.selectors[~iselector]);
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
const promises = [];
|
||||
for ( const details of toLookup ) {
|
||||
promises.push(lookupSelectors(details));
|
||||
const cachedCSS = await isolatedAPI.sessionGet('css.specific.cache') || {};
|
||||
if ( cachedCSS[isolatedAPI.docHostname] ) {
|
||||
selectors.push(...cachedCSS[isolatedAPI.docHostname]);
|
||||
} else {
|
||||
selectors.push(...await isolatedAPI.getSelectors('specific', specificImports));
|
||||
cachedCSS[isolatedAPI.docHostname] = selectors;
|
||||
isolatedAPI.sessionSet('css.specific.cache', cachedCSS);
|
||||
}
|
||||
|
||||
await Promise.all(promises);
|
||||
|
||||
for ( const selector of exceptions ) {
|
||||
selectors.delete(selector);
|
||||
}
|
||||
|
||||
if ( selectors.size === 0 ) { return; }
|
||||
|
||||
const css = `${Array.from(selectors).join(',\n')}{display:none!important;}`;
|
||||
self.cssAPI.insert(css);
|
||||
const insert = selectors.length !== 0
|
||||
? `${Array.from(selectors).join(',\n')}{display:none!important;}`
|
||||
: undefined;
|
||||
self.cssAPI.update(insert, '*{visibility:hidden!important;}');
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
|
|
|
|||
|
|
@ -26,8 +26,8 @@
|
|||
const plainSelectors = self.customFilters?.plainSelectors;
|
||||
if ( plainSelectors ) {
|
||||
chrome.runtime.sendMessage({
|
||||
what: 'removeCSS',
|
||||
css: `${plainSelectors.join(',\n')}{display:none!important;}`,
|
||||
what: 'updateCSS',
|
||||
remove: `${plainSelectors.join(',\n')}{display:none!important;}`,
|
||||
}).catch(( ) => {
|
||||
});
|
||||
}
|
||||
|
|
|
|||
|
|
@ -29,6 +29,7 @@
|
|||
|
||||
const hostnameStack = (( ) => {
|
||||
const docloc = document.location;
|
||||
isolatedAPI.docHostname = docloc.hostname;
|
||||
const origins = [ docloc.origin ];
|
||||
if ( docloc.ancestorOrigins ) {
|
||||
origins.push(...docloc.ancestorOrigins);
|
||||
|
|
@ -95,45 +96,54 @@
|
|||
return -1;
|
||||
};
|
||||
|
||||
const sessionGet = async function(key) {
|
||||
let data;
|
||||
isolatedAPI.sessionGet = async function(key) {
|
||||
try {
|
||||
const bin = await chrome.storage.session.get(key);
|
||||
data = bin?.[key] ?? undefined;
|
||||
} catch (error) {
|
||||
console.trace(error);
|
||||
return bin?.[key] ?? undefined;
|
||||
} catch {
|
||||
}
|
||||
return data;
|
||||
};
|
||||
|
||||
const sessionSet = function(key, data) {
|
||||
isolatedAPI.sessionSet = function(key, data) {
|
||||
try {
|
||||
chrome.storage.session.set({ [key]: data });
|
||||
} catch (error) {
|
||||
console.trace(error);
|
||||
} catch {
|
||||
}
|
||||
};
|
||||
|
||||
const localGet = async function(key) {
|
||||
let data;
|
||||
isolatedAPI.localGet = async function(key) {
|
||||
try {
|
||||
const bin = await chrome.storage.local.get(key);
|
||||
data = bin?.[key] ?? undefined;
|
||||
} catch (error) {
|
||||
console.trace(error);
|
||||
return bin?.[key] ?? undefined;
|
||||
} catch {
|
||||
}
|
||||
return data;
|
||||
};
|
||||
|
||||
isolatedAPI.storageGet = async function(key) {
|
||||
let data = await sessionGet(key);
|
||||
if ( data === undefined ) {
|
||||
data = await localGet(key);
|
||||
if ( data !== undefined ) {
|
||||
sessionSet(key, data);
|
||||
isolatedAPI.getSelectors = async function(realm, details) {
|
||||
const selectors = new Set();
|
||||
const exceptions = new Set();
|
||||
const lookupHostname = (hostname, data) => {
|
||||
const listref = isolatedAPI.binarySearch(data.hostnames, hostname);
|
||||
if ( listref === -1 ) { return; }
|
||||
const ilist = data.selectorListRefs[listref];
|
||||
const list = JSON.parse(`[${data.selectorLists[ilist]}]`);
|
||||
for ( const iselector of list ) {
|
||||
if ( iselector >= 0 ) {
|
||||
selectors.add(data.selectors[iselector]);
|
||||
} else {
|
||||
exceptions.add(data.selectors[~iselector]);
|
||||
}
|
||||
}
|
||||
};
|
||||
const selectorsFromRuleset = async rulesetId => {
|
||||
const data = await isolatedAPI.localGet(`css.${realm}.json.${rulesetId}`);
|
||||
isolatedAPI.forEachHostname(lookupHostname, data);
|
||||
};
|
||||
await Promise.all(details.map(a => selectorsFromRuleset(a.rulesetId)));
|
||||
for ( const selector of exceptions ) {
|
||||
selectors.delete(selector);
|
||||
}
|
||||
return data;
|
||||
return Array.from(selectors);
|
||||
};
|
||||
|
||||
})(self.isolatedAPI);
|
||||
|
|
|
|||
|
|
@ -246,7 +246,7 @@ async function previewSelector(selector) {
|
|||
}
|
||||
}
|
||||
if ( previewedCSS !== '' ) {
|
||||
await ubolOverlay.sendMessage({ what: 'removeCSS', css: previewedCSS });
|
||||
await ubolOverlay.sendMessage({ what: 'updateCSS', remove: previewedCSS });
|
||||
previewedCSS = '';
|
||||
}
|
||||
}
|
||||
|
|
@ -261,7 +261,7 @@ async function previewSelector(selector) {
|
|||
return;
|
||||
}
|
||||
previewedCSS = `${selector}{display:none!important;}`;
|
||||
await ubolOverlay.sendMessage({ what: 'insertCSS', css: previewedCSS });
|
||||
await ubolOverlay.sendMessage({ what: 'updateCSS', insert: previewedCSS });
|
||||
}
|
||||
|
||||
let previewedSelector = '';
|
||||
|
|
|
|||
|
|
@ -78,7 +78,7 @@ self.ubolOverlay = {
|
|||
`:root > [${this.secretAttr}-loaded] { visibility: visible !important; }`,
|
||||
`:root > [${this.secretAttr}-click] { pointer-events: none !important; }`,
|
||||
].join('\n');
|
||||
this.sendMessage({ what: 'insertCSS', css: this.pickerCSS });
|
||||
this.sendMessage({ what: 'updateCSS', insert: this.pickerCSS });
|
||||
self.addEventListener('scroll', this.onViewportChanged, { passive: true });
|
||||
self.addEventListener('resize', this.onViewportChanged, { passive: true });
|
||||
self.addEventListener('keydown', this.onKeyPressed, true);
|
||||
|
|
@ -86,7 +86,7 @@ self.ubolOverlay = {
|
|||
|
||||
stop() {
|
||||
if ( this.pickerCSS ) {
|
||||
this.sendMessage({ what: 'removeCSS', css: this.pickerCSS });
|
||||
this.sendMessage({ what: 'updateCSS', remove: this.pickerCSS });
|
||||
this.pickerCSS = undefined;
|
||||
}
|
||||
self.removeEventListener('scroll', this.onViewportChanged, { passive: true });
|
||||
|
|
|
|||
|
|
@ -870,12 +870,13 @@ async function processCosmeticFilters(assetDetails, realm, mapin) {
|
|||
});
|
||||
|
||||
const data = JSON.stringify({
|
||||
signature: secret,
|
||||
selectors: Array.from(allSelectors.keys()),
|
||||
selectorLists: Array.from(allSelectorLists.keys()),
|
||||
selectorListRefs: sortedHostnames.map(a => allHostnames.get(a)),
|
||||
hostnames: sortedHostnames,
|
||||
hasEntities,
|
||||
});
|
||||
writeFile(`${scriptletDir}/${realm}/data/${assetDetails.id}.json`, data);
|
||||
writeFile(`${scriptletDir}/${realm}/${assetDetails.id}.json`, data);
|
||||
|
||||
// The cosmetic filters will be injected programmatically as content
|
||||
// script and the decisions to activate the cosmetic filters will be
|
||||
|
|
@ -885,18 +886,6 @@ async function processCosmeticFilters(assetDetails, realm, mapin) {
|
|||
'self.$rulesetId$',
|
||||
JSON.stringify(assetDetails.id)
|
||||
);
|
||||
patchedScriptlet = safeReplace(patchedScriptlet,
|
||||
'self.$signature$',
|
||||
JSON.stringify(secret)
|
||||
);
|
||||
patchedScriptlet = safeReplace(patchedScriptlet,
|
||||
/\bself\.\$hostnames\$/,
|
||||
`/* ${sortedHostnames.length} */ ${JSON.stringify(sortedHostnames)}`
|
||||
);
|
||||
patchedScriptlet = safeReplace(patchedScriptlet,
|
||||
'self.$hasEntities$',
|
||||
JSON.stringify(hasEntities)
|
||||
);
|
||||
writeFile(`${scriptletDir}/${realm}/${assetDetails.id}.js`, patchedScriptlet);
|
||||
|
||||
log(`CSS-${realm}: ${allSelectors.size} distinct filters for ${allHostnames.size} distinct hostnames`);
|
||||
|
|
|
|||
|
|
@ -28,12 +28,9 @@ if ( Boolean(chrome?.storage?.local) === false ) { return; }
|
|||
/******************************************************************************/
|
||||
|
||||
const rulesetId = self.$rulesetId$;
|
||||
const signature = self.$signature$;
|
||||
const hostnames = self.$hostnames$;
|
||||
const hasEntities = self.$hasEntities$;
|
||||
|
||||
self.proceduralImports = self.proceduralImports || [];
|
||||
self.proceduralImports.push({ rulesetId, signature, hostnames, hasEntities });
|
||||
self.proceduralImports.push({ rulesetId });
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
|
|
|
|||
|
|
@ -28,12 +28,9 @@ if ( Boolean(chrome?.storage?.local) === false ) { return; }
|
|||
/******************************************************************************/
|
||||
|
||||
const rulesetId = self.$rulesetId$;
|
||||
const signature = self.$signature$;
|
||||
const hostnames = self.$hostnames$;
|
||||
const hasEntities = self.$hasEntities$;
|
||||
|
||||
self.specificImports = self.specificImports || [];
|
||||
self.specificImports.push({ rulesetId, signature, hostnames, hasEntities });
|
||||
self.specificImports.push({ rulesetId });
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue