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