420733b93a
* add Patch CSP option * show style version, size, and update age in manager * add scope selector to style search in manager * keep scroll position and selections in tab's session * directly install usercss from raw github links * ditch localStorage, use on-demand SessionStore proxy * simplify localization * allow <code> tag in i18n-html * keep nodes in HTML templates * API.getAllStyles is actually faster with code untouched * fix fitToContent when applies-to is taller than window * dedupe linter.enableForEditor calls * prioritize visible CMs in refreshOnViewListener * don't scroll to last style on editing a new one * delay colorview for invisible CMs * eslint comma-dangle error + autofix files * styleViaXhr: also toggle for disableAll pref * styleViaXhr: allow cookies for sandbox CSP * simplify notes in options * simplify getStylesViaXhr * oldUI fixups: * remove separator before 1st applies-to * center name bubbles * fix updateToc focus on a newly added section * fix fitToContent when cloning section * remove CSS `contain` as it makes no difference * replace overrides with declarative CSS + code cosmetics * simplify adjustWidth and make it work in FF
110 lines
3.2 KiB
JavaScript
110 lines
3.2 KiB
JavaScript
/* global
|
|
API_METHODS
|
|
debounce
|
|
stringAsRegExp
|
|
styleManager
|
|
tryRegExp
|
|
usercss
|
|
*/
|
|
'use strict';
|
|
|
|
(() => {
|
|
// toLocaleLowerCase cache, autocleared after 1 minute
|
|
const cache = new Map();
|
|
const METAKEYS = ['customName', 'name', 'url', 'installationUrl', 'updateUrl'];
|
|
|
|
const extractMeta = style =>
|
|
style.usercssData
|
|
? (style.sourceCode.match(usercss.RX_META) || [''])[0]
|
|
: null;
|
|
|
|
const stripMeta = style =>
|
|
style.usercssData
|
|
? style.sourceCode.replace(usercss.RX_META, '')
|
|
: null;
|
|
|
|
const MODES = Object.assign(Object.create(null), {
|
|
code: (style, test) =>
|
|
style.usercssData
|
|
? test(stripMeta(style))
|
|
: searchSections(style, test, 'code'),
|
|
|
|
meta: (style, test, part) =>
|
|
METAKEYS.some(key => test(style[key])) ||
|
|
test(part === 'all' ? style.sourceCode : extractMeta(style)) ||
|
|
searchSections(style, test, 'funcs'),
|
|
|
|
name: (style, test) =>
|
|
test(style.customName) ||
|
|
test(style.name),
|
|
|
|
all: (style, test) =>
|
|
MODES.meta(style, test, 'all') ||
|
|
!style.usercssData && MODES.code(style, test),
|
|
});
|
|
|
|
/**
|
|
* @param params
|
|
* @param {string} params.query - 1. url:someurl 2. text (may contain quoted parts like "qUot Ed")
|
|
* @param {'name'|'meta'|'code'|'all'|'url'} [params.mode=all]
|
|
* @param {number[]} [params.ids] - if not specified, all styles are searched
|
|
* @returns {number[]} - array of matched styles ids
|
|
*/
|
|
API_METHODS.searchDB = async ({query, mode = 'all', ids}) => {
|
|
let res = [];
|
|
if (mode === 'url' && query) {
|
|
res = (await styleManager.getStylesByUrl(query)).map(r => r.data.id);
|
|
} else if (mode in MODES) {
|
|
const modeHandler = MODES[mode];
|
|
const m = /^\/(.+?)\/([gimsuy]*)$/.exec(query);
|
|
const rx = m && tryRegExp(m[1], m[2]);
|
|
const test = rx ? rx.test.bind(rx) : makeTester(query);
|
|
res = (await styleManager.getAllStyles())
|
|
.filter(style =>
|
|
(!ids || ids.includes(style.id)) &&
|
|
(!query || modeHandler(style, test)))
|
|
.map(style => style.id);
|
|
if (cache.size) debounce(clearCache, 60e3);
|
|
}
|
|
return res;
|
|
};
|
|
|
|
function makeTester(query) {
|
|
const flags = `u${lower(query) === query ? 'i' : ''}`;
|
|
const words = query
|
|
.split(/(".*?")|\s+/)
|
|
.filter(Boolean)
|
|
.map(w => w.startsWith('"') && w.endsWith('"')
|
|
? w.slice(1, -1)
|
|
: w)
|
|
.filter(w => w.length > 1);
|
|
const rxs = (words.length ? words : [query])
|
|
.map(w => stringAsRegExp(w, flags));
|
|
return text => rxs.every(rx => rx.test(text));
|
|
}
|
|
|
|
function searchSections({sections}, test, part) {
|
|
const inCode = part === 'code' || part === 'all';
|
|
const inFuncs = part === 'funcs' || part === 'all';
|
|
for (const section of sections) {
|
|
for (const prop in section) {
|
|
const value = section[prop];
|
|
if (inCode && prop === 'code' && test(value) ||
|
|
inFuncs && Array.isArray(value) && value.some(str => test(str))) {
|
|
return true;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
function lower(text) {
|
|
let result = cache.get(text);
|
|
if (!result) cache.set(text, result = text.toLocaleLowerCase());
|
|
return result;
|
|
}
|
|
|
|
function clearCache() {
|
|
cache.clear();
|
|
}
|
|
})();
|