diff --git a/_locales/en/messages.json b/_locales/en/messages.json index 2b1d4f87..a1529384 100644 --- a/_locales/en/messages.json +++ b/_locales/en/messages.json @@ -183,6 +183,13 @@ "message": "Open color picker", "description": "Tooltip for the colored squares shown before CSS colors in the style editor." }, + "configOnChange": { + "message": "on change", + "description": "VERY SHORT label for the checkbox in style config dialog after the save button - when enabled the changes in the dialog are saved and applied automatically without the need to press the Save button" + }, + "configOnChangeTooltip": { + "message": "Autosave and apply changes automatically" + }, "dysfunctional": { "message": "Stylus cannot function in private windows because Firefox disallows direct connection to the internal background page context of the extension.", "description": "Displayed in Firefox when its settings make Stylus dysfunctional" diff --git a/js/prefs.js b/js/prefs.js index 4eb5b0db..080b3a6a 100644 --- a/js/prefs.js +++ b/js/prefs.js @@ -11,6 +11,9 @@ var prefs = new function Prefs() { 'exposeIframes': false, // Add 'stylus-iframe' attribute to HTML element in all iframes 'newStyleAsUsercss': false, // create new style in usercss format + // checkbox in style config dialog + 'config.autosave': true, + 'popup.breadcrumbs': true, // display 'New style' links as URL breadcrumbs 'popup.breadcrumbs.usePath': false, // use URL path for 'this URL' 'popup.enabledFirst': true, // display enabled styles before disabled styles diff --git a/manage/config-dialog.css b/manage/config-dialog.css index 9edc3e1a..639cc856 100644 --- a/manage/config-dialog.css +++ b/manage/config-dialog.css @@ -1,11 +1,11 @@ /* config dialog */ -.config-dialog .config-heading { +.config-heading { float: right; margin: -1.25rem 0 0 0; font-size: 0.9em; } -.config-dialog label { +.config-body label { display: flex; padding: .75em 0; align-items: center; @@ -15,28 +15,28 @@ position: static; } -.config-dialog label:first-child { +.config-body label:first-child { padding-top: 0; } -.config-dialog label:last-child { +.config-body label:last-child { padding-bottom: 0; } -.config-dialog label:not(:first-child) { +.config-body label:not(:first-child) { border-top: 1px dotted #ccc; } -.config-dialog label > :first-child { +.config-body label > :first-child { margin-right: 8px; flex-grow: 1; } -.config-dialog label:not([disabled]) > :first-child { +.config-body label:not([disabled]) > :first-child { cursor: default; } -.config-dialog label:not([disabled]):hover > :first-child { +.config-body label:not([disabled]):hover > :first-child { text-shadow: 0 0 0.01px rgba(0, 0, 0, .25); cursor: pointer; } @@ -51,9 +51,9 @@ font-style: italic; } -.config-dialog input, -.config-dialog select, -.config-dialog .onoffswitch { +.config-body input, +.config-body select, +.config-body .onoffswitch { width: var(--onoffswitch-width); margin: 0; height: 2em; @@ -61,8 +61,8 @@ vertical-align: middle; } -.config-dialog .select-resizer, -.config-dialog select { +.config-body .select-resizer, +.config-body select { width: auto; min-width: var(--onoffswitch-width); max-width: 124px; @@ -70,24 +70,30 @@ position: relative; } -.config-dialog .onoffswitch { +.config-body .onoffswitch { height: auto; margin: calc((2em - 12px) / 2) 0; } -.config-dialog input[type="text"] { +.config-body input[type="text"] { padding-left: 0.25em; } -.config-dialog label > :last-child { +.config-body label > :last-child { box-sizing: border-box; flex-shrink: 0; } -.config-dialog label > :last-child:not(.onoffswitch):not(.select-resizer) > :not(:last-child) { +.config-body label > :last-child:not(.onoffswitch):not(.select-resizer) > :not(:last-child) { margin-right: 4px; } +#config-autosave-wrapper { + position: relative; + padding: 0 0 0 16px; + display: inline-flex; +} + .cm-colorview::before, .color-swatch { width: var(--onoffswitch-width) !important; diff --git a/manage/config-dialog.js b/manage/config-dialog.js index 6c6e3273..53043e20 100644 --- a/manage/config-dialog.js +++ b/manage/config-dialog.js @@ -46,10 +46,22 @@ function configDialog(style) { } function onshow(box) { + $('button', box).insertAdjacentElement('afterend', + $create('label#config-autosave-wrapper', { + title: t('configOnChangeTooltip'), + }, [ + $create('input', {id: 'config.autosave', type: 'checkbox'}), + $create('SVG:svg.svg-icon.checked', + $create('SVG:use', {'xlink:href': '#svg-icon-checked'})), + t('configOnChange'), + ])); + setupLivePrefs(['config.autosave']); + if (isPopup) { adjustSizeForPopup(box); box.style.animationDuration = '0s'; } + box.addEventListener('change', onchange); buttons.save = $('[data-cmd="save"]', box); buttons.default = $('[data-cmd="default"]', box); @@ -62,8 +74,12 @@ function configDialog(style) { const va = target.va; if (va) { va.dirty = varsInitial[va.name] !== (isDefault(va) ? va.default : va.value); - target.closest('label').classList.toggle('dirty', va.dirty); - updateButtons(); + if (prefs.get('config.autosave')) { + debounce(save, 100); + } else { + target.closest('label').classList.toggle('dirty', va.dirty); + updateButtons(); + } } }