warn when paste-importing usercss with @preprocessor, #1082
This commit is contained in:
commit
1a7b51be6b
|
@ -468,6 +468,12 @@
|
||||||
"message": "Import",
|
"message": "Import",
|
||||||
"description": "Label for the button to import a style ('edit' page) or all styles ('manage' page)"
|
"description": "Label for the button to import a style ('edit' page) or all styles ('manage' page)"
|
||||||
},
|
},
|
||||||
|
"importPreprocessor": {
|
||||||
|
"message": "Style with a <code>@preprocessor</code> won't work in the classic mode. You can switch the editor to Usercss mode: 1) open the style manager, 2) enable \"as Usercss\" checkbox, 3) click \"Write new style\"\n\nImport now anyway?"
|
||||||
|
},
|
||||||
|
"importPreprocessorTitle": {
|
||||||
|
"message": "Potential problem due to @preprocessor"
|
||||||
|
},
|
||||||
"importReplaceLabel": {
|
"importReplaceLabel": {
|
||||||
"message": "Overwrite style",
|
"message": "Overwrite style",
|
||||||
"description": "Label for the button to import and overwrite current style"
|
"description": "Label for the button to import and overwrite current style"
|
||||||
|
|
|
@ -8,6 +8,7 @@ const usercssHelper = (() => {
|
||||||
API_METHODS.configUsercssVars = configUsercssVars;
|
API_METHODS.configUsercssVars = configUsercssVars;
|
||||||
|
|
||||||
API_METHODS.buildUsercss = build;
|
API_METHODS.buildUsercss = build;
|
||||||
|
API_METHODS.buildUsercssMeta = buildMeta;
|
||||||
API_METHODS.findUsercss = find;
|
API_METHODS.findUsercss = find;
|
||||||
|
|
||||||
function buildMeta(style) {
|
function buildMeta(style) {
|
||||||
|
|
|
@ -176,10 +176,9 @@ function createSection({
|
||||||
});
|
});
|
||||||
cm.on('paste', (cm, event) => {
|
cm.on('paste', (cm, event) => {
|
||||||
const text = event.clipboardData.getData('text') || '';
|
const text = event.clipboardData.getData('text') || '';
|
||||||
if (
|
if (/@-moz-document/i.test(text) &&
|
||||||
text.includes('@-moz-document') &&
|
/@-moz-document\s+(url|url-prefix|domain|regexp)\(/i
|
||||||
text.replace(/\/\*[\s\S]*?(?:\*\/|$)/g, '')
|
.test(text.replace(/\/\*([^*]|\*(?!\/))*(\*\/|$)/g, ''))
|
||||||
.match(/@-moz-document[\s\r\n]+(url|url-prefix|domain|regexp)\(/)
|
|
||||||
) {
|
) {
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
showMozillaFormatImport(text);
|
showMozillaFormatImport(text);
|
||||||
|
|
|
@ -48,7 +48,7 @@ function createSectionsEditor(editorBase) {
|
||||||
|
|
||||||
let sectionOrder = '';
|
let sectionOrder = '';
|
||||||
let headerOffset; // in compact mode the header is at the top so it reduces the available height
|
let headerOffset; // in compact mode the header is at the top so it reduces the available height
|
||||||
const ready = initSections(style.sections, {isFirstInit: true});
|
const ready = initSections(style.sections, {pristine: true});
|
||||||
|
|
||||||
const livePreview = createLivePreview();
|
const livePreview = createLivePreview();
|
||||||
livePreview.show(Boolean(style.id));
|
livePreview.show(Boolean(style.id));
|
||||||
|
@ -333,24 +333,37 @@ function createSectionsEditor(editorBase) {
|
||||||
'Shift-Ctrl-Enter': () => doImport({replaceOldStyle: true}),
|
'Shift-Ctrl-Enter': () => doImport({replaceOldStyle: true}),
|
||||||
};
|
};
|
||||||
|
|
||||||
function doImport({replaceOldStyle = false}) {
|
async function doImport({replaceOldStyle = false}) {
|
||||||
lockPageUI(true);
|
lockPageUI(true);
|
||||||
API.parseCss({code: popup.codebox.getValue().trim()})
|
try {
|
||||||
.then(({sections, errors}) => {
|
const code = popup.codebox.getValue().trim();
|
||||||
|
if (!/==userstyle==/i.test(code) ||
|
||||||
|
!await getPreprocessor(code) ||
|
||||||
|
await messageBox.confirm(
|
||||||
|
t('importPreprocessor'), 'pre-line',
|
||||||
|
t('importPreprocessorTitle'))
|
||||||
|
) {
|
||||||
|
const {sections, errors} = await API.parseCss({code});
|
||||||
// shouldn't happen but just in case
|
// shouldn't happen but just in case
|
||||||
if (!sections.length || errors.length) {
|
if (!sections.length || errors.length) {
|
||||||
throw errors;
|
throw errors;
|
||||||
}
|
}
|
||||||
if (replaceOldStyle) {
|
await initSections(sections, {
|
||||||
return replaceSections(sections);
|
replace: replaceOldStyle,
|
||||||
}
|
focusOn: replaceOldStyle ? 0 : false,
|
||||||
return initSections(sections, {focusOn: false});
|
});
|
||||||
})
|
|
||||||
.then(() => {
|
|
||||||
$('.dismiss').dispatchEvent(new Event('click'));
|
$('.dismiss').dispatchEvent(new Event('click'));
|
||||||
})
|
}
|
||||||
.catch(showError)
|
} catch (err) {
|
||||||
.then(() => lockPageUI(false));
|
showError(err);
|
||||||
|
}
|
||||||
|
lockPageUI(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
async function getPreprocessor(code) {
|
||||||
|
try {
|
||||||
|
return (await API.buildUsercssMeta({sourceCode: code})).usercssData.preprocessor;
|
||||||
|
} catch (e) {}
|
||||||
}
|
}
|
||||||
|
|
||||||
function lockPageUI(locked) {
|
function lockPageUI(locked) {
|
||||||
|
@ -451,8 +464,14 @@ function createSectionsEditor(editorBase) {
|
||||||
|
|
||||||
function initSections(originalSections, {
|
function initSections(originalSections, {
|
||||||
focusOn = 0,
|
focusOn = 0,
|
||||||
isFirstInit,
|
replace = false,
|
||||||
|
pristine = false,
|
||||||
} = {}) {
|
} = {}) {
|
||||||
|
if (replace) {
|
||||||
|
sections.forEach(s => s.remove(true));
|
||||||
|
sections.length = 0;
|
||||||
|
container.textContent = '';
|
||||||
|
}
|
||||||
let done;
|
let done;
|
||||||
const total = originalSections.length;
|
const total = originalSections.length;
|
||||||
originalSections = originalSections.slice();
|
originalSections = originalSections.slice();
|
||||||
|
@ -464,7 +483,7 @@ function createSectionsEditor(editorBase) {
|
||||||
const t0 = performance.now();
|
const t0 = performance.now();
|
||||||
while (originalSections.length && performance.now() - t0 < 100) {
|
while (originalSections.length && performance.now() - t0 < 100) {
|
||||||
insertSectionAfter(originalSections.shift(), undefined, forceRefresh);
|
insertSectionAfter(originalSections.shift(), undefined, forceRefresh);
|
||||||
if (isFirstInit) dirty.clear();
|
if (pristine) dirty.clear();
|
||||||
if (focusOn !== false && sections[focusOn]) {
|
if (focusOn !== false && sections[focusOn]) {
|
||||||
sections[focusOn].cm.focus();
|
sections[focusOn].cm.focus();
|
||||||
focusOn = false;
|
focusOn = false;
|
||||||
|
@ -572,36 +591,21 @@ function createSectionsEditor(editorBase) {
|
||||||
updateSectionOrder();
|
updateSectionOrder();
|
||||||
}
|
}
|
||||||
|
|
||||||
function replaceSections(...args) {
|
async function replaceStyle(newStyle, codeIsUpdated) {
|
||||||
for (const section of sections) {
|
|
||||||
section.remove(true);
|
|
||||||
}
|
|
||||||
sections.length = 0;
|
|
||||||
container.textContent = '';
|
|
||||||
return initSections(...args);
|
|
||||||
}
|
|
||||||
|
|
||||||
function replaceStyle(newStyle, codeIsUpdated) {
|
|
||||||
dirty.clear('name');
|
dirty.clear('name');
|
||||||
// FIXME: avoid recreating all editors?
|
// FIXME: avoid recreating all editors?
|
||||||
reinit().then(() => {
|
if (codeIsUpdated !== false) {
|
||||||
Object.assign(style, newStyle);
|
await initSections(newStyle.sections, {replace: true, pristine: true});
|
||||||
updateHeader();
|
|
||||||
dirty.clear();
|
|
||||||
// Go from new style URL to edit style URL
|
|
||||||
if (location.href.indexOf('id=') === -1 && style.id) {
|
|
||||||
history.replaceState({}, document.title, 'edit.html?id=' + style.id);
|
|
||||||
$('#heading').textContent = t('editStyleHeading');
|
|
||||||
}
|
|
||||||
livePreview.show(Boolean(style.id));
|
|
||||||
updateLivePreview();
|
|
||||||
});
|
|
||||||
|
|
||||||
function reinit() {
|
|
||||||
if (codeIsUpdated !== false) {
|
|
||||||
return replaceSections(newStyle.sections, {isFirstInit: true});
|
|
||||||
}
|
|
||||||
return Promise.resolve();
|
|
||||||
}
|
}
|
||||||
|
Object.assign(style, newStyle);
|
||||||
|
updateHeader();
|
||||||
|
dirty.clear();
|
||||||
|
// Go from new style URL to edit style URL
|
||||||
|
if (location.href.indexOf('id=') === -1 && style.id) {
|
||||||
|
history.replaceState({}, document.title, 'edit.html?id=' + style.id);
|
||||||
|
$('#heading').textContent = t('editStyleHeading');
|
||||||
|
}
|
||||||
|
livePreview.show(Boolean(style.id));
|
||||||
|
updateLivePreview();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -56,6 +56,10 @@
|
||||||
text-align: left;
|
text-align: left;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#message-box.pre-line #message-box-contents {
|
||||||
|
white-space: pre-line;
|
||||||
|
}
|
||||||
|
|
||||||
#message-box-title {
|
#message-box-title {
|
||||||
font-weight: bold;
|
font-weight: bold;
|
||||||
background-color: rgb(145, 208, 198);
|
background-color: rgb(145, 208, 198);
|
||||||
|
|
|
@ -168,10 +168,12 @@ messageBox.alert = (contents, className, title) =>
|
||||||
/**
|
/**
|
||||||
* @param {String|Node|Array<String|Node>} contents
|
* @param {String|Node|Array<String|Node>} contents
|
||||||
* @param {String} [className] like 'pre' for monospace font
|
* @param {String} [className] like 'pre' for monospace font
|
||||||
|
* @param {String} [title]
|
||||||
* @returns {Promise<Boolean>} resolves to true when confirmed
|
* @returns {Promise<Boolean>} resolves to true when confirmed
|
||||||
*/
|
*/
|
||||||
messageBox.confirm = (contents, className) =>
|
messageBox.confirm = (contents, className, title) =>
|
||||||
messageBox({
|
messageBox({
|
||||||
|
title,
|
||||||
contents,
|
contents,
|
||||||
className: `center ${className || ''}`,
|
className: `center ${className || ''}`,
|
||||||
buttons: [t('confirmYes'), t('confirmNo')]
|
buttons: [t('confirmYes'), t('confirmNo')]
|
||||||
|
|
Loading…
Reference in New Issue
Block a user