stylus/edit/regexp-tester.js

194 lines
5.5 KiB
JavaScript
Raw Permalink Normal View History

2017-10-07 15:40:37 +00:00
/* global showHelp */
'use strict';
// eslint-disable-next-line no-var
2017-10-29 17:22:10 +00:00
var regExpTester = (() => {
2017-10-07 15:40:37 +00:00
const GET_FAVICON_URL = 'https://www.google.com/s2/favicons?domain=';
const OWN_ICON = chrome.runtime.getManifest().icons['16'];
const cachedRegexps = new Map();
let currentRegexps = [];
2017-10-29 17:07:08 +00:00
let isInit = false;
2017-10-07 15:40:37 +00:00
2017-10-29 17:07:08 +00:00
function init() {
isInit = true;
chrome.tabs.onUpdated.addListener(onTabUpdate);
}
function uninit() {
chrome.tabs.onUpdated.removeListener(onTabUpdate);
isInit = false;
}
function onTabUpdate(tabId, info) {
2017-10-07 15:40:37 +00:00
if (info.url) {
update();
}
2017-10-29 17:07:08 +00:00
}
2017-10-07 15:40:37 +00:00
function isShown() {
2017-10-29 17:07:08 +00:00
return Boolean($('.regexp-report'));
2017-10-07 15:40:37 +00:00
}
function toggle(state = !isShown()) {
if (state && !isShown()) {
2017-10-29 17:07:08 +00:00
if (!isInit) {
init();
}
showHelp('', $create('.regexp-report'));
} else if (!state && isShown()) {
2017-10-29 17:07:08 +00:00
if (isInit) {
uninit();
}
2017-10-07 15:40:37 +00:00
// TODO: need a closeHelp function
$('#help-popup .dismiss').onclick();
}
}
function update(newRegexps) {
if (!isShown()) {
2017-10-29 17:07:08 +00:00
if (isInit) {
uninit();
}
2017-10-07 15:40:37 +00:00
return;
}
if (newRegexps) {
currentRegexps = newRegexps;
}
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, see detectSloppyRegexps()
rx: tryRegExp('^' + text + '$'),
urls: new Map(),
}));
}
return rxData;
});
const getMatchInfo = m => m && {text: m[0], pos: m.index};
queryTabs().then(tabs => {
const supported = tabs.map(tab => tab.url)
.filter(url => URLS.supported(url));
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')},
partial: {data: [], label: [
t('styleRegexpTestPartial'),
template.regexpTestPartial.cloneNode(true),
]},
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
: GET_FAVICON_URL + new URL(url).hostname;
const icon = $create('img', {src: faviconUrl});
2017-10-07 15:40:37 +00:00
if (match.text.length === url.length) {
full.push($create('a', {href: '#'}, [
2017-10-07 15:40:37 +00:00
icon,
url,
]));
2017-10-07 15:40:37 +00:00
} else {
partial.push($create('a', {href: '#'}, [
2017-10-07 15:40:37 +00:00
icon,
url.substr(0, match.pos),
$create('mark', match.text),
2017-10-07 15:40:37 +00:00
url.substr(match.pos + match.text.length),
]));
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
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;
}
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
block.appendChild(
$create('details', {open: true}, [
$create('summary', text),
2017-10-07 15:40:37 +00:00
// 3rd level: tab urls
...urls,
]));
2017-10-07 15:40:37 +00:00
} else {
// type is none or invalid
block.appendChild(document.createTextNode(text));
block.appendChild(br.cloneNode());
}
}
}
showHelp(t('styleRegexpTestTitle'), report);
report.onclick = onClick;
2017-10-07 15:40:37 +00:00
const note = $create('p.regexp-report-note',
t('styleRegexpTestNote')
.split(/(\\+)/)
.map(s => (s.startsWith('\\') ? $create('code', s) : s)));
report.appendChild(note);
adjustNote(report, note);
2017-10-07 15:40:37 +00:00
});
function onClick(event) {
const a = event.target.closest('a');
if (a) {
event.preventDefault();
openURL({
url: a.href && a.getAttribute('href') !== '#' && a.href || a.textContent,
currentWindow: null,
});
} else if (event.target.closest('details')) {
setTimeout(adjustNote);
}
}
function adjustNote(report, note) {
report.style.paddingBottom = note.offsetHeight + 'px';
}
2017-10-07 15:40:37 +00:00
}
return {toggle, update};
})();