2021-01-01 14:27:58 +00:00
|
|
|
/* global $create */// dom.js
|
|
|
|
/* global URLS openURL tryRegExp */// toolbox.js
|
|
|
|
/* global helpPopup */// util.js
|
|
|
|
/* global t */// localization.js
|
2017-10-07 15:40:37 +00:00
|
|
|
'use strict';
|
|
|
|
|
2021-01-01 14:27:58 +00:00
|
|
|
const regexpTester = (() => {
|
2017-10-07 15:40:37 +00:00
|
|
|
const OWN_ICON = chrome.runtime.getManifest().icons['16'];
|
|
|
|
const cachedRegexps = new Map();
|
|
|
|
let currentRegexps = [];
|
2021-01-01 14:27:58 +00:00
|
|
|
let isWatching = false;
|
|
|
|
let isShown = false;
|
2017-10-07 15:40:37 +00:00
|
|
|
|
2021-01-01 14:27:58 +00:00
|
|
|
return {
|
2017-10-07 15:40:37 +00:00
|
|
|
|
2021-01-01 14:27:58 +00:00
|
|
|
toggle(state = !isShown) {
|
|
|
|
if (state && !isShown) {
|
|
|
|
if (!isWatching) {
|
|
|
|
isWatching = true;
|
2021-09-11 12:58:59 +00:00
|
|
|
chrome.tabs.onRemoved.addListener(onTabRemoved);
|
|
|
|
chrome.tabs.onUpdated.addListener(onTabUpdated);
|
2021-01-01 14:27:58 +00:00
|
|
|
}
|
|
|
|
helpPopup.show('', $create('.regexp-report'));
|
2021-07-30 04:37:33 +00:00
|
|
|
window.on('closeHelp', () => regexpTester.toggle(false), {once: true});
|
2021-01-01 14:27:58 +00:00
|
|
|
isShown = true;
|
|
|
|
} else if (!state && isShown) {
|
|
|
|
unwatch();
|
|
|
|
helpPopup.close();
|
|
|
|
isShown = false;
|
2017-10-29 17:07:08 +00:00
|
|
|
}
|
2021-01-01 14:27:58 +00:00
|
|
|
},
|
2017-10-07 15:40:37 +00:00
|
|
|
|
2021-01-01 14:27:58 +00:00
|
|
|
async update(newRegexps) {
|
|
|
|
if (!isShown) {
|
|
|
|
unwatch();
|
|
|
|
return;
|
2017-10-29 17:07:08 +00:00
|
|
|
}
|
2021-01-01 14:27:58 +00:00
|
|
|
if (newRegexps) {
|
|
|
|
currentRegexps = newRegexps;
|
2017-10-07 15:40:37 +00:00
|
|
|
}
|
2021-01-01 14:27:58 +00:00
|
|
|
const regexps = currentRegexps.map(text => {
|
|
|
|
const rxData = Object.assign({text}, cachedRegexps.get(text));
|
|
|
|
if (!rxData.urls) {
|
|
|
|
cachedRegexps.set(text, Object.assign(rxData, {
|
|
|
|
// imitate buggy Stylish-for-chrome
|
|
|
|
rx: tryRegExp('^' + text + '$'),
|
|
|
|
urls: new Map(),
|
|
|
|
}));
|
|
|
|
}
|
|
|
|
return rxData;
|
|
|
|
});
|
|
|
|
const getMatchInfo = m => m && {text: m[0], pos: m.index};
|
|
|
|
const tabs = await browser.tabs.query({});
|
2020-09-22 10:54:48 +00:00
|
|
|
const supported = tabs.map(tab => tab.pendingUrl || tab.url).filter(URLS.supported);
|
2017-10-07 15:40:37 +00:00
|
|
|
const unique = [...new Set(supported).values()];
|
|
|
|
for (const rxData of regexps) {
|
|
|
|
const {rx, urls} = rxData;
|
|
|
|
if (rx) {
|
|
|
|
const urlsNow = new Map();
|
|
|
|
for (const url of unique) {
|
|
|
|
const match = urls.get(url) || getMatchInfo(url.match(rx));
|
|
|
|
if (match) {
|
|
|
|
urlsNow.set(url, match);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
rxData.urls = urlsNow;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
const stats = {
|
|
|
|
full: {data: [], label: t('styleRegexpTestFull')},
|
2021-01-01 14:27:58 +00:00
|
|
|
partial: {
|
|
|
|
data: [], label: [
|
|
|
|
t('styleRegexpTestPartial'),
|
|
|
|
t.template.regexpTestPartial.cloneNode(true),
|
|
|
|
],
|
|
|
|
},
|
2017-10-07 15:40:37 +00:00
|
|
|
none: {data: [], label: t('styleRegexpTestNone')},
|
|
|
|
invalid: {data: [], label: t('styleRegexpTestInvalid')},
|
|
|
|
};
|
|
|
|
// collect stats
|
|
|
|
for (const {text, rx, urls} of regexps) {
|
|
|
|
if (!rx) {
|
|
|
|
stats.invalid.data.push({text});
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
if (!urls.size) {
|
|
|
|
stats.none.data.push({text});
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
const full = [];
|
|
|
|
const partial = [];
|
|
|
|
for (const [url, match] of urls.entries()) {
|
|
|
|
const faviconUrl = url.startsWith(URLS.ownOrigin)
|
|
|
|
? OWN_ICON
|
2022-01-27 02:07:28 +00:00
|
|
|
: URLS.favicon(new URL(url).hostname);
|
2017-12-03 21:12:09 +00:00
|
|
|
const icon = $create('img', {src: faviconUrl});
|
2017-10-07 15:40:37 +00:00
|
|
|
if (match.text.length === url.length) {
|
2021-03-19 19:53:52 +00:00
|
|
|
full.push($create('a', {tabIndex: 0}, [
|
2017-10-07 15:40:37 +00:00
|
|
|
icon,
|
|
|
|
url,
|
2017-12-03 21:12:09 +00:00
|
|
|
]));
|
2017-10-07 15:40:37 +00:00
|
|
|
} else {
|
2021-03-19 19:53:52 +00:00
|
|
|
partial.push($create('a', {tabIndex: 0}, [
|
2017-10-07 15:40:37 +00:00
|
|
|
icon,
|
|
|
|
url.substr(0, match.pos),
|
2017-12-03 21:12:09 +00:00
|
|
|
$create('mark', match.text),
|
2017-10-07 15:40:37 +00:00
|
|
|
url.substr(match.pos + match.text.length),
|
2017-12-03 21:12:09 +00:00
|
|
|
]));
|
2017-10-07 15:40:37 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
if (full.length) {
|
|
|
|
stats.full.data.push({text, urls: full});
|
|
|
|
}
|
|
|
|
if (partial.length) {
|
|
|
|
stats.partial.data.push({text, urls: partial});
|
|
|
|
}
|
|
|
|
}
|
|
|
|
// render stats
|
2017-12-03 21:12:09 +00:00
|
|
|
const report = $create('.regexp-report');
|
|
|
|
const br = $create('br');
|
2017-10-07 15:40:37 +00:00
|
|
|
for (const type in stats) {
|
|
|
|
// top level groups: full, partial, none, invalid
|
|
|
|
const {label, data} = stats[type];
|
|
|
|
if (!data.length) {
|
|
|
|
continue;
|
|
|
|
}
|
2017-12-03 21:12:09 +00:00
|
|
|
const block = report.appendChild(
|
|
|
|
$create('details', {open: true, dataset: {type}}, [
|
|
|
|
$create('summary', label),
|
|
|
|
]));
|
2017-10-07 15:40:37 +00:00
|
|
|
// 2nd level: regexp text
|
|
|
|
for (const {text, urls} of data) {
|
|
|
|
if (urls) {
|
|
|
|
// type is partial or full
|
2017-12-03 21:12:09 +00:00
|
|
|
block.appendChild(
|
|
|
|
$create('details', {open: true}, [
|
|
|
|
$create('summary', text),
|
2021-09-11 12:53:10 +00:00
|
|
|
$create('div', urls),
|
2017-12-03 21:12:09 +00:00
|
|
|
]));
|
2017-10-07 15:40:37 +00:00
|
|
|
} else {
|
|
|
|
// type is none or invalid
|
|
|
|
block.appendChild(document.createTextNode(text));
|
|
|
|
block.appendChild(br.cloneNode());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2021-01-01 14:27:58 +00:00
|
|
|
helpPopup.show(t('styleRegexpTestTitle'), report);
|
2017-12-13 04:33:16 +00:00
|
|
|
report.onclick = onClick;
|
2017-10-07 15:40:37 +00:00
|
|
|
|
2017-12-05 18:55:01 +00:00
|
|
|
const note = $create('p.regexp-report-note',
|
|
|
|
t('styleRegexpTestNote')
|
|
|
|
.split(/(\\+)/)
|
|
|
|
.map(s => (s.startsWith('\\') ? $create('code', s) : s)));
|
|
|
|
report.appendChild(note);
|
2021-02-27 17:42:49 +00:00
|
|
|
report.style.paddingBottom = note.offsetHeight + 'px';
|
2021-01-01 14:27:58 +00:00
|
|
|
},
|
|
|
|
};
|
2017-12-13 04:33:16 +00:00
|
|
|
|
2021-01-01 14:27:58 +00:00
|
|
|
function onClick(event) {
|
2021-02-27 17:42:49 +00:00
|
|
|
const a = event.target.closest('a, button');
|
2021-01-01 14:27:58 +00:00
|
|
|
if (a) {
|
|
|
|
event.preventDefault();
|
|
|
|
openURL({
|
2021-02-27 17:42:49 +00:00
|
|
|
url: a.href || a.textContent,
|
2021-01-01 14:27:58 +00:00
|
|
|
currentWindow: null,
|
|
|
|
});
|
2017-12-13 04:33:16 +00:00
|
|
|
}
|
2021-01-01 14:27:58 +00:00
|
|
|
}
|
2017-12-13 04:33:16 +00:00
|
|
|
|
2021-09-11 12:58:59 +00:00
|
|
|
function onTabRemoved() {
|
|
|
|
regexpTester.update();
|
|
|
|
}
|
|
|
|
|
|
|
|
function onTabUpdated(tabId, info) {
|
2021-01-01 14:27:58 +00:00
|
|
|
if (info.url) {
|
|
|
|
regexpTester.update();
|
2017-12-13 04:33:16 +00:00
|
|
|
}
|
2017-10-07 15:40:37 +00:00
|
|
|
}
|
|
|
|
|
2021-01-01 14:27:58 +00:00
|
|
|
function unwatch() {
|
|
|
|
if (isWatching) {
|
2021-09-11 12:58:59 +00:00
|
|
|
chrome.tabs.onRemoved.removeListener(onTabRemoved);
|
|
|
|
chrome.tabs.onUpdated.removeListener(onTabUpdated);
|
2021-01-01 14:27:58 +00:00
|
|
|
isWatching = false;
|
|
|
|
}
|
|
|
|
}
|
2017-10-07 15:40:37 +00:00
|
|
|
})();
|