editor import: warn about invalid -moz-document functions
* fixes #118 * alleviates #116 by switching showRegExpTester() from innerHTML to DOM
This commit is contained in:
parent
e48e1ab874
commit
b50c19a802
101
edit/edit.js
101
edit/edit.js
|
@ -1557,7 +1557,7 @@ function fromMozillaFormat() {
|
|||
const parser = new parserlib.css.Parser();
|
||||
const lines = mozStyle.split('\n');
|
||||
const sectionStack = [{code: '', start: {line: 1, col: 1}}];
|
||||
let errors = '';
|
||||
const errors = [];
|
||||
// let oldSectionCount = editors.length;
|
||||
let firstAddedCM;
|
||||
|
||||
|
@ -1575,12 +1575,16 @@ function fromMozillaFormat() {
|
|||
doAddSection(sectionStack.last);
|
||||
sectionStack.last.code = '';
|
||||
}
|
||||
e.functions.forEach(f => {
|
||||
const m = f.match(/^(url|url-prefix|domain|regexp)\((['"]?)(.+?)\2?\)$/);
|
||||
for (const f of e.functions) {
|
||||
const m = f && f.match(/^([\w-]*)\((['"]?)(.+?)\2?\)$/);
|
||||
if (!m || !/^(url|url-prefix|domain|regexp)$/.test(m[1])) {
|
||||
errors.push(`${e.line}:${e.col + 1} invalid function "${m ? m[1] : f || ''}"`);
|
||||
continue;
|
||||
}
|
||||
const aType = CssToProperty[m[1]];
|
||||
const aValue = aType !== 'regexps' ? m[3] : m[3].replace(/\\\\/g, '\\');
|
||||
(section[aType] = section[aType] || []).push(aValue);
|
||||
});
|
||||
}
|
||||
sectionStack.push(section);
|
||||
});
|
||||
|
||||
|
@ -1607,12 +1611,16 @@ function fromMozillaFormat() {
|
|||
firstAddedCM.focus();
|
||||
|
||||
if (errors) {
|
||||
showHelp(t('issues'), errors);
|
||||
showHelp(t('issues'), $element({
|
||||
tag: 'pre',
|
||||
textContent: errors.join('\n'),
|
||||
}));
|
||||
}
|
||||
});
|
||||
|
||||
parser.addListener('error', e => {
|
||||
errors += e.line + ':' + e.col + ' ' + e.message.replace(/ at line \d.+$/, '') + '<br>';
|
||||
errors.push(e.line + ':' + e.col + ' ' +
|
||||
e.message.replace(/ at line \d.+$/, ''));
|
||||
});
|
||||
|
||||
parser.parse(mozStyle);
|
||||
|
@ -1834,13 +1842,16 @@ function showRegExpTester(event, section = getSectionForChild(this)) {
|
|||
rxData.urls = urlsNow;
|
||||
}
|
||||
}
|
||||
const moreInfoLink = template.regexpTestPartial.outerHTML;
|
||||
const stats = {
|
||||
full: {data: [], label: t('styleRegexpTestFull')},
|
||||
partial: {data: [], label: t('styleRegexpTestPartial') + moreInfoLink},
|
||||
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});
|
||||
|
@ -1856,12 +1867,18 @@ function showRegExpTester(event, section = getSectionForChild(this)) {
|
|||
const faviconUrl = url.startsWith(URLS.ownOrigin)
|
||||
? OWN_ICON
|
||||
: GET_FAVICON_URL + new URL(url).hostname;
|
||||
const icon = `<img src="${faviconUrl}">`;
|
||||
const icon = $element({tag: 'img', src: faviconUrl});
|
||||
if (match.length === url.length) {
|
||||
full.push(`<div>${icon + url}</div>`);
|
||||
full.push($element({appendChild: [
|
||||
icon,
|
||||
url,
|
||||
]}));
|
||||
} else {
|
||||
partial.push(`<div>${icon}<mark>${match}</mark>` +
|
||||
url.substr(match.length) + '</div>');
|
||||
partial.push($element({appendChild: [
|
||||
icon,
|
||||
$element({tag: 'mark', textContent: match}),
|
||||
url.substr(match.length),
|
||||
]}));
|
||||
}
|
||||
}
|
||||
if (full.length) {
|
||||
|
@ -1871,17 +1888,42 @@ function showRegExpTester(event, section = getSectionForChild(this)) {
|
|||
stats.partial.data.push({text, urls: partial});
|
||||
}
|
||||
}
|
||||
showHelp(t('styleRegexpTestTitle'),
|
||||
'<div class="regexp-report">' +
|
||||
Object.keys(stats).map(type => (!stats[type].data.length ? '' :
|
||||
`<details open data-type="${type}">
|
||||
<summary>${stats[type].label}</summary>` +
|
||||
stats[type].data.map(({text, urls}) => (!urls ? text :
|
||||
`<details open><summary>${text}</summary>${urls.join('')}</details>`
|
||||
)).join('<br>') +
|
||||
'</details>'
|
||||
)).join('') +
|
||||
'</div>');
|
||||
// render stats
|
||||
const report = $element({className: 'regexp-report'});
|
||||
const br = $element({tag: 'br'});
|
||||
for (const type in stats) {
|
||||
// top level groups: full, partial, none, invalid
|
||||
const {label, data} = stats[type];
|
||||
if (!data.length) {
|
||||
continue;
|
||||
}
|
||||
// 2nd level: regexp text
|
||||
const summary = $element({tag: 'summary', appendChild: label});
|
||||
const block = [summary];
|
||||
for (const {text, urls} of data) {
|
||||
if (!urls) {
|
||||
block.push(text, br.cloneNode());
|
||||
continue;
|
||||
}
|
||||
block.push($element({
|
||||
tag: 'details',
|
||||
open: true,
|
||||
appendChild: [
|
||||
$element({tag: 'summary', textContent: text}),
|
||||
// 3rd level: tab urls
|
||||
...urls,
|
||||
],
|
||||
}));
|
||||
}
|
||||
report.appendChild($element({
|
||||
tag: 'details',
|
||||
open: true,
|
||||
dataset: {type},
|
||||
appendChild: block,
|
||||
}));
|
||||
}
|
||||
showHelp(t('styleRegexpTestTitle'), report);
|
||||
|
||||
document.querySelector('.regexp-report').onclick = event => {
|
||||
const target = event.target.closest('a, .regexp-report div');
|
||||
if (target) {
|
||||
|
@ -1893,10 +1935,17 @@ function showRegExpTester(event, section = getSectionForChild(this)) {
|
|||
}
|
||||
|
||||
function showHelp(title, text) {
|
||||
const div = document.getElementById('help-popup');
|
||||
const div = $('#help-popup');
|
||||
div.classList.remove('big');
|
||||
div.querySelector('.contents').innerHTML = text;
|
||||
div.querySelector('.title').innerHTML = title;
|
||||
|
||||
const contents = $('.contents', div);
|
||||
if (text instanceof HTMLElement) {
|
||||
contents.textContent = '';
|
||||
contents.appendChild(text);
|
||||
} else {
|
||||
contents.innerHTML = text;
|
||||
}
|
||||
$('.title', div).textContent = title;
|
||||
|
||||
if (getComputedStyle(div).display === 'none') {
|
||||
document.addEventListener('keydown', closeHelp);
|
||||
|
|
10
js/dom.js
10
js/dom.js
|
@ -106,7 +106,7 @@ function $$(selector, base = document) {
|
|||
|
||||
function $element(opt) {
|
||||
// tag: string, default 'div', may include namespace like 'ns#tag'
|
||||
// appendChild: element or an array of elements
|
||||
// appendChild: element/string or an array of elements/strings
|
||||
// dataset: object
|
||||
// any DOM property: assigned as is
|
||||
const [ns, tag] = opt.tag && opt.tag.includes('#')
|
||||
|
@ -115,8 +115,12 @@ function $element(opt) {
|
|||
const element = ns
|
||||
? document.createElementNS(ns === 'SVG' || ns === 'svg' ? 'http://www.w3.org/2000/svg' : ns, tag)
|
||||
: document.createElement(tag || 'div');
|
||||
(opt.appendChild instanceof Array ? opt.appendChild : [opt.appendChild])
|
||||
.forEach(child => child && element.appendChild(child));
|
||||
const children = opt.appendChild instanceof Array ? opt.appendChild : [opt.appendChild];
|
||||
for (const child of children) {
|
||||
if (child) {
|
||||
element.appendChild(child instanceof Node ? child : document.createTextNode(child));
|
||||
}
|
||||
}
|
||||
delete opt.appendChild;
|
||||
delete opt.tag;
|
||||
if (opt.dataset) {
|
||||
|
|
Loading…
Reference in New Issue
Block a user