avoid overwriting existing usercss on saving a new one

This commit is contained in:
tophf 2018-08-18 23:17:20 +03:00
parent 4bcdbb78b1
commit c0c5f1dbcc
4 changed files with 42 additions and 10 deletions

View File

@ -1259,6 +1259,10 @@
"message": "Specify @name in the code", "message": "Specify @name in the code",
"description": "Placeholder text for the empty name input field when creating a new Usercss style" "description": "Placeholder text for the empty name input field when creating a new Usercss style"
}, },
"usercssAvoidOverwriting": {
"message": "Please change the value of @name or @namespace to avoid overwriting an existing style.",
"description": "Shown in a message box when attempting to save a new Usercss style that would overwrite an existing one."
},
"usercssReplaceTemplateConfirmation": { "usercssReplaceTemplateConfirmation": {
"message": "Replace the default template for new Usercss styles with the current code?" "message": "Replace the default template for new Usercss styles with the current code?"
}, },

View File

@ -65,10 +65,21 @@
return style; return style;
} }
// Parse the source and find the duplication /**
function build({sourceCode, checkDup = false}) { * Parse the source and find the duplication
return buildMeta({sourceCode}) * @param _
.then(usercss.buildCode) * @param {String} _.sourceCode
* @param {Boolean=} _.checkDup
* @param {Boolean=} _.metaOnly
* @returns {Promise<{style, dup:Boolean?}>}
*/
function build({
sourceCode,
checkDup,
metaOnly,
}) {
const task = buildMeta({sourceCode});
return (metaOnly ? task : task.then(usercss.buildCode))
.then(style => ({ .then(style => ({
style, style,
dup: checkDup && find(style), dup: checkDup && find(style),

View File

@ -122,11 +122,11 @@ function createSourceEditor(style) {
style.sourceCode = ''; style.sourceCode = '';
chromeSync.getLZValue('usercssTemplate').then(code => { chromeSync.getLZValue('usercssTemplate').then(code => {
const name = style.name || t('usercssReplaceTemplateName');
const date = new Date().toLocaleString();
code = code || DEFAULT_CODE; code = code || DEFAULT_CODE;
code = code.replace(/@name(\s*)(?=[\r\n])/, (str, space) => code = code.replace(/@name(\s*)(?=[\r\n])/, (str, space) =>
`${str}${space ? '' : ' '}${ `${str}${space ? '' : ' '}${name} - ${date}`);
style.name ||
t('usercssReplaceTemplateName') + ' - ' + new Date().toLocaleString()}`);
// strip the last dummy section if any, add an empty line followed by the section // strip the last dummy section if any, add an empty line followed by the section
style.sourceCode = code.replace(/\s*@-moz-document[^{]*\{[^}]*\}\s*$|\s+$/g, '') + '\n\n' + section; style.sourceCode = code.replace(/\s*@-moz-document[^{]*\{[^}]*\}\s*$|\s+$/g, '') + '\n\n' + section;
cm.startOperation(); cm.startOperation();
@ -202,8 +202,8 @@ function createSourceEditor(style) {
function save() { function save() {
if (!dirty.isDirty()) return; if (!dirty.isDirty()) return;
const code = cm.getValue(); const code = cm.getValue();
return ( return ensureUniqueStyle(code)
API.saveUsercssUnsafe({ .then(() => API.saveUsercssUnsafe({
id: style.id, id: style.id,
reason: 'editSave', reason: 'editSave',
enabled: style.enabled, enabled: style.enabled,
@ -214,6 +214,7 @@ function createSourceEditor(style) {
if (errors) return Promise.reject(errors); if (errors) return Promise.reject(errors);
}) })
.catch(err => { .catch(err => {
if (err.handled) return;
if (err.message === t('styleMissingMeta', 'name')) { if (err.message === t('styleMissingMeta', 'name')) {
messageBox.confirm(t('usercssReplaceTemplateConfirmation')).then(ok => ok && messageBox.confirm(t('usercssReplaceTemplateConfirmation')).then(ok => ok &&
chromeSync.setLZValue('usercssTemplate', code) chromeSync.setLZValue('usercssTemplate', code)
@ -233,6 +234,20 @@ function createSourceEditor(style) {
}); });
} }
function ensureUniqueStyle(code) {
return style.id ? Promise.resolve() :
API.buildUsercss({
sourceCode: code,
checkDup: true,
metaOnly: true,
}).then(({dup}) => {
if (dup) {
messageBox.alert(t('usercssAvoidOverwriting'), 'danger', t('genericError'));
return Promise.reject({handled: true});
}
});
}
function drawLinePointer(pos) { function drawLinePointer(pos) {
const SIZE = 60; const SIZE = 60;
const line = cm.getLine(pos.line); const line = cm.getLine(pos.line);

View File

@ -150,10 +150,12 @@ function messageBox({
/** /**
* @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>} same as messageBox * @returns {Promise<Boolean>} same as messageBox
*/ */
messageBox.alert = (contents, className) => messageBox.alert = (contents, className, title) =>
messageBox({ messageBox({
title,
contents, contents,
className: `center ${className || ''}`, className: `center ${className || ''}`,
buttons: [t('confirmClose')] buttons: [t('confirmClose')]