Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@
# v2.37.2
##### 2025-10-30

* Correctly resolve subtitles of NSI presets when base preset has a crossreferenced string ([#11527])

Check failure on line 70 in CHANGELOG.md

View workflow job for this annotation

GitHub Actions / Check for spelling errors

crossreferenced ==> cross-referenced

Check failure on line 70 in CHANGELOG.md

View workflow job for this annotation

GitHub Actions / Check for spelling errors

crossreferenced ==> cross-referenced

[#11527]: https://github.com/openstreetmap/iD/issues/11527

Expand Down Expand Up @@ -307,6 +307,7 @@
#### :mortar_board: Walkthrough / Help
* Change background imagery of walkthrough tutorial to Bing (the previous source is not available anymore)
#### :rocket: Presets
* When changing presets, delete tags from the old preset which are not in the new preset ([#11696], thanks [@k-yle])
* Suggest housenumber/housename values from surrounding areas ([#10946])
#### :hammer: Development
* Drop support for Node 18
Expand All @@ -324,6 +325,7 @@
[#10997]: https://github.com/openstreetmap/iD/issues/10997
[#11006]: https://github.com/openstreetmap/iD/issues/11006
[#11011]: https://github.com/openstreetmap/iD/issues/11011
[#11696]: https://github.com/openstreetmap/iD/pull/11696
[@ChaitanyaKadu03]: https://github.com/ChaitanyaKadu03


Expand Down
17 changes: 16 additions & 1 deletion modules/actions/change_preset.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import { utilArrayDifference, utilObjectOmit } from '../util';

export function actionChangePreset(entityID, oldPreset, newPreset, skipFieldDefaults) {
return function action(graph) {
var entity = graph.entity(entityID);
Expand All @@ -18,9 +20,22 @@ export function actionChangePreset(entityID, oldPreset, newPreset, skipFieldDefa
// https://github.com/openstreetmap/iD/issues/9372
newPreset.fields(loc).concat(newPreset.moreFields(loc))
.filter(f => f.matchGeometry(geometry))
.map(f => f.key).filter(Boolean)
.flatMap(f => f.allKeys())
.filter(Boolean)
.forEach(key => preserveKeys.push(key));
}

if (oldPreset) {
// 'field-keys' are keys used by fields (different to the keys used by preset itself)
const oldPresetFieldKeys = [
...oldPreset.fields(loc),
...oldPreset.moreFields(loc)
].flatMap(f => f.allKeys());

// field-keys used by the old preset but not the new preset
const fieldKeysToRemove = utilArrayDifference(oldPresetFieldKeys, preserveKeys);
tags = utilObjectOmit(tags, fieldKeysToRemove);
}
}
if (oldPreset) tags = oldPreset.unsetTags(tags, geometry, preserveKeys, false, loc);
if (newPreset) tags = newPreset.setTags(tags, geometry, skipFieldDefaults, loc);
Expand Down
8 changes: 8 additions & 0 deletions modules/presets/field.js
Original file line number Diff line number Diff line change
Expand Up @@ -53,5 +53,13 @@ export function presetField(fieldID, field, allFields) {

_this.increment = (_this.type === 'number' || _this.type === 'integer') ? (_this.increment || 1) : undefined;

/** all keys controlled by this field */
_this.allKeys = () => {
const allKeys = [];
if (_this.key) allKeys.push(_this.key);
if (_this.keys) allKeys.push(..._this.keys);
return allKeys;
};

return _this;
}
41 changes: 41 additions & 0 deletions test/spec/actions/change_preset.js
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,47 @@ describe('iD.actionChangePreset', function() {
expect(action(graph).entity(entity.id).tags).to.eql({amenity: 'school'});
});

it('does not preserve field tags which only exist in the old preset, not in the new preset', () => {
const entity = iD.osmNode({
tags: {
building: 'yes', // case 1: the preset's own tags.
'roof:colour': 'pink', // case 2: a field which exists in the old preset, but not the new one.
check_date: '2025-12-05', // case 3: a field which exists in the old AND new preset.
grades: '0-13', // case 4: a field which exists only in the new preset, not in the old one.
'ref:SG:address_id': '1234', // case 5: a tag which does not exist in either preset
},
loc: [0, 0],
});
const graph = iD.coreGraph([entity]);

const fields = {
'roof:colour': iD.presetField('roof:colour', { key: 'roof:colour', geometry: 'point' }),
check_date: iD.presetField('check_date', { key: 'check_date', geometry: 'point' }),
grades: iD.presetField('roof:colour', { key: 'grades', geometry: 'point' }),
};

const oldPreset = iD.presetPreset(
'building/yes',
{ tags: { building: 'yes' }, fields: ['roof:colour', 'check_date'] },
undefined,
fields,
);
const newPreset = iD.presetPreset(
'amenity/school',
{ tags: { amenity: 'school' }, fields: ['check_date', 'grades'] },
undefined,
fields,
);
const action = iD.actionChangePreset(entity.id, oldPreset, newPreset);
expect(action(graph).entity(entity.id).tags).toStrictEqual({
amenity: 'school', // case 1: the preset's own tags were replaced.
// case 2: the field which exists in the old preset was removed (roof:colour).
check_date: '2025-12-05', // case 3: the field which exists in the old AND new preset was kept.
grades: '0-13', // case 4: a field which exists only in the new preset was also kept.
'ref:SG:address_id': '1234', // case 5: tags which do not exist in either preset are kept
});
});

// https://github.com/openstreetmap/iD/issues/9372
it('does not preserve field tags when changing from a subpreset to its parent', function() {
var entity = iD.osmNode({tags: {highway: 'service', service: 'driveway'}});
Expand Down