mirror of
https://github.com/FoggedLens/iD.git
synced 2026-04-22 03:36:37 +02:00
fill remoteGraph with loadMultiple, finally do proper undeletion
This commit is contained in:
+1
-1
@@ -334,7 +334,7 @@ en:
|
||||
your changes or the other user's changes.
|
||||
merge_remote_changes:
|
||||
conflict:
|
||||
deleted: 'This object has been deleted.'
|
||||
deleted: 'This object has been deleted by {user}.'
|
||||
location: 'This object was moved by both you and {user}.'
|
||||
nodelist: 'Nodes were changed by both you and {user}.'
|
||||
memberlist: 'Relation members were changed by both you and {user}.'
|
||||
|
||||
Vendored
+1
-1
@@ -407,7 +407,7 @@
|
||||
},
|
||||
"merge_remote_changes": {
|
||||
"conflict": {
|
||||
"deleted": "This object has been deleted.",
|
||||
"deleted": "This object has been deleted by {user}.",
|
||||
"location": "This object was moved by both you and {user}.",
|
||||
"nodelist": "Nodes were changed by both you and {user}.",
|
||||
"memberlist": "Relation members were changed by both you and {user}.",
|
||||
|
||||
@@ -63,11 +63,11 @@ iD.actions.MergeRemoteChanges = function(id, localGraph, remoteGraph, formatUser
|
||||
}
|
||||
|
||||
|
||||
function mergeChildren(target, children, updates, graph) {
|
||||
function isUsed(node, target) {
|
||||
function mergeChildren(targetWay, children, updates, graph) {
|
||||
function isUsed(node, targetWay) {
|
||||
var parentWays = _.pluck(graph.parentWays(node), 'id');
|
||||
return node.hasInterestingTags() ||
|
||||
_.without(parentWays, target.id).length > 0 ||
|
||||
_.without(parentWays, targetWay.id).length > 0 ||
|
||||
graph.parentRelations(node).length > 0;
|
||||
}
|
||||
|
||||
@@ -78,35 +78,41 @@ iD.actions.MergeRemoteChanges = function(id, localGraph, remoteGraph, formatUser
|
||||
node = graph.hasEntity(id);
|
||||
|
||||
// remove unused childNodes..
|
||||
if (target.nodes.indexOf(id) === -1) {
|
||||
if (node && !isUsed(node, target)) {
|
||||
if (targetWay.nodes.indexOf(id) === -1) {
|
||||
if (node && !isUsed(node, targetWay)) {
|
||||
updates.removeIds.push(id);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
// restore used childNodes..
|
||||
var localNode = localGraph.hasEntity(id),
|
||||
remoteNode = remoteGraph.hasEntity(id),
|
||||
targetNode;
|
||||
var local = localGraph.hasEntity(id),
|
||||
remote = remoteGraph.hasEntity(id),
|
||||
target;
|
||||
|
||||
if (remoteNode && option === 'force_remote') {
|
||||
updates.replacements.push(remoteNode);
|
||||
if (!remote) continue;
|
||||
|
||||
} else if (localNode && option === 'force_local') {
|
||||
targetNode = iD.Entity(localNode,
|
||||
{ version: (remoteNode ? remoteNode.version : +localNode.version + 1) });
|
||||
updates.replacements.push(targetNode);
|
||||
if (option === 'force_remote' && remote.visible) {
|
||||
updates.replacements.push(remote);
|
||||
}
|
||||
if (option === 'force_local' && local) {
|
||||
target = iD.Entity(local, { version: remote.version });
|
||||
updates.replacements.push(target);
|
||||
}
|
||||
if (option === 'safe' && local && remote) {
|
||||
target = iD.Entity(local, { version: remote.version });
|
||||
if (remote.visible) {
|
||||
target = mergeLocation(remote, target);
|
||||
} else {
|
||||
conflicts.push(t('merge_remote_changes.conflict.deleted', { user: user(remote.user) }));
|
||||
}
|
||||
|
||||
} else if (localNode && remoteNode && option === 'safe') {
|
||||
targetNode = iD.Entity(localNode, { version: remoteNode.version });
|
||||
targetNode = mergeLocation(remoteNode, targetNode);
|
||||
if (conflicts.length !== ccount) break;
|
||||
updates.replacements.push(targetNode);
|
||||
updates.replacements.push(target);
|
||||
}
|
||||
}
|
||||
|
||||
return target;
|
||||
return targetWay;
|
||||
}
|
||||
|
||||
|
||||
@@ -191,16 +197,15 @@ iD.actions.MergeRemoteChanges = function(id, localGraph, remoteGraph, formatUser
|
||||
var updates = { replacements: [], removeIds: [] },
|
||||
base = graph.base().entities[id],
|
||||
local = localGraph.entity(id),
|
||||
remote = remoteGraph.hasEntity(id),
|
||||
target;
|
||||
remote = remoteGraph.entity(id),
|
||||
target = iD.Entity(local, { version: remote.version });
|
||||
|
||||
// delete/undelete
|
||||
if (!remote) {
|
||||
if (!remote.visible) {
|
||||
if (option === 'force_remote') {
|
||||
return iD.actions.DeleteMultiple([id])(graph);
|
||||
|
||||
} else if (option === 'force_local') {
|
||||
target = iD.Entity(local, { version: +local.version + 1 });
|
||||
if (target.type === 'way') {
|
||||
target = mergeChildren(target, _.uniq(local.nodes), updates, graph);
|
||||
graph = updateChildren(updates, graph);
|
||||
@@ -208,14 +213,12 @@ iD.actions.MergeRemoteChanges = function(id, localGraph, remoteGraph, formatUser
|
||||
return graph.replace(target);
|
||||
|
||||
} else {
|
||||
conflicts.push(t('merge_remote_changes.conflict.deleted'));
|
||||
conflicts.push(t('merge_remote_changes.conflict.deleted', { user: user(remote.user) }));
|
||||
return graph; // do nothing
|
||||
}
|
||||
}
|
||||
|
||||
// merge
|
||||
target = iD.Entity(local, { version: remote.version });
|
||||
|
||||
if (target.type === 'node') {
|
||||
target = mergeLocation(remote, target);
|
||||
|
||||
|
||||
+56
-66
@@ -8,6 +8,14 @@ iD.modes.Save = function(context) {
|
||||
}
|
||||
|
||||
function save(e, tryAgain) {
|
||||
function withChildNodes(ids) {
|
||||
return _.uniq(_.reduce(toCheck, function(result, id) {
|
||||
var e = context.entity(id);
|
||||
if (e.type === 'way') result.push.apply(result, e.nodes);
|
||||
return result;
|
||||
}, _.clone(ids)));
|
||||
}
|
||||
|
||||
var loading = iD.ui.Loading(context).message(t('save.uploading')).blocking(true),
|
||||
history = context.history(),
|
||||
origChanges = history.changes(iD.actions.DiscardTags(history.difference())),
|
||||
@@ -15,6 +23,7 @@ iD.modes.Save = function(context) {
|
||||
remoteGraph = iD.Graph(history.base(), true),
|
||||
modified = _.filter(history.difference().summary(), {changeType: 'modified'}),
|
||||
toCheck = _.pluck(_.pluck(modified, 'entity'), 'id'),
|
||||
toLoad = withChildNodes(toCheck),
|
||||
conflicts = [],
|
||||
errors = [];
|
||||
|
||||
@@ -22,89 +31,70 @@ iD.modes.Save = function(context) {
|
||||
context.container().call(loading);
|
||||
|
||||
if (toCheck.length) {
|
||||
_.each(toCheck, loadAndCheck);
|
||||
context.connection().loadMultiple(toLoad, loaded);
|
||||
} else {
|
||||
finalize();
|
||||
}
|
||||
|
||||
|
||||
// Reload modified entities into an alternate graph and check for conflicts..
|
||||
function loadAndCheck(id) {
|
||||
context.connection().loadEntity(id, function(err, result) {
|
||||
toCheck = _.without(toCheck, id);
|
||||
function loaded(err, result) {
|
||||
if (errors.length) return;
|
||||
|
||||
if (err) {
|
||||
if (err.status === 410) { // Status: Gone (contains no responseText)
|
||||
if (!tryAgain) {
|
||||
remoteGraph.remove(remoteGraph.hasEntity(id));
|
||||
addDeleteConflict(id);
|
||||
}
|
||||
} else {
|
||||
errors.push({
|
||||
id: id,
|
||||
msg: err.responseText,
|
||||
details: [ t('save.status_code', { code: err.status }) ]
|
||||
});
|
||||
}
|
||||
if (err) {
|
||||
errors.push({
|
||||
msg: err.responseText,
|
||||
details: [ t('save.status_code', { code: err.status }) ]
|
||||
});
|
||||
showErrors();
|
||||
|
||||
} else {
|
||||
_.each(result.data, function(entity) { remoteGraph.replace(entity); });
|
||||
checkConflicts(id);
|
||||
} else {
|
||||
_.each(result.data, function(entity) {
|
||||
remoteGraph.replace(entity);
|
||||
toLoad = _.without(toLoad, entity.id);
|
||||
});
|
||||
|
||||
if (!toLoad.length) {
|
||||
checkConflicts();
|
||||
}
|
||||
|
||||
if (!toCheck.length) {
|
||||
finalize();
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
function addDeleteConflict(id) {
|
||||
var local = localGraph.entity(id),
|
||||
action = iD.actions.MergeRemoteChanges,
|
||||
forceLocal = action(id, localGraph, remoteGraph).withOption('force_local'),
|
||||
forceRemote = action(id, localGraph, remoteGraph).withOption('force_remote');
|
||||
function checkConflicts() {
|
||||
_.each(toCheck, function(id) {
|
||||
var local = localGraph.entity(id),
|
||||
remote = remoteGraph.entity(id);
|
||||
|
||||
conflicts.push({
|
||||
id: id,
|
||||
name: entityName(local),
|
||||
details: [ t('merge_remote_changes.conflict.deleted') ],
|
||||
chosen: 1,
|
||||
choices: [
|
||||
choice(id, t('save.conflict.restore'), forceLocal),
|
||||
choice(id, t('save.conflict.delete'), forceRemote)
|
||||
],
|
||||
if (compareVersions(local, remote)) return;
|
||||
|
||||
var action = iD.actions.MergeRemoteChanges,
|
||||
merge = action(id, localGraph, remoteGraph, formatUser),
|
||||
diff = history.replace(merge);
|
||||
|
||||
if (diff.length()) return; // merged safely
|
||||
|
||||
var forceLocal = action(id, localGraph, remoteGraph).withOption('force_local'),
|
||||
forceRemote = action(id, localGraph, remoteGraph).withOption('force_remote'),
|
||||
keepMine = t('save.conflict.' + (remote.visible ? 'keep_local' : 'restore')),
|
||||
keepTheirs = t('save.conflict.' + (remote.visible ? 'keep_remote' : 'delete'));
|
||||
|
||||
conflicts.push({
|
||||
id: id,
|
||||
name: entityName(local),
|
||||
details: merge.conflicts(),
|
||||
chosen: 1,
|
||||
choices: [
|
||||
choice(id, keepMine, forceLocal),
|
||||
choice(id, keepTheirs, forceRemote)
|
||||
]
|
||||
});
|
||||
});
|
||||
|
||||
finalize();
|
||||
}
|
||||
|
||||
|
||||
function checkConflicts(id) {
|
||||
var local = localGraph.entity(id),
|
||||
remote = remoteGraph.entity(id);
|
||||
|
||||
if (compareVersions(local, remote)) return;
|
||||
|
||||
var action = iD.actions.MergeRemoteChanges,
|
||||
merge = action(id, localGraph, remoteGraph, formatUser),
|
||||
diff = history.replace(merge);
|
||||
|
||||
if (diff.length()) return; // merged safely
|
||||
|
||||
var forceLocal = action(id, localGraph, remoteGraph).withOption('force_local'),
|
||||
forceRemote = action(id, localGraph, remoteGraph).withOption('force_remote');
|
||||
|
||||
conflicts.push({
|
||||
id: id,
|
||||
name: entityName(local),
|
||||
details: merge.conflicts(),
|
||||
chosen: 1,
|
||||
choices: [
|
||||
choice(id, t('save.conflict.keep_local'), forceLocal),
|
||||
choice(id, t('save.conflict.keep_remote'), forceRemote)
|
||||
]
|
||||
});
|
||||
}
|
||||
|
||||
function compareVersions(local, remote) {
|
||||
if (local.version !== remote.version) return false;
|
||||
|
||||
|
||||
@@ -68,7 +68,7 @@ describe("iD.actions.MergeRemoteChanges", function () {
|
||||
'merge_remote_changes': {
|
||||
"annotation": "Merged remote changes from server.",
|
||||
"conflict": {
|
||||
"deleted": "This object has been deleted.",
|
||||
"deleted": "This object has been deleted by {user}.",
|
||||
"location": "This object was moved by both you and {user}.",
|
||||
"nodelist": "Nodes were changed by both you and {user}.",
|
||||
"memberlist": "Relation members were changed by both you and {user}.",
|
||||
|
||||
Reference in New Issue
Block a user