diff --git a/CHANGELOG.md b/CHANGELOG.md index 8b07d9b55..ebebe5634 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -43,11 +43,14 @@ _Breaking developer changes, which may affect downstream projects or sites that * Fix bug which made it impossible to change an object's preset from a sub-preset to the respective parents preset (e.g. from Driveway to Service Road) ([#9372]) #### :hourglass: Performance #### :rocket: Presets +* Clamp degree values in `direction` fields between 0 and 359 degrees ([#9386]) +* Disable increment/decrement buttons on number fields if the input value is not numeric or when there is a multi-selection with conflicting values #### :hammer: Development * Upgrade to Transifex API v3 ([#9375]) [#9372]: https://github.com/openstreetmap/iD/issues/9372 [#9375]: https://github.com/openstreetmap/iD/pull/9375 +[#9386]: https://github.com/openstreetmap/iD/issues/9386 # 2.23.2 diff --git a/modules/actions/reverse.js b/modules/actions/reverse.js index 31f498f03..163660ea4 100644 --- a/modules/actions/reverse.js +++ b/modules/actions/reverse.js @@ -99,17 +99,19 @@ export function actionReverse(entityID, options) { return onewayReplacements[value] || value; } else if (includeAbsolute && directionKey.test(key)) { - if (compassReplacements[value]) return compassReplacements[value]; + return value.split(';').map(value => { + if (compassReplacements[value]) return compassReplacements[value]; - var degrees = parseFloat(value); - if (typeof degrees === 'number' && !isNaN(degrees)) { - if (degrees < 180) { - degrees += 180; - } else { - degrees -= 180; + var degrees = Number(value); + if (isFinite(degrees)) { + if (degrees < 180) { + degrees += 180; + } else { + degrees -= 180; + } + return degrees.toString(); } - return degrees.toString(); - } + }).join(';'); } return valueReplacements[value] || value; diff --git a/modules/ui/fields/input.js b/modules/ui/fields/input.js index 76b795d32..db55fa600 100644 --- a/modules/ui/fields/input.js +++ b/modules/ui/fields/input.js @@ -28,6 +28,7 @@ export function uiFieldText(field, context) { var _entityIDs = []; var _tags; var _phoneFormats = {}; + const isDirectionField = field.key.split(':').some(keyPart => keyPart === 'direction'); if (field.type === 'tel') { fileFetcher.get('phone_formats') @@ -112,23 +113,43 @@ export function uiFieldText(field, context) { var which = (d > 0 ? 'increment' : 'decrement'); return 'form-field-button ' + which; }) - .attr('title', function(d){ + .attr('title', function(d) { var which = (d > 0 ? 'increment' : 'decrement'); return t(`inspector.${which}`); }) .merge(buttons) .on('click', function(d3_event, d) { d3_event.preventDefault(); + + // do nothing if this is a multi-selection with mixed values + var isMixed = Array.isArray(_tags[field.key]); + if (isMixed) return; + var raw_vals = input.node().value || '0'; var vals = raw_vals.split(';'); vals = vals.map(function(v) { - var num = parseFloat(v.trim(), 10); - if (isFinite(num)) return clamped(num + d); + var num = Number(v); + if (isDirectionField) { + const compassDir = cardinal[v.trim().toLowerCase()]; + if (compassDir !== undefined) { + num = compassDir; + } + } - const compassDir = cardinal[v.trim().toLowerCase()]; - if (compassDir !== undefined) return clamped(compassDir + d); + if (!isFinite(num)) { + // do nothing if the value is neither a number, nor a cardinal direction + return v.trim(); + } - return v.trim(); // do nothing if the value is neither a number, nor a cardinal direction + num += d; + // clamp to 0..359 degree range if it's a direction field + // https://github.com/openstreetmap/iD/issues/9386 + if (isDirectionField) { + num = ((num % 360) + 360) % 360; + } + // make sure no extra decimals are introduced + const numDecimals = v.includes('.') ? v.split('.')[1].length : 0; + return clamped(num).toFixed(numDecimals); }); input.node().value = vals.join(';'); change()(); @@ -294,7 +315,7 @@ export function uiFieldText(field, context) { if (field.type === 'number' && val) { var vals = val.split(';'); vals = vals.map(function(v) { - var num = parseFloat(v.trim(), 10); + var num = Number(v); return isFinite(num) ? clamped(num) : v.trim(); }); val = vals.join(';'); @@ -324,6 +345,18 @@ export function uiFieldText(field, context) { .attr('placeholder', isMixed ? t('inspector.multiple_values') : (field.placeholder() || t('inspector.unknown'))) .classed('mixed', isMixed); + if (field.type === 'number') { + const buttons = wrap.selectAll('.increment, .decrement'); + if (isMixed) { + buttons.attr('disabled', 'disabled').classed('disabled', true); + } else { + var raw_vals = tags[field.key] || '0'; + const canIncDec = raw_vals.split(';').some(val => isFinite(Number(val)) + || isDirectionField && cardinal[val.trim().toLowerCase()]); + buttons.attr('disabled', canIncDec ? null : 'disabled').classed('disabled', !canIncDec); + } + } + if (field.type === 'tel') updatePhonePlaceholder(); if (field.key.split(':').includes('colour')) updateColourPreview();