mirror of
https://github.com/FoggedLens/iD.git
synced 2026-02-13 01:02:58 +00:00
263 lines
7.6 KiB
JavaScript
263 lines
7.6 KiB
JavaScript
import * as d3 from 'd3';
|
|
import { t } from '../util/locale';
|
|
import { geoExtent } from '../geo/index';
|
|
import { svgIcon } from '../svg/index';
|
|
import { utilEntityOrMemberSelector } from '../util/index';
|
|
import { utilRebind } from '../util/rebind';
|
|
|
|
|
|
export function uiConflicts(context) {
|
|
var dispatch = d3.dispatch('download', 'cancel', 'save'),
|
|
list;
|
|
|
|
|
|
function conflicts(selection) {
|
|
var header = selection
|
|
.append('div')
|
|
.attr('class', 'header fillL');
|
|
|
|
header
|
|
.append('button')
|
|
.attr('class', 'fr')
|
|
.on('click', function() { dispatch.call('cancel'); })
|
|
.call(svgIcon('#icon-close'));
|
|
|
|
header
|
|
.append('h3')
|
|
.text(t('save.conflict.header'));
|
|
|
|
var body = selection
|
|
.append('div')
|
|
.attr('class', 'body fillL');
|
|
|
|
body
|
|
.append('div')
|
|
.attr('class', 'conflicts-help')
|
|
.text(t('save.conflict.help'))
|
|
.append('a')
|
|
.attr('class', 'conflicts-download')
|
|
.text(t('save.conflict.download_changes'))
|
|
.on('click.download', function() { dispatch.call('download'); });
|
|
|
|
body
|
|
.append('div')
|
|
.attr('class', 'conflict-container fillL3')
|
|
.call(showConflict, 0);
|
|
|
|
body
|
|
.append('div')
|
|
.attr('class', 'conflicts-done')
|
|
.attr('opacity', 0)
|
|
.style('display', 'none')
|
|
.text(t('save.conflict.done'));
|
|
|
|
var buttons = body
|
|
.append('div')
|
|
.attr('class','buttons col12 joined conflicts-buttons');
|
|
|
|
buttons
|
|
.append('button')
|
|
.attr('disabled', list.length > 1)
|
|
.attr('class', 'action conflicts-button col6')
|
|
.text(t('save.title'))
|
|
.on('click.try_again', function() { dispatch.call('save'); });
|
|
|
|
buttons
|
|
.append('button')
|
|
.attr('class', 'secondary-action conflicts-button col6')
|
|
.text(t('confirm.cancel'))
|
|
.on('click.cancel', function() { dispatch.call('cancel'); });
|
|
}
|
|
|
|
|
|
function showConflict(selection, index) {
|
|
if (index < 0 || index >= list.length) return;
|
|
|
|
var parent = d3.select(selection.node().parentNode);
|
|
|
|
// enable save button if this is the last conflict being reviewed..
|
|
if (index === list.length - 1) {
|
|
window.setTimeout(function() {
|
|
parent.select('.conflicts-button')
|
|
.attr('disabled', null);
|
|
|
|
parent.select('.conflicts-done')
|
|
.transition()
|
|
.attr('opacity', 1)
|
|
.style('display', 'block');
|
|
}, 250);
|
|
}
|
|
|
|
var item = selection
|
|
.selectAll('.conflict')
|
|
.data([list[index]]);
|
|
|
|
var enter = item.enter()
|
|
.append('div')
|
|
.attr('class', 'conflict');
|
|
|
|
enter
|
|
.append('h4')
|
|
.attr('class', 'conflict-count')
|
|
.text(t('save.conflict.count', { num: index + 1, total: list.length }));
|
|
|
|
enter
|
|
.append('a')
|
|
.attr('class', 'conflict-description')
|
|
.attr('href', '#')
|
|
.text(function(d) { return d.name; })
|
|
.on('click', function(d) {
|
|
zoomToEntity(d.id);
|
|
d3.event.preventDefault();
|
|
});
|
|
|
|
var details = enter
|
|
.append('div')
|
|
.attr('class', 'conflict-detail-container');
|
|
|
|
details
|
|
.append('ul')
|
|
.attr('class', 'conflict-detail-list')
|
|
.selectAll('li')
|
|
.data(function(d) { return d.details || []; })
|
|
.enter()
|
|
.append('li')
|
|
.attr('class', 'conflict-detail-item')
|
|
.html(function(d) { return d; });
|
|
|
|
details
|
|
.append('div')
|
|
.attr('class', 'conflict-choices')
|
|
.call(addChoices);
|
|
|
|
details
|
|
.append('div')
|
|
.attr('class', 'conflict-nav-buttons joined cf')
|
|
.selectAll('button')
|
|
.data(['previous', 'next'])
|
|
.enter()
|
|
.append('button')
|
|
.text(function(d) { return t('save.conflict.' + d); })
|
|
.attr('class', 'conflict-nav-button action col6')
|
|
.attr('disabled', function(d, i) {
|
|
return (i === 0 && index === 0) ||
|
|
(i === 1 && index === list.length - 1) || null;
|
|
})
|
|
.on('click', function(d, i) {
|
|
var container = parent.select('.conflict-container'),
|
|
sign = (i === 0 ? -1 : 1);
|
|
|
|
container
|
|
.selectAll('.conflict')
|
|
.remove();
|
|
|
|
container
|
|
.call(showConflict, index + sign);
|
|
|
|
d3.event.preventDefault();
|
|
});
|
|
|
|
item.exit()
|
|
.remove();
|
|
}
|
|
|
|
|
|
function addChoices(selection) {
|
|
var choices = selection
|
|
.append('ul')
|
|
.attr('class', 'layer-list')
|
|
.selectAll('li')
|
|
.data(function(d) { return d.choices || []; });
|
|
|
|
var enter = choices.enter()
|
|
.append('li')
|
|
.attr('class', 'layer');
|
|
|
|
var label = enter
|
|
.append('label');
|
|
|
|
label
|
|
.append('input')
|
|
.attr('type', 'radio')
|
|
.attr('name', function(d) { return d.id; })
|
|
.on('change', function(d, i) {
|
|
var ul = this.parentNode.parentNode.parentNode;
|
|
ul.__data__.chosen = i;
|
|
choose(ul, d);
|
|
});
|
|
|
|
label
|
|
.append('span')
|
|
.text(function(d) { return d.text; });
|
|
|
|
choices
|
|
.each(function(d, i) {
|
|
var ul = this.parentNode;
|
|
if (ul.__data__.chosen === i) choose(ul, d);
|
|
});
|
|
}
|
|
|
|
|
|
function choose(ul, datum) {
|
|
if (d3.event) d3.event.preventDefault();
|
|
|
|
d3.select(ul)
|
|
.selectAll('li')
|
|
.classed('active', function(d) { return d === datum; })
|
|
.selectAll('input')
|
|
.property('checked', function(d) { return d === datum; });
|
|
|
|
var extent = geoExtent(),
|
|
entity;
|
|
|
|
entity = context.graph().hasEntity(datum.id);
|
|
if (entity) extent._extend(entity.extent(context.graph()));
|
|
|
|
datum.action();
|
|
|
|
entity = context.graph().hasEntity(datum.id);
|
|
if (entity) extent._extend(entity.extent(context.graph()));
|
|
|
|
zoomToEntity(datum.id, extent);
|
|
}
|
|
|
|
|
|
function zoomToEntity(id, extent) {
|
|
context.surface().selectAll('.hover')
|
|
.classed('hover', false);
|
|
|
|
var entity = context.graph().hasEntity(id);
|
|
if (entity) {
|
|
if (extent) {
|
|
context.map().trimmedExtent(extent);
|
|
} else {
|
|
context.map().zoomTo(entity);
|
|
}
|
|
context.surface().selectAll(
|
|
utilEntityOrMemberSelector([entity.id], context.graph()))
|
|
.classed('hover', true);
|
|
}
|
|
}
|
|
|
|
|
|
// The conflict list should be an array of objects like:
|
|
// {
|
|
// id: id,
|
|
// name: entityName(local),
|
|
// details: merge.conflicts(),
|
|
// chosen: 1,
|
|
// choices: [
|
|
// choice(id, keepMine, forceLocal),
|
|
// choice(id, keepTheirs, forceRemote)
|
|
// ]
|
|
// }
|
|
conflicts.list = function(_) {
|
|
if (!arguments.length) return list;
|
|
list = _;
|
|
return conflicts;
|
|
};
|
|
|
|
|
|
return utilRebind(conflicts, dispatch, 'on');
|
|
}
|