mirror of
https://github.com/gorhill/uBlock.git
synced 2026-03-11 09:04:36 +00:00
[mv3] Generate at most two scriptlet-related files per rulesets
Related issue: https://github.com/uBlockOrigin/uBOL-home/issues/557
This commit is contained in:
parent
d5793b83f2
commit
6039ef2b6d
5 changed files with 244 additions and 146 deletions
|
|
@ -434,29 +434,24 @@ function registerScriptlet(context, scriptletDetails) {
|
|||
];
|
||||
|
||||
for ( const rulesetId of rulesetsDetails.map(v => v.id) ) {
|
||||
const scriptletList = scriptletDetails.get(rulesetId);
|
||||
if ( scriptletList === undefined ) { continue; }
|
||||
|
||||
for ( const [ token, details ] of scriptletList ) {
|
||||
const id = `${rulesetId}.${token}`;
|
||||
const registered = before.get(id);
|
||||
const worlds = scriptletDetails.get(rulesetId);
|
||||
if ( worlds === undefined ) { continue; }
|
||||
for ( const world of Object.keys(worlds) ) {
|
||||
const id = `${rulesetId}.${world.toLowerCase()}`;
|
||||
|
||||
const matches = [];
|
||||
const excludeMatches = [];
|
||||
const hostnames = worlds[world];
|
||||
let targetHostnames = [];
|
||||
if ( hasBroadHostPermission ) {
|
||||
excludeMatches.push(...permissionRevokedMatches);
|
||||
if ( details.hostnames.length > 100 ) {
|
||||
targetHostnames = [ '*' ];
|
||||
} else {
|
||||
targetHostnames = details.hostnames;
|
||||
}
|
||||
targetHostnames = hostnames;
|
||||
} else if ( permissionGrantedHostnames.length !== 0 ) {
|
||||
if ( details.hostnames.includes('*') ) {
|
||||
if ( hostnames.includes('*') ) {
|
||||
targetHostnames = permissionGrantedHostnames;
|
||||
} else {
|
||||
targetHostnames = ut.intersectHostnameIters(
|
||||
details.hostnames,
|
||||
hostnames,
|
||||
permissionGrantedHostnames
|
||||
);
|
||||
}
|
||||
|
|
@ -465,16 +460,17 @@ function registerScriptlet(context, scriptletDetails) {
|
|||
matches.push(...ut.matchesFromHostnames(targetHostnames));
|
||||
normalizeMatches(matches);
|
||||
|
||||
const registered = before.get(id);
|
||||
before.delete(id); // Important!
|
||||
|
||||
const directive = {
|
||||
id,
|
||||
js: [ `/rulesets/scripting/scriptlet/${id}.js` ],
|
||||
js: [ `/rulesets/scripting/scriptlet/${world.toLowerCase()}/${rulesetId}.js` ],
|
||||
matches,
|
||||
allFrames: true,
|
||||
matchOriginAsFallback: true,
|
||||
runAt: 'document_start',
|
||||
world: details.world,
|
||||
world,
|
||||
};
|
||||
if ( excludeMatches.length !== 0 ) {
|
||||
directive.excludeMatches = excludeMatches;
|
||||
|
|
|
|||
|
|
@ -101,6 +101,7 @@ const consoleLog = console.log;
|
|||
const stdOutput = [];
|
||||
|
||||
const log = (text, silent = true) => {
|
||||
silent = silent && text.startsWith('!!!') === false;
|
||||
stdOutput.push(text);
|
||||
if ( silent === false ) {
|
||||
consoleLog(text);
|
||||
|
|
|
|||
|
|
@ -27,24 +27,37 @@ import { safeReplace } from './safe-replace.js';
|
|||
|
||||
const resourceDetails = new Map();
|
||||
const resourceAliases = new Map();
|
||||
const scriptletFiles = new Map();
|
||||
const worldTemplate = {
|
||||
scriptletFunctions: new Map(),
|
||||
allFunctions: new Map(),
|
||||
args: new Map(),
|
||||
arglists: new Map(),
|
||||
hostnames: new Map(),
|
||||
matches: new Set(),
|
||||
hasEntities: false,
|
||||
hasAncestors: false,
|
||||
};
|
||||
const worlds = {
|
||||
ISOLATED: structuredClone(worldTemplate),
|
||||
MAIN: structuredClone(worldTemplate),
|
||||
};
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
function createScriptletCoreCode(scriptletToken) {
|
||||
const details = resourceDetails.get(scriptletToken);
|
||||
const components = new Map([ [ scriptletToken, details.code ] ]);
|
||||
const dependencies = details.dependencies && details.dependencies.slice() || [];
|
||||
function createScriptletCoreCode(worldDetails, resourceEntry) {
|
||||
const { allFunctions } = worldDetails;
|
||||
allFunctions.set(resourceEntry.name, resourceEntry.code);
|
||||
const dependencies = resourceEntry.dependencies &&
|
||||
resourceEntry.dependencies.slice() || [];
|
||||
while ( dependencies.length !== 0 ) {
|
||||
const token = dependencies.shift();
|
||||
if ( components.has(token) ) { continue; }
|
||||
const details = resourceDetails.get(token);
|
||||
if ( details === undefined ) { continue; }
|
||||
components.set(token, details.code);
|
||||
if ( allFunctions.has(details.name) ) { continue; }
|
||||
allFunctions.set(details.name, details.code);
|
||||
if ( Array.isArray(details.dependencies) === false ) { continue; }
|
||||
dependencies.push(...details.dependencies);
|
||||
}
|
||||
return Array.from(components.values()).join('\n\n');
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
|
|
@ -70,7 +83,8 @@ export function init() {
|
|||
/******************************************************************************/
|
||||
|
||||
export function reset() {
|
||||
scriptletFiles.clear();
|
||||
worlds.ISOLATED = structuredClone(worldTemplate);
|
||||
worlds.MAIN = structuredClone(worldTemplate);
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
|
|
@ -85,56 +99,58 @@ export function compile(assetDetails, details) {
|
|||
const scriptletToken = details.args[0];
|
||||
const resourceEntry = resourceDetails.get(scriptletToken);
|
||||
if ( resourceEntry === undefined ) { return; }
|
||||
const argsToken = JSON.stringify(details.args.slice(1));
|
||||
if ( resourceEntry.requiresTrust && details.trustedSource !== true ) {
|
||||
console.log(`Rejecting +js(${scriptletToken},${argsToken.slice(1,-1)}): ${assetDetails.id} is not trusted`);
|
||||
console.log(`Rejecting +js(${details.args.join()}): ${assetDetails.id} is not trusted`);
|
||||
return;
|
||||
}
|
||||
if ( scriptletFiles.has(scriptletToken) === false ) {
|
||||
scriptletFiles.set(scriptletToken, {
|
||||
name: resourceEntry.name,
|
||||
code: createScriptletCoreCode(scriptletToken),
|
||||
world: resourceEntry.world,
|
||||
args: new Map(),
|
||||
hostnames: new Map(),
|
||||
exceptions: new Map(),
|
||||
hasEntities: false,
|
||||
hasAncestors: false,
|
||||
matches: new Set(),
|
||||
});
|
||||
const worldDetails = worlds[resourceEntry.world];
|
||||
const { scriptletFunctions } = worldDetails;
|
||||
if ( scriptletFunctions.has(resourceEntry.name) === false ) {
|
||||
scriptletFunctions.set(resourceEntry.name, scriptletFunctions.size);
|
||||
createScriptletCoreCode(worldDetails, resourceEntry);
|
||||
}
|
||||
const scriptletDetails = scriptletFiles.get(scriptletToken);
|
||||
if ( scriptletDetails.args.has(argsToken) === false ) {
|
||||
scriptletDetails.args.set(argsToken, scriptletDetails.args.size);
|
||||
// Convert args to arg indices
|
||||
const arglist = details.args.slice();
|
||||
arglist[0] = scriptletFunctions.get(resourceEntry.name);
|
||||
for ( let i = 1; i < arglist.length; i++ ) {
|
||||
const arg = arglist[i];
|
||||
if ( worldDetails.args.has(arg) === false ) {
|
||||
worldDetails.args.set(arg, worldDetails.args.size);
|
||||
}
|
||||
arglist[i] = worldDetails.args.get(arg);
|
||||
}
|
||||
const iArgs = scriptletDetails.args.get(argsToken);
|
||||
const arglistKey = JSON.stringify(arglist).slice(1, -1);
|
||||
if ( worldDetails.arglists.has(arglistKey) === false ) {
|
||||
worldDetails.arglists.set(arglistKey, worldDetails.arglists.size);
|
||||
}
|
||||
const arglistIndex = worldDetails.arglists.get(arglistKey);
|
||||
if ( details.matches ) {
|
||||
for ( const hn of details.matches ) {
|
||||
const isEntity = hn.endsWith('.*') || hn.endsWith('.*>>');
|
||||
scriptletDetails.hasEntities ||= isEntity;
|
||||
worldDetails.hasEntities ||= isEntity;
|
||||
const isAncestor = hn.endsWith('>>')
|
||||
scriptletDetails.hasAncestors ||= isAncestor;
|
||||
worldDetails.hasAncestors ||= isAncestor;
|
||||
if ( isEntity || isAncestor ) {
|
||||
scriptletDetails.matches.clear();
|
||||
scriptletDetails.matches.add('*');
|
||||
worldDetails.matches.clear();
|
||||
worldDetails.matches.add('*');
|
||||
}
|
||||
if ( scriptletDetails.matches.has('*') === false ) {
|
||||
scriptletDetails.matches.add(hn);
|
||||
if ( worldDetails.matches.has('*') === false ) {
|
||||
worldDetails.matches.add(hn);
|
||||
}
|
||||
if ( scriptletDetails.hostnames.has(hn) === false ) {
|
||||
scriptletDetails.hostnames.set(hn, new Set());
|
||||
if ( worldDetails.hostnames.has(hn) === false ) {
|
||||
worldDetails.hostnames.set(hn, new Set());
|
||||
}
|
||||
scriptletDetails.hostnames.get(hn).add(iArgs);
|
||||
worldDetails.hostnames.get(hn).add(arglistIndex);
|
||||
}
|
||||
} else {
|
||||
scriptletDetails.matches.add('*');
|
||||
worldDetails.matches.add('*');
|
||||
}
|
||||
if ( details.excludeMatches ) {
|
||||
for ( const hn of details.excludeMatches ) {
|
||||
if ( scriptletDetails.exceptions.has(hn) === false ) {
|
||||
scriptletDetails.exceptions.set(hn, []);
|
||||
if ( worldDetails.hostnames.has(hn) === false ) {
|
||||
worldDetails.hostnames.set(hn, new Set());
|
||||
}
|
||||
scriptletDetails.exceptions.get(hn).push(iArgs);
|
||||
worldDetails.hostnames.get(hn).add(~arglistIndex);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -146,51 +162,57 @@ export async function commit(rulesetId, path, writeFn) {
|
|||
'./scriptlets/scriptlet.template.js',
|
||||
{ encoding: 'utf8' }
|
||||
);
|
||||
const patchHnMap = hnmap => {
|
||||
const out = Array.from(hnmap);
|
||||
out.forEach(a => {
|
||||
const values = Array.from(a[1]);
|
||||
a[1] = values.length === 1 ? values[0] : values;
|
||||
});
|
||||
return out;
|
||||
};
|
||||
const scriptletStats = [];
|
||||
for ( const [ name, details ] of scriptletFiles ) {
|
||||
let content = safeReplace(scriptletTemplate,
|
||||
'function $scriptletName$(){}',
|
||||
details.code
|
||||
);
|
||||
content = safeReplace(content, /\$rulesetId\$/, rulesetId, 0);
|
||||
content = safeReplace(content, /\$scriptletName\$/, details.name, 0);
|
||||
const stats = {};
|
||||
for ( const world of Object.keys(worlds) ) {
|
||||
const worldDetails = worlds[world];
|
||||
const { scriptletFunctions, allFunctions, args, arglists } = worldDetails;
|
||||
if ( scriptletFunctions.size === 0 ) { continue; }
|
||||
const hostnames = Array.from(worldDetails.hostnames).toSorted((a, b) => {
|
||||
const d = a[0].length - b[0].length;
|
||||
if ( d !== 0 ) { return d; }
|
||||
return a[0] < b[0] ? -1 : 1;
|
||||
}).map(a => ([ a[0], JSON.stringify(Array.from(a[1]).map(a => JSON.parse(a))).slice(1,-1)]));
|
||||
let content = safeReplace(scriptletTemplate, /\$rulesetId\$/, rulesetId, 0);
|
||||
if ( worldDetails.hasEntities ) {
|
||||
content = safeReplace(content,
|
||||
'const $hasEntities$ = false;',
|
||||
'const $hasEntities$ = true;'
|
||||
);
|
||||
}
|
||||
if ( worldDetails.hasAncestors ) {
|
||||
content = safeReplace(content,
|
||||
'const $hasAncestors$ = false;',
|
||||
'const $hasAncestors$ = true;'
|
||||
);
|
||||
};
|
||||
content = safeReplace(content,
|
||||
'self.$argsList$',
|
||||
JSON.stringify(Array.from(details.args.keys()).map(a => JSON.parse(a)))
|
||||
'const $scriptletHostnames$ = [];',
|
||||
`const $scriptletHostnames$ = /* ${hostnames.length} */ ${JSON.stringify(hostnames.map(a => a[0]))};`
|
||||
);
|
||||
content = safeReplace(content,
|
||||
'self.$hostnamesMap$',
|
||||
JSON.stringify(patchHnMap(details.hostnames))
|
||||
'const $scriptletArglistRefs$ = [];',
|
||||
`const $scriptletArglistRefs$ = /* ${hostnames.length} */ ${JSON.stringify(hostnames.map(a => a[1]).join(';'))};`
|
||||
);
|
||||
content = safeReplace(content,
|
||||
'self.$hasEntities$',
|
||||
JSON.stringify(details.hasEntities)
|
||||
'const $scriptletArglists$ = [];',
|
||||
`const $scriptletArglists$ = /* ${arglists.size} */ ${JSON.stringify(Array.from(arglists.keys()).join(';'))};`
|
||||
);
|
||||
content = safeReplace(content,
|
||||
'self.$hasAncestors$',
|
||||
JSON.stringify(details.hasAncestors)
|
||||
'const $scriptletArgs$ = [];',
|
||||
`const $scriptletArgs$ = /* ${args.size} */ ${JSON.stringify(Array.from(args.keys()).join('\n'))};`
|
||||
);
|
||||
content = safeReplace(content,
|
||||
'self.$exceptionsMap$',
|
||||
JSON.stringify(Array.from(details.exceptions))
|
||||
'const $scriptletFunctions$ = [];',
|
||||
`const $scriptletFunctions$ = /* ${scriptletFunctions.size} */\n[${Array.from(scriptletFunctions.keys()).join(',')}];`
|
||||
);
|
||||
writeFn(`${path}/${rulesetId}.${name}`, content);
|
||||
scriptletStats.push([
|
||||
name.slice(0, -3), {
|
||||
hostnames: Array.from(details.matches).sort(),
|
||||
world: details.world,
|
||||
}
|
||||
]);
|
||||
content = safeReplace(content,
|
||||
'function $scriptletCode$(){} // eslint-disable-line',
|
||||
Array.from(allFunctions.values()).join('\n\n')
|
||||
);
|
||||
writeFn(`${path}/${world.toLowerCase()}/${rulesetId}.js`, content);
|
||||
stats[world] = Array.from(worldDetails.matches).sort();
|
||||
}
|
||||
return scriptletStats;
|
||||
return stats;
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
|
|
|
|||
|
|
@ -26,53 +26,30 @@
|
|||
// Isolate from global scope
|
||||
|
||||
// Start of local scope
|
||||
(function uBOL_$scriptletName$() {
|
||||
(function uBOL_scriptlets() {
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
function $scriptletName$(){}
|
||||
function $scriptletCode$(){} // eslint-disable-line
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
const scriptletGlobals = {}; // eslint-disable-line
|
||||
const argsList = self.$argsList$;
|
||||
const hostnamesMap = new Map(self.$hostnamesMap$);
|
||||
const exceptionsMap = new Map(self.$exceptionsMap$);
|
||||
const hasEntities = self.$hasEntities$;
|
||||
const hasAncestors = self.$hasAncestors$;
|
||||
|
||||
const collectArgIndices = (hn, map, out) => {
|
||||
let argsIndices = map.get(hn);
|
||||
if ( argsIndices === undefined ) { return; }
|
||||
if ( typeof argsIndices !== 'number' ) {
|
||||
for ( const argsIndex of argsIndices ) {
|
||||
out.add(argsIndex);
|
||||
}
|
||||
} else {
|
||||
out.add(argsIndices);
|
||||
}
|
||||
};
|
||||
const $scriptletFunctions$ = [];
|
||||
|
||||
const indicesFromHostname = (hostname, suffix = '') => {
|
||||
const hnParts = hostname.split('.');
|
||||
const hnpartslen = hnParts.length;
|
||||
if ( hnpartslen === 0 ) { return; }
|
||||
for ( let i = 0; i < hnpartslen; i++ ) {
|
||||
const hn = `${hnParts.slice(i).join('.')}${suffix}`;
|
||||
collectArgIndices(hn, hostnamesMap, todoIndices);
|
||||
collectArgIndices(hn, exceptionsMap, tonotdoIndices);
|
||||
}
|
||||
if ( hasEntities ) {
|
||||
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('.')}.*${suffix}`;
|
||||
collectArgIndices(en, hostnamesMap, todoIndices);
|
||||
collectArgIndices(en, exceptionsMap, tonotdoIndices);
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
const $scriptletArgs$ = [];
|
||||
|
||||
const $scriptletArglists$ = [];
|
||||
|
||||
const $scriptletArglistRefs$ = [];
|
||||
|
||||
const $scriptletHostnames$ = [];
|
||||
|
||||
const $hasEntities$ = false;
|
||||
const $hasAncestors$ = false;
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
const entries = (( ) => {
|
||||
const docloc = document.location;
|
||||
|
|
@ -81,31 +58,107 @@ const entries = (( ) => {
|
|||
origins.push(...docloc.ancestorOrigins);
|
||||
}
|
||||
return origins.map((origin, i) => {
|
||||
const beg = origin.lastIndexOf('://');
|
||||
const beg = origin.indexOf('://');
|
||||
if ( beg === -1 ) { return; }
|
||||
const hn = origin.slice(beg+3)
|
||||
const end = hn.indexOf(':');
|
||||
return { hn: end === -1 ? hn : hn.slice(0, end), i };
|
||||
const hn1 = origin.slice(beg+3)
|
||||
const end = hn1.indexOf(':');
|
||||
const hn2 = end === -1 ? hn1 : hn1.slice(0, end);
|
||||
const hnParts = hn2.split('.');
|
||||
if ( hn2.length === 0 ) { return; }
|
||||
const hns = [];
|
||||
for ( let i = 0; i < hnParts.length; i++ ) {
|
||||
hns.push(`${hnParts.slice(i).join('.')}`);
|
||||
}
|
||||
const ens = [];
|
||||
if ( $hasEntities$ ) {
|
||||
const n = hnParts.length - 1;
|
||||
for ( let i = 0; i < n; i++ ) {
|
||||
for ( let j = n; j > i; j-- ) {
|
||||
ens.push(`${hnParts.slice(i,j).join('.')}.*`);
|
||||
}
|
||||
}
|
||||
ens.sort((a, b) => {
|
||||
const d = b.length - a.length;
|
||||
if ( d !== 0 ) { return d; }
|
||||
return a > b ? -1 : 1;
|
||||
});
|
||||
}
|
||||
return { hns, ens, i };
|
||||
}).filter(a => a !== undefined);
|
||||
})();
|
||||
if ( entries.length === 0 ) { return; }
|
||||
|
||||
const todoIndices = new Set();
|
||||
const tonotdoIndices = new Set();
|
||||
const collectArglistRefIndices = (out, hn, r) => {
|
||||
let l = 0, i = 0, d = 0;
|
||||
let candidate = '';
|
||||
while ( l < r ) {
|
||||
i = l + r >>> 1;
|
||||
candidate = $scriptletHostnames$[i];
|
||||
d = hn.length - candidate.length;
|
||||
if ( d === 0 ) {
|
||||
if ( hn === candidate ) {
|
||||
out.add(i); break;
|
||||
}
|
||||
d = hn < candidate ? -1 : 1;
|
||||
}
|
||||
if ( d < 0 ) {
|
||||
r = i;
|
||||
} else {
|
||||
l = i + 1;
|
||||
}
|
||||
}
|
||||
return i;
|
||||
};
|
||||
|
||||
indicesFromHostname(entries[0].hn);
|
||||
if ( hasAncestors ) {
|
||||
const indicesFromHostname = (out, hnDetails, suffix = '') => {
|
||||
if ( hnDetails.hns.length === 0 ) { return; }
|
||||
let r = $scriptletHostnames$.length;
|
||||
for ( const hn of hnDetails.hns ) {
|
||||
r = collectArglistRefIndices(out, `${hn}${suffix}`, r);
|
||||
}
|
||||
if ( $hasEntities$ ) {
|
||||
let r = $scriptletHostnames$.length;
|
||||
for ( const en of hnDetails.ens ) {
|
||||
r = collectArglistRefIndices(out, `${en}${suffix}`, r);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
const todoIndices = new Set();
|
||||
indicesFromHostname(todoIndices, entries[0]);
|
||||
if ( $hasAncestors$ ) {
|
||||
for ( const entry of entries ) {
|
||||
if ( entry.i === 0 ) { continue; }
|
||||
indicesFromHostname(entry.hn, '>>');
|
||||
indicesFromHostname(todoIndices, entry, '>>');
|
||||
}
|
||||
}
|
||||
$scriptletHostnames$.length = 0;
|
||||
|
||||
if ( todoIndices.size === 0 ) { return; }
|
||||
|
||||
// Collect arglist references
|
||||
const todo = new Set();
|
||||
{
|
||||
const arglistRefs = $scriptletArglistRefs$.split(';');
|
||||
for ( const i of todoIndices ) {
|
||||
for ( const ref of JSON.parse(`[${arglistRefs[i]}]`) ) {
|
||||
todo.add(ref);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Apply scriplets
|
||||
for ( const i of todoIndices ) {
|
||||
if ( tonotdoIndices.has(i) ) { continue; }
|
||||
try { $scriptletName$(...argsList[i]); }
|
||||
catch { }
|
||||
// Execute scriplets
|
||||
{
|
||||
const arglists = $scriptletArglists$.split(';');
|
||||
const args = $scriptletArgs$.split('\n');
|
||||
for ( const ref of todo ) {
|
||||
if ( ref < 0 ) { continue; }
|
||||
if ( todo.has(~ref) ) { continue; }
|
||||
const arglist = JSON.parse(`[${arglists[ref]}]`);
|
||||
const fn = $scriptletFunctions$[arglist[0]];
|
||||
try { fn(...arglist.slice(1).map(a => args[a])); }
|
||||
catch { }
|
||||
}
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
|
|
|
|||
|
|
@ -47,6 +47,7 @@ export function setLocalStorageItemFn(
|
|||
trusted = false,
|
||||
key = '',
|
||||
value = '',
|
||||
options = {}
|
||||
) {
|
||||
if ( key === '' ) { return; }
|
||||
|
||||
|
|
@ -86,6 +87,8 @@ export function setLocalStorageItemFn(
|
|||
}
|
||||
}
|
||||
|
||||
let modified = false;
|
||||
|
||||
try {
|
||||
const storage = self[`${which}Storage`];
|
||||
if ( value === '$remove$' ) {
|
||||
|
|
@ -96,14 +99,25 @@ export function setLocalStorageItemFn(
|
|||
const key = storage.key(i);
|
||||
if ( pattern.test(key) ) { toRemove.push(key); }
|
||||
}
|
||||
modified = toRemove.length !== 0;
|
||||
for ( const key of toRemove ) {
|
||||
storage.removeItem(key);
|
||||
}
|
||||
} else {
|
||||
storage.setItem(key, `${value}`);
|
||||
|
||||
const before = storage.getItem(key);
|
||||
const after = `${value}`;
|
||||
modified = after !== before;
|
||||
if ( modified ) {
|
||||
storage.setItem(key, after);
|
||||
}
|
||||
}
|
||||
} catch {
|
||||
}
|
||||
|
||||
if ( modified && typeof options.reload === 'number' ) {
|
||||
setTimeout(( ) => { window.location.reload(); }, options.reload);
|
||||
}
|
||||
}
|
||||
registerScriptlet(setLocalStorageItemFn, {
|
||||
name: 'set-local-storage-item.fn',
|
||||
|
|
@ -178,23 +192,29 @@ registerScriptlet(removeCacheStorageItem, {
|
|||
**/
|
||||
|
||||
export function setLocalStorageItem(key = '', value = '') {
|
||||
setLocalStorageItemFn('local', false, key, value);
|
||||
const safe = safeSelf();
|
||||
const options = safe.getExtraArgs(Array.from(arguments), 2)
|
||||
setLocalStorageItemFn('local', false, key, value, options);
|
||||
}
|
||||
registerScriptlet(setLocalStorageItem, {
|
||||
name: 'set-local-storage-item.js',
|
||||
world: 'ISOLATED',
|
||||
dependencies: [
|
||||
safeSelf,
|
||||
setLocalStorageItemFn,
|
||||
],
|
||||
});
|
||||
|
||||
export function setSessionStorageItem(key = '', value = '') {
|
||||
setLocalStorageItemFn('session', false, key, value);
|
||||
const safe = safeSelf();
|
||||
const options = safe.getExtraArgs(Array.from(arguments), 2)
|
||||
setLocalStorageItemFn('session', false, key, value, options);
|
||||
}
|
||||
registerScriptlet(setSessionStorageItem, {
|
||||
name: 'set-session-storage-item.js',
|
||||
world: 'ISOLATED',
|
||||
dependencies: [
|
||||
safeSelf,
|
||||
setLocalStorageItemFn,
|
||||
],
|
||||
});
|
||||
|
|
@ -211,25 +231,31 @@ registerScriptlet(setSessionStorageItem, {
|
|||
**/
|
||||
|
||||
export function trustedSetLocalStorageItem(key = '', value = '') {
|
||||
setLocalStorageItemFn('local', true, key, value);
|
||||
const safe = safeSelf();
|
||||
const options = safe.getExtraArgs(Array.from(arguments), 2)
|
||||
setLocalStorageItemFn('local', true, key, value, options);
|
||||
}
|
||||
registerScriptlet(trustedSetLocalStorageItem, {
|
||||
name: 'trusted-set-local-storage-item.js',
|
||||
requiresTrust: true,
|
||||
world: 'ISOLATED',
|
||||
dependencies: [
|
||||
safeSelf,
|
||||
setLocalStorageItemFn,
|
||||
],
|
||||
});
|
||||
|
||||
export function trustedSetSessionStorageItem(key = '', value = '') {
|
||||
setLocalStorageItemFn('session', true, key, value);
|
||||
const safe = safeSelf();
|
||||
const options = safe.getExtraArgs(Array.from(arguments), 2)
|
||||
setLocalStorageItemFn('session', true, key, value, options);
|
||||
}
|
||||
registerScriptlet(trustedSetSessionStorageItem, {
|
||||
name: 'trusted-set-session-storage-item.js',
|
||||
requiresTrust: true,
|
||||
world: 'ISOLATED',
|
||||
dependencies: [
|
||||
safeSelf,
|
||||
setLocalStorageItemFn,
|
||||
],
|
||||
});
|
||||
|
|
|
|||
Loading…
Reference in a new issue