stylus/background/style-search-db.js
tophf fdbfb23547
API groups + use executeScript for early injection (#1149)
* parserlib: fast section extraction, tweaks and speedups
* csslint: "simple-not" rule
* csslint: enable and fix "selector-newline" rule
* simplify db: resolve with result
* simplify download()
* remove noCode param as it wastes more time/memory on copying
* styleManager: switch style<->data names to reflect their actual contents
* inline method bodies to avoid indirection and enable better autocomplete/hint/jump support in IDE
* upgrade getEventKeyName to handle mouse clicks
* don't trust location.href as it hides text fragment
* getAllKeys is implemented since Chrome48, FF44
* allow recoverable css errors + async'ify usercss.js
* openManage: unminimize windows
* remove the obsolete Chrome pre-65 workaround
* fix temporal dead zone in apply.js
* ff bug workaround for simple editor window
* consistent window scrolling in scrollToEditor and jumpToPos
* rework waitForSelector and collapsible <details>
* blank paint frame workaround for new Chrome
* extract stuff from edit.js and load on demand
* simplify regexpTester::isShown
* move MozDocMapper to sections-util.js
* extract fitSelectBox()
* initialize router earlier
* use helpPopup.close()
* fix autofocus in popups, follow-up to 5bb1b5ef
* clone objects in prefs.get() + cosmetics
* reuse getAll result for INC
2021-01-01 17:27:58 +03:00

109 lines
3.3 KiB
JavaScript

/* global API */// msg.js
/* global URLS debounce stringAsRegExp tryRegExp */// toolbox.js
/* global addAPI */// common.js
'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(URLS.rxMETA) || [''])[0]
: null;
const stripMeta = style =>
style.usercssData
? style.sourceCode.replace(URLS.rxMETA, '')
: 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),
});
addAPI(/** @namespace API */ {
styles: {
/**
* @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
*/
async searchDB({query, mode = 'all', ids}) {
let res = [];
if (mode === 'url' && query) {
res = (await API.styles.getByUrl(query)).map(r => r.style.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) : createTester(query);
res = (await API.styles.getAll())
.filter(style =>
(!ids || ids.includes(style.id)) &&
(!query || modeHandler(style, test)))
.map(style => style.id);
if (cache.size) debounce(clearCache, 60e3);
}
return res;
},
},
});
function createTester(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();
}
})();