Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Enable field editing in multiselection #7306

Merged
merged 9 commits into from
Jan 31, 2020
19 changes: 16 additions & 3 deletions css/80_app.css
Original file line number Diff line number Diff line change
Expand Up @@ -220,6 +220,11 @@ input[type="radio"] {
margin-right: 0;
}

input.mixed::placeholder,
textarea.mixed::placeholder {
font-style: italic;
}

/* tables */
table {
background-color: #fff;
Expand Down Expand Up @@ -1591,6 +1596,11 @@ a.hide-toggle {
z-index: 3000;
cursor: grabbing;
}
.form-field-input-multicombo li.mixed {
border-color: #eff2f7;
color: #888;
font-style: italic;
}

.form-field-input-multicombo li.chip span {
display: block;
Expand Down Expand Up @@ -1708,6 +1718,9 @@ a.hide-toggle {
.form-field-input-check > span {
flex: 1 1 auto;
}
.form-field-input-check > span.mixed {
font-style: italic;
}
.form-field-input-check > .reverser.button {
flex: 0 1 auto;
background-color: #eff2f7;
Expand Down Expand Up @@ -1754,6 +1767,9 @@ a.hide-toggle {
color: #7092ff;
cursor: pointer;
}
.form-field-input-radio > label.mixed {
font-style: italic;
}
.form-field-input-radio > label:last-child {
border-radius: 0 0 4px 4px;
}
Expand Down Expand Up @@ -2371,9 +2387,6 @@ button.raw-tag-option svg.icon {
[dir='rtl'] .tag-row input.value {
border-left: 1px solid #ccc;
}
.tag-row input.value.conflicting::placeholder {
font-style: italic;
}

.tag-row:first-child input.key {
border-top: 1px solid #ccc;
Expand Down
1 change: 1 addition & 0 deletions data/core.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -555,6 +555,7 @@ en:
key_value: "key=value"
multiple_values: Multiple Values
multiple_types: Multiple Types
unshared_value_tooltip: not shared by all features
hidden_preset:
manual: "{features} are hidden. Enable them in the Map Data pane."
zoom: "{features} are hidden. Zoom in to enable them."
Expand Down
1 change: 1 addition & 0 deletions dist/locales/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -694,6 +694,7 @@
"key_value": "key=value",
"multiple_values": "Multiple Values",
"multiple_types": "Multiple Types",
"unshared_value_tooltip": "not shared by all features",
"hidden_preset": {
"manual": "{features} are hidden. Enable them in the Map Data pane.",
"zoom": "{features} are hidden. Zoom in to enable them."
Expand Down
6 changes: 6 additions & 0 deletions modules/presets/field.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,12 @@ export function presetField(id, field) {
return !field.geometry || field.geometry === geometry;
};

field.matchAllGeometry = function(geometries) {
return !field.geometry || geometries.every(function(geometry) {
return field.geometry.indexOf(geometry) !== -1;
});
};


field.t = function(scope, options) {
return t('presets.fields.' + id + '.' + scope, options);
Expand Down
69 changes: 63 additions & 6 deletions modules/ui/entity_editor.js
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ import { uiEntityIssues } from './entity_issues';
import { uiSelectionList } from './selection_list';
import { uiTooltipHtml } from './tooltipHtml';
import { utilArrayIdentical } from '../util/array';
import { utilCleanTags, utilRebind } from '../util';
import { utilCleanTags, utilCombinedTags, utilRebind } from '../util';


export function uiEntityEditor(context) {
Expand All @@ -36,7 +36,7 @@ export function uiEntityEditor(context) {
var selectionList = uiSelectionList(context);
var entityIssues = uiEntityIssues(context);
var quickLinks = uiQuickLinks();
var presetEditor = uiPresetEditor(context).on('change', changeTags);
var presetEditor = uiPresetEditor(context).on('change', changeTags).on('revert', revertTags);
var rawTagEditor = uiRawTagEditor(context).on('change', changeTags);
var rawMemberEditor = uiRawMemberEditor(context);
var rawMembershipEditor = uiRawMembershipEditor(context);
Expand All @@ -46,6 +46,8 @@ export function uiEntityEditor(context) {
var singularEntityID = _entityIDs.length === 1 && _entityIDs[0];
var singularEntity = singularEntityID && context.entity(singularEntityID);

var combinedTags = utilCombinedTags(_entityIDs, context.graph());

// Header
var header = selection.selectAll('.header')
.data([0]);
Expand Down Expand Up @@ -234,13 +236,13 @@ export function uiEntityEditor(context) {
}
}, {
klass: 'preset-editor',
shouldHave: singularEntityID,
shouldHave: true,
update: function(section) {
section
.call(presetEditor
.preset(_activePresets[0])
.entityID(singularEntityID)
.tags(Object.assign({}, singularEntity.tags))
.presets(_activePresets)
.entityIDs(_entityIDs)
.tags(combinedTags)
.state(_state)
);
}
Expand All @@ -252,6 +254,7 @@ export function uiEntityEditor(context) {
.call(rawTagEditor
.preset(_activePresets[0])
.entityIDs(_entityIDs)
.tags(combinedTags)
.state(_state)
);
}
Expand Down Expand Up @@ -410,6 +413,60 @@ export function uiEntityEditor(context) {
}
}

function revertTags(keys) {

var actions = [];
for (var i in _entityIDs) {
var entityID = _entityIDs[i];

var original = context.graph().base().entities[entityID];
var changed = {};
for (var j in keys) {
var key = keys[j];
changed[key] = original ? original.tags[key] : undefined;
}

var entity = context.entity(entityID);
var tags = Object.assign({}, entity.tags); // shallow copy

for (var k in changed) {
if (!k) continue;
var v = changed[k];
if (v !== undefined || tags.hasOwnProperty(k)) {
tags[k] = v;
}
}


tags = utilCleanTags(tags);

if (!deepEqual(entity.tags, tags)) {
actions.push(actionChangeTags(entityID, tags));
}

}

if (actions.length) {
var combinedAction = function(graph) {
actions.forEach(function(action) {
graph = action(graph);
});
return graph;
};

var annotation = t('operations.change_tags.annotation');

if (_coalesceChanges) {
context.overwrite(combinedAction, annotation);
} else {
context.perform(combinedAction, annotation);
_coalesceChanges = false;
}
}

context.validator().validate();
}


entityEditor.modified = function(val) {
if (!arguments.length) return _modified;
Expand Down
82 changes: 47 additions & 35 deletions modules/ui/field.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,14 @@ import { t } from '../util/locale';
import { textDirection } from '../util/locale';
import { svgIcon } from '../svg/icon';
import { tooltip } from '../util/tooltip';
import { geoExtent } from '../geo/extent';
import { uiFieldHelp } from './field_help';
import { uiFields } from './fields';
import { uiTagReference } from './tag_reference';
import { utilRebind } from '../util';


export function uiField(context, presetField, entity, options) {
export function uiField(context, presetField, entityIDs, options) {
options = Object.assign({
show: true,
wrap: true,
Expand All @@ -21,7 +22,7 @@ export function uiField(context, presetField, entity, options) {
info: true
}, options);

var dispatch = d3_dispatch('change');
var dispatch = d3_dispatch('change', 'revert');
var field = Object.assign({}, presetField); // shallow copy
var _show = options.show;
var _state = '';
Expand All @@ -48,21 +49,24 @@ export function uiField(context, presetField, entity, options) {
dispatch.call('change', field, t, onInput);
});

if (entity) {
field.entityID = entity.id;
// if this field cares about the entity, pass it along
if (field.impl.entity) {
field.impl.entity(entity);
if (entityIDs) {
field.entityIDs = entityIDs;
// if this field cares about the entities, pass them along
if (field.impl.entityIDs) {
field.impl.entityIDs(entityIDs);
}
}
}


function isModified() {
if (!entity) return false;
var original = context.graph().base().entities[entity.id];
return field.keys.some(function(key) {
return original ? _tags[key] !== original.tags[key] : _tags[key];
if (!entityIDs || !entityIDs.length) return false;
return entityIDs.some(function(entityID) {
var original = context.graph().base().entities[entityID];
var latest = context.graph().entity(entityID);
return field.keys.some(function(key) {
return original ? latest.tags[key] !== original.tags[key] : latest.tags[key];
});
});
}

Expand All @@ -85,15 +89,9 @@ export function uiField(context, presetField, entity, options) {
function revert(d) {
d3_event.stopPropagation();
d3_event.preventDefault();
if (!entity || _locked) return;
if (!entityIDs || _locked) return;

var original = context.graph().base().entities[entity.id];
var t = {};
d.keys.forEach(function(key) {
t[key] = original ? original.tags[key] : undefined;
});

dispatch.call('change', d, t);
dispatch.call('revert', d, d.keys);
}


Expand Down Expand Up @@ -297,11 +295,13 @@ export function uiField(context, presetField, entity, options) {
// A non-allowed field is hidden from the user altogether
field.isAllowed = function() {

var latest = entity && context.hasEntity(entity.id); // check the most current copy of the entity
if (!latest) return true;
if (entityIDs && entityIDs.length > 1 && uiFields[field.type].supportsMultiselection === false) return;

if (field.countryCodes || field.notCountryCodes) {
var center = latest.extent(context.graph()).center();
var extent = combinedEntityExtent();
if (!extent) return true;

var center = extent.center();
var countryCode = countryCoder.iso1A2Code(center);

if (!countryCode) return false;
Expand All @@ -318,21 +318,25 @@ export function uiField(context, presetField, entity, options) {

var prerequisiteTag = field.prerequisiteTag;

if (!tagsContainFieldKey() && // ignore tagging prerequisites if a value is already present
if (entityIDs &&
!tagsContainFieldKey() && // ignore tagging prerequisites if a value is already present
prerequisiteTag) {
if (prerequisiteTag.key) {
var value = latest.tags[prerequisiteTag.key];
if (!value) return false;

if (prerequisiteTag.valueNot) {
return prerequisiteTag.valueNot !== value;
}
if (prerequisiteTag.value) {
return prerequisiteTag.value === value;
return entityIDs.some(function(entityID) {
var entity = context.graph().entity(entityID);
if (prerequisiteTag.key) {
var value = entity.tags[prerequisiteTag.key];
if (!value) return false;

if (prerequisiteTag.valueNot) {
return prerequisiteTag.valueNot !== value;
}
if (prerequisiteTag.value) {
return prerequisiteTag.value === value;
}
} else if (prerequisiteTag.keyNot) {
if (entity.tags[prerequisiteTag.keyNot]) return false;
}
} else if (prerequisiteTag.keyNot) {
if (latest.tags[prerequisiteTag.keyNot]) return false;
}
});
}

return true;
Expand All @@ -346,5 +350,13 @@ export function uiField(context, presetField, entity, options) {
};


function combinedEntityExtent() {
return entityIDs && entityIDs.length && entityIDs.reduce(function(extent, entityID) {
var entity = context.graph().entity(entityID);
return extent.extend(entity.extent(context.graph()));
}, geoExtent());
}


return utilRebind(field, dispatch, 'on');
}
Loading