From ebe5484e22b83cbb7d5c39541065d8cf15da6ec4 Mon Sep 17 00:00:00 2001 From: Bryan Housel Date: Tue, 17 Feb 2015 00:51:49 -0500 Subject: [PATCH] WIP: MergeRemoteChanges merges way childnodes --- js/id/actions/merge_remote_changes.js | 86 +++++++++++++++++++-------- js/id/modes/save.js | 6 +- 2 files changed, 63 insertions(+), 29 deletions(-) diff --git a/js/id/actions/merge_remote_changes.js b/js/id/actions/merge_remote_changes.js index 0592ed04e..55a897fc2 100644 --- a/js/id/actions/merge_remote_changes.js +++ b/js/id/actions/merge_remote_changes.js @@ -1,23 +1,58 @@ -iD.actions.MergeRemoteChanges = function(id, localGraph, remoteGraph, formatUser) { - var base = localGraph.base().entities[id], - local = localGraph.entity(id), - remote = remoteGraph.entity(id), - option = 'safe', // 'safe', 'force_local', 'force_remote' +iD.actions.MergeRemoteChanges = function(id, remoteGraph, formatUser) { + var option = 'safe', // 'safe', 'force_local', 'force_remote' conflicts = []; function user(d) { return _.isFunction(formatUser) ? formatUser(d) : d; } - function mergeLocation(target) { - if (!target) return; + function mergeChildren(remote, target, graph) { + var children = graph.childNodes(target), + updateNodes = [], + removeNodes = [], + i; + for (i = 0; i < children.length; i++) { + var lnode = children[i], + rnode = remoteGraph.hasEntity(lnode.id); + + if (option === 'force_remote') { + if (rnode) { + updateNodes.push(rnode); + } else { + removeNodes.push(lnode); + } + } else { + var tversion = (rnode && rnode.version) || (+lnode.version + 1), + tnode = iD.Entity(lnode, { version: tversion }); + + tnode = mergeLocation(rnode, tnode); + if (tnode) { + updateNodes.push(tnode); + } else { + return graph; // child location conflict + } + } + } + + for (i = 0; i < updateNodes.length; i++) { + graph = graph.replace(updateNodes[i]); + } + for (i = 0; i < removeNodes.length; i++) { + graph = iD.actions.DeleteNode(removeNodes[i].id)(graph); + } + + return graph; + } + + + function mergeLocation(remote, target) { function pointEqual(a, b) { var epsilon = 1e-6; return (Math.abs(a[0] - b[0]) < epsilon) && (Math.abs(a[1] - b[1]) < epsilon); } - if (pointEqual(target.loc, remote.loc)) { + if (option === 'force_local' || pointEqual(target.loc, remote.loc)) { return target; } if (option === 'force_remote') { @@ -28,10 +63,9 @@ iD.actions.MergeRemoteChanges = function(id, localGraph, remoteGraph, formatUser return; // fail merge } - function mergeNodes(target) { - if (!target) return; - if (_.isEqual(target.nodes, remote.nodes)) { + function mergeNodes(base, remote, target) { + if (option === 'force_local' || _.isEqual(target.nodes, remote.nodes)) { return target; } if (option === 'force_remote') { @@ -39,7 +73,7 @@ iD.actions.MergeRemoteChanges = function(id, localGraph, remoteGraph, formatUser } var o = base.nodes || [], - a = local.nodes || [], + a = target.nodes || [], b = remote.nodes || [], nodes = [], hunks = Diff3.diff3_merge(a, o, b, true); @@ -66,10 +100,9 @@ iD.actions.MergeRemoteChanges = function(id, localGraph, remoteGraph, formatUser return target.update({nodes: nodes}); } - function mergeMembers(target) { - if (!target) return; - if (_.isEqual(target.members, remote.members)) { + function mergeMembers(remote, target) { + if (option === 'force_local' || _.isEqual(target.members, remote.members)) { return target; } if (option === 'force_remote') { @@ -80,10 +113,11 @@ iD.actions.MergeRemoteChanges = function(id, localGraph, remoteGraph, formatUser return; // fail merge } - function mergeTags(target) { + + function mergeTags(base, remote, target) { if (!target) return; - if (_.isEqual(target.tags, remote.tags)) { + if (option === 'force_local' || _.isEqual(target.tags, remote.tags)) { return target; } if (option === 'force_remote') { @@ -117,22 +151,22 @@ iD.actions.MergeRemoteChanges = function(id, localGraph, remoteGraph, formatUser } var action = function(graph) { - var target = iD.Entity(local, {version: remote.version}); - - if (option === 'force_local') { - return graph.replace(target); - } + var base = graph.base().entities[id], + local = graph.entity(id), + remote = remoteGraph.entity(id), + target = iD.Entity(local, { version: remote.version }); if (target.type === 'node') { - target = mergeLocation(target); + target = mergeLocation(remote, target); } else if (target.type === 'way') { graph.rebase(remoteGraph.childNodes(remote), [graph], false); - target = mergeNodes(target); + graph = mergeChildren(remote, target, graph); + target = mergeNodes(base, remote, target); } else if (target.type === 'relation') { - target = mergeMembers(target); + target = mergeMembers(remote, target); } - target = mergeTags(target); + target = mergeTags(base, remote, target); return target ? graph.replace(target) : graph; }; diff --git a/js/id/modes/save.js b/js/id/modes/save.js index b6e2843f2..6873c779b 100644 --- a/js/id/modes/save.js +++ b/js/id/modes/save.js @@ -89,13 +89,13 @@ iD.modes.Save = function(context) { if (local.version !== remote.version) { var action = iD.actions.MergeRemoteChanges, - merge = action(id, graph, altGraph, formatUser), + merge = action(id, altGraph, formatUser), diff = history.replace(merge); if (diff.length()) return; // merged safely - var forceLocal = action(id, graph, altGraph, formatUser).withOption('force_local'), - forceRemote = action(id, graph, altGraph, formatUser).withOption('force_remote'); + var forceLocal = action(id, altGraph, formatUser).withOption('force_local'), + forceRemote = action(id, altGraph, formatUser).withOption('force_remote'); conflicts.push({ id: id,