Merge remote-tracking branch 'upstream/master'

* upstream/master: (45 commits)
  Alas, poor clamp! I knew it well
  Update number input on blur
  Don't re-render input while focused
  Fix undefined value
  Update current value in updateRangeCurrentValue
  Remove onblur, don't save invalid inputs
  Change stored number value on change
  Remove isNumber function
  Fix isNumber function
  Change clamp function order & only call onblur
  Remove misleading comment
  Fix strict equals
  Fix clamp function
  Check for null in isNumber
  Fix clamp function
  Fix clamp undefined step
  Fix clamp undefined min/max
  Switch to isNumber function
  More suggested changes
  Remove unnecessary css
  ...
This commit is contained in:
dana 2018-09-24 05:04:10 -07:00
commit 5a8936e15e
4 changed files with 116 additions and 7 deletions

View File

@ -1051,6 +1051,15 @@
},
"description": "Error displayed when the value of @var color is invalid"
},
"styleMetaErrorRangeOrNumber": {
"message": "Invalid @var $type$: value must be an array containing at least one number at index zero",
"description": "Error displayed when the value of @var number or @var range is invalid",
"placeholders": {
"type": {
"content": "$1"
}
}
},
"styleMetaErrorPreprocessor": {
"message": "Unsupported @preprocessor: $preprocessor$",
"placeholders": {

View File

@ -29,7 +29,7 @@ var usercss = (() => {
['version', 0],
]);
const MANDATORY_META = ['name', 'namespace', 'version'];
const META_VARS = ['text', 'color', 'checkbox', 'select', 'dropdown', 'image'];
const META_VARS = ['text', 'color', 'checkbox', 'select', 'dropdown', 'image', 'number', 'range'];
const META_URLS = [...KNOWN_META.keys()].filter(k => k.endsWith('URL'));
const BUILDER = {
@ -194,12 +194,40 @@ var usercss = (() => {
state.errorPrefix = 'Invalid JSON: ';
parseJSONValue(state);
state.errorPrefix = '';
const extractDefaultOption = (key, value) => {
if (key.endsWith('*')) {
const option = createOption(key.slice(0, -1), value);
result.default = option.name;
return option;
}
return createOption(key, value);
};
if (Array.isArray(state.value)) {
result.options = state.value.map(text => createOption(text));
result.options = state.value.map(k => extractDefaultOption(k));
} else {
result.options = Object.keys(state.value).map(k => createOption(k, state.value[k]));
result.options = Object.keys(state.value).map(k => extractDefaultOption(k, state.value[k]));
}
if (result.default === null) {
result.default = (result.options[0] || {}).name || '';
}
break;
}
case 'number':
case 'range': {
state.errorPrefix = 'Invalid JSON: ';
parseJSONValue(state);
state.errorPrefix = '';
// [default, start, end, step, units] (start, end, step & units are optional)
if (Array.isArray(state.value) && state.value.length) {
// label may be placed anywhere
result.units = (state.value.find(i => typeof i === 'string') || '').replace(/[\d.+-]/g, '');
const range = state.value.filter(i => typeof i === 'number' || i === null);
result.default = range[0];
result.min = range[1];
result.max = range[2];
result.step = range[3] === 0 ? 1 : range[3];
}
result.default = (result.options[0] || {}).name || '';
break;
}
@ -541,6 +569,9 @@ var usercss = (() => {
// TODO: handle customized image
return va.options.find(o => o.name === va[prop]).value;
}
if ((va.type === 'number' || va.type === 'range') && va.units) {
return va[prop] + va.units;
}
return va[prop];
}
@ -578,6 +609,8 @@ var usercss = (() => {
throw new Error(chrome.i18n.getMessage('styleMetaErrorCheckbox'));
} else if (va.type === 'color') {
va[value] = colorConverter.format(colorConverter.parse(va[value]), 'rgb');
} else if ((va.type === 'number' || va.type === 'range') && typeof va[value] !== 'number') {
throw new Error(chrome.i18n.getMessage('styleMetaErrorRangeOrNumber', va.type));
}
}

View File

@ -98,6 +98,15 @@
margin-right: 4px;
}
.current-value {
padding: 2px 4px;
margin-right: 4px;
}
.config-number span, .config-range span {
line-height: 22px;
}
.config-body label:not(.nondefault) .config-reset-icon {
visibility: hidden;
}

View File

@ -258,16 +258,44 @@ function configDialog(style) {
];
break;
case 'range':
case 'number': {
const options = {
va,
type: va.type,
onfocus: va.type === 'number' ? selectAllOnFocus : null,
onblur: va.type === 'number' ? updateVarOnBlur : null,
onchange: updateVarOnChange,
oninput: updateVarOnInput,
required: true
};
if (typeof va.min === 'number') {
options.min = va.min;
}
if (typeof va.max === 'number') {
options.max = va.max;
}
if (typeof va.step === 'number' && isFinite(va.step)) {
options.step = va.step;
}
children = [
va.type === 'range' && $create('span.current-value'),
va.input = $create('input.config-value', options)
];
break;
}
default:
children = [
va.input = $create('input.config-value', {
va,
type: 'text',
type: va.type,
onchange: updateVarOnChange,
oninput: updateVarOnInput,
onfocus: selectAllOnFocus,
}),
];
break;
}
resetter = resetter.cloneNode(true);
@ -285,8 +313,28 @@ function configDialog(style) {
}
}
function updateVarOnBlur() {
this.value = isDefault(this.va) ? this.va.default : this.va.value;
}
function updateVarOnChange() {
this.va.value = this.type !== 'checkbox' ? this.value : this.checked ? '1' : '0';
if (this.type === 'range') {
this.va.value = Number(this.value);
updateRangeCurrentValue(this.va, this.va.value);
} else if (this.type === 'number') {
if (this.reportValidity()) {
this.va.value = Number(this.value);
}
} else {
this.va.value = this.type !== 'checkbox' ? this.value : this.checked ? '1' : '0';
}
}
function updateRangeCurrentValue(va, value) {
const span = $('.current-value', va.input.closest('.config-range'));
if (span) {
span.textContent = value + (va.units || '');
}
}
function updateVarOnInput(event, debounced = false) {
@ -297,8 +345,15 @@ function configDialog(style) {
}
}
function selectAllOnFocus(event) {
event.target.select();
}
function renderValues(varsToRender = vars) {
for (const va of varsToRender) {
if (va.input === document.activeElement) {
continue;
}
const value = isDefault(va) ? va.default : va.value;
if (va.type === 'color') {
va.input.style.backgroundColor = value;
@ -307,6 +362,9 @@ function configDialog(style) {
}
} else if (va.type === 'checkbox') {
va.input.checked = Number(value);
} else if (va.type === 'range') {
va.input.value = value;
updateRangeCurrentValue(va, va.input.value);
} else {
va.input.value = value;
}