node-red/editor/js/ui/diff.js

1659 lines
76 KiB
JavaScript
Raw Normal View History

2016-12-07 14:51:20 +01:00
RED.diff = (function() {
2016-12-20 20:42:38 +01:00
var currentDiff = {};
var diffVisible = false;
var diffList;
2016-12-20 20:42:38 +01:00
2016-12-07 14:51:20 +01:00
function init() {
// RED.actions.add("core:show-current-diff",showLocalDiff);
2016-12-15 21:41:53 +01:00
RED.actions.add("core:show-remote-diff",showRemoteDiff);
// RED.keyboard.add("*","ctrl-shift-l","core:show-current-diff");
2016-12-15 21:41:53 +01:00
RED.keyboard.add("*","ctrl-shift-r","core:show-remote-diff");
2016-12-07 14:51:20 +01:00
2017-08-20 23:59:51 +02:00
RED.actions.add("core:show-test-flow-diff-1",function(){showTestFlowDiff(1)});
RED.keyboard.add("*","ctrl-shift-f 1","core:show-test-flow-diff-1");
RED.actions.add("core:show-test-flow-diff-2",function(){showTestFlowDiff(2)});
RED.keyboard.add("*","ctrl-shift-f 2","core:show-test-flow-diff-2");
RED.actions.add("core:show-test-flow-diff-3",function(){showTestFlowDiff(3)});
RED.keyboard.add("*","ctrl-shift-f 3","core:show-test-flow-diff-3");
}
function buildDiffPanel(container) {
var diffPanel = $('<div id="node-dialog-view-diff"><div id="node-dialog-view-diff-headers"></div><ol id="node-dialog-view-diff-diff"></ol></div>').appendTo(container);
2016-12-07 14:51:20 +01:00
var toolbar = $('<div class="node-diff-toolbar">'+
2016-12-20 20:42:38 +01:00
'<span><span id="node-diff-toolbar-resolved-conflicts"></span></span> '+
'</div>').prependTo(diffPanel);
2016-12-07 14:51:20 +01:00
diffList = diffPanel.find("#node-dialog-view-diff-diff").editableList({
2016-12-07 14:51:20 +01:00
addButton: false,
scrollOnAdd: false,
addItem: function(container,i,object) {
var localDiff = object.diff;
2016-12-15 21:41:53 +01:00
var remoteDiff = object.remoteDiff;
2016-12-07 14:51:20 +01:00
var tab = object.tab.n;
var def = object.def;
var conflicts = currentDiff.conflicts;
2016-12-07 14:51:20 +01:00
var tabDiv = $('<div>',{class:"node-diff-tab"}).appendTo(container);
2016-12-20 20:42:38 +01:00
tabDiv.addClass('collapsed');
2016-12-07 14:51:20 +01:00
var titleRow = $('<div>',{class:"node-diff-tab-title"}).appendTo(tabDiv);
2016-12-15 21:41:53 +01:00
var nodesDiv = $('<div>').appendTo(tabDiv);
var originalCell = $('<div>',{class:"node-diff-node-entry-cell"}).appendTo(titleRow);
2016-12-20 20:42:38 +01:00
var localCell = $('<div>',{class:"node-diff-node-entry-cell node-diff-node-local"}).appendTo(titleRow);
2016-12-15 21:41:53 +01:00
var remoteCell;
2016-12-20 20:42:38 +01:00
var selectState;
2016-12-15 21:41:53 +01:00
if (remoteDiff) {
2016-12-20 20:42:38 +01:00
remoteCell = $('<div>',{class:"node-diff-node-entry-cell node-diff-node-remote"}).appendTo(titleRow);
2016-12-07 14:51:20 +01:00
}
2016-12-15 21:41:53 +01:00
$('<span class="node-diff-chevron"><i class="fa fa-angle-down"></i></span>').appendTo(originalCell);
createNodeIcon(tab,def).appendTo(originalCell);
2016-12-07 14:51:20 +01:00
var tabForLabel = (object.newTab || object.tab).n;
2016-12-15 21:41:53 +01:00
var titleSpan = $('<span>',{class:"node-diff-tab-title-meta"}).appendTo(originalCell);
2016-12-07 14:51:20 +01:00
if (tabForLabel.type === 'tab') {
2016-12-15 21:41:53 +01:00
titleSpan.html(tabForLabel.label||tabForLabel.id);
2016-12-07 14:51:20 +01:00
} else if (tab.type === 'subflow') {
2016-12-15 21:41:53 +01:00
titleSpan.html((tabForLabel.name||tabForLabel.id));
2016-12-07 14:51:20 +01:00
} else {
titleSpan.html(RED._("diff.globalNodes"));
2016-12-07 14:51:20 +01:00
}
2016-12-15 21:41:53 +01:00
var flowStats = {
local: {
addedCount:0,
deletedCount:0,
changedCount:0,
unchangedCount: 0
},
remote: {
addedCount:0,
deletedCount:0,
changedCount:0,
unchangedCount: 0
},
conflicts: 0
}
if (object.newTab || object.remoteTab) {
var localTabNode = {
node: localDiff.newConfig.all[tab.id],
all: localDiff.newConfig.all,
diff: localDiff
}
var remoteTabNode;
if (remoteDiff) {
remoteTabNode = {
node:remoteDiff.newConfig.all[tab.id]||null,
all: remoteDiff.newConfig.all,
diff: remoteDiff
}
}
if (tab.type !== undefined) {
var div = $("<div>",{class:"node-diff-node-entry node-diff-node-props collapsed"}).appendTo(nodesDiv);
var row = $("<div>",{class:"node-diff-node-entry-header"}).appendTo(div);
var originalNodeDiv = $("<div>",{class:"node-diff-node-entry-cell"}).appendTo(row);
2016-12-20 20:42:38 +01:00
var localNodeDiv = $("<div>",{class:"node-diff-node-entry-cell node-diff-node-local"}).appendTo(row);
2016-12-15 21:41:53 +01:00
var localChanged = false;
var remoteChanged = false;
2016-12-07 14:51:20 +01:00
2016-12-15 21:41:53 +01:00
if (!localDiff.newConfig.all[tab.id]) {
localNodeDiv.addClass("node-diff-empty");
} else if (localDiff.added[tab.id]) {
localNodeDiv.addClass("node-diff-node-added");
2016-12-20 20:42:38 +01:00
localChanged = true;
2017-01-04 23:02:35 +01:00
$('<span class="node-diff-status"><i class="fa fa-plus-square"></i> <span data-i18n="diff.type.added"></span></span>').appendTo(localNodeDiv);
2016-12-15 21:41:53 +01:00
} else if (localDiff.changed[tab.id]) {
localNodeDiv.addClass("node-diff-node-changed");
2016-12-20 20:42:38 +01:00
localChanged = true;
2017-01-04 23:02:35 +01:00
$('<span class="node-diff-status"><i class="fa fa-square"></i> <span data-i18n="diff.type.changed"></span></span>').appendTo(localNodeDiv);
2016-12-15 21:41:53 +01:00
} else {
localNodeDiv.addClass("node-diff-node-unchanged");
2017-01-04 23:02:35 +01:00
$('<span class="node-diff-status"><i class="fa fa-square-o"></i> <span data-i18n="diff.type.unchanged"></span></span>').appendTo(localNodeDiv);
2016-12-15 21:41:53 +01:00
}
var remoteNodeDiv;
if (remoteDiff) {
2016-12-20 20:42:38 +01:00
remoteNodeDiv = $("<div>",{class:"node-diff-node-entry-cell node-diff-node-remote"}).appendTo(row);
2016-12-15 21:41:53 +01:00
if (!remoteDiff.newConfig.all[tab.id]) {
remoteNodeDiv.addClass("node-diff-empty");
if (remoteDiff.deleted[tab.id]) {
remoteChanged = true;
}
2016-12-15 21:41:53 +01:00
} else if (remoteDiff.added[tab.id]) {
remoteNodeDiv.addClass("node-diff-node-added");
remoteChanged = true;
2017-01-04 23:02:35 +01:00
$('<span class="node-diff-status"><i class="fa fa-plus-square"></i> <span data-i18n="diff.type.added"></span></span>').appendTo(remoteNodeDiv);
2016-12-15 21:41:53 +01:00
} else if (remoteDiff.changed[tab.id]) {
remoteNodeDiv.addClass("node-diff-node-changed");
remoteChanged = true;
2017-01-04 23:02:35 +01:00
$('<span class="node-diff-status"><i class="fa fa-square"></i> <span data-i18n="diff.type.changed"></span></span>').appendTo(remoteNodeDiv);
2016-12-15 21:41:53 +01:00
} else {
remoteNodeDiv.addClass("node-diff-node-unchanged");
2017-01-04 23:02:35 +01:00
$('<span class="node-diff-status"><i class="fa fa-square-o"></i> <span data-i18n="diff.type.unchanged"></span></span>').appendTo(remoteNodeDiv);
2016-12-15 21:41:53 +01:00
}
}
$('<span class="node-diff-chevron"><i class="fa fa-angle-down"></i></span>').appendTo(originalNodeDiv);
$('<span>').html(RED._("diff.flowProperties")).appendTo(originalNodeDiv);
2016-12-20 20:42:38 +01:00
2016-12-15 21:41:53 +01:00
row.click(function(evt) {
evt.preventDefault();
$(this).parent().toggleClass('collapsed');
});
2016-12-07 14:51:20 +01:00
createNodePropertiesTable(def,tab,localTabNode,remoteTabNode,conflicts).appendTo(div);
2016-12-20 20:42:38 +01:00
selectState = "";
if (conflicts[tab.id]) {
2016-12-20 20:42:38 +01:00
flowStats.conflicts++;
2016-12-15 21:41:53 +01:00
2016-12-20 20:42:38 +01:00
if (!localNodeDiv.hasClass("node-diff-empty")) {
$('<span class="node-diff-node-conflict"><span class="node-diff-status"><i class="fa fa-exclamation"></i></span></span>').prependTo(localNodeDiv);
}
if (!remoteNodeDiv.hasClass("node-diff-empty")) {
$('<span class="node-diff-node-conflict"><span class="node-diff-status"><i class="fa fa-exclamation"></i></span></span>').prependTo(remoteNodeDiv);
}
div.addClass("node-diff-node-entry-conflict");
} else {
selectState = currentDiff.resolutions[tab.id];
2016-12-20 20:42:38 +01:00
}
// Tab properties row
createNodeConflictRadioBoxes(tab,div,localNodeDiv,remoteNodeDiv,true,!conflicts[tab.id],selectState);
2016-12-20 20:42:38 +01:00
}
}
// var stats = $('<span>',{class:"node-diff-tab-stats"}).appendTo(titleRow);
var localNodeCount = 0;
var remoteNodeCount = 0;
2016-12-07 14:51:20 +01:00
var seen = {};
object.tab.nodes.forEach(function(node) {
seen[node.id] = true;
createNodeDiffRow(node,flowStats).appendTo(nodesDiv)
2016-12-07 14:51:20 +01:00
});
if (object.newTab) {
2016-12-20 20:42:38 +01:00
localNodeCount = object.newTab.nodes.length;
2016-12-07 14:51:20 +01:00
object.newTab.nodes.forEach(function(node) {
if (!seen[node.id]) {
2016-12-15 21:41:53 +01:00
seen[node.id] = true;
createNodeDiffRow(node,flowStats).appendTo(nodesDiv)
2016-12-15 21:41:53 +01:00
}
});
}
if (object.remoteTab) {
2016-12-20 20:42:38 +01:00
remoteNodeCount = object.remoteTab.nodes.length;
2016-12-15 21:41:53 +01:00
object.remoteTab.nodes.forEach(function(node) {
if (!seen[node.id]) {
createNodeDiffRow(node,flowStats).appendTo(nodesDiv)
2016-12-07 14:51:20 +01:00
}
});
}
titleRow.click(function(evt) {
2016-12-15 21:41:53 +01:00
// if (titleRow.parent().find(".node-diff-node-entry:not(.hide)").length > 0) {
titleRow.parent().toggleClass('collapsed');
if ($(this).parent().hasClass('collapsed')) {
$(this).parent().find('.node-diff-node-entry').addClass('collapsed');
$(this).parent().find('.debug-message-element').addClass('collapsed');
2016-12-07 14:51:20 +01:00
}
2016-12-15 21:41:53 +01:00
// }
2016-12-07 14:51:20 +01:00
})
2016-12-15 21:41:53 +01:00
if (localDiff.deleted[tab.id]) {
2017-01-04 23:02:35 +01:00
$('<span class="node-diff-node-deleted"><span class="node-diff-status"><i class="fa fa-minus-square"></i> <span data-i18n="diff.type.flowDeleted"></span></span></span>').appendTo(localCell);
2016-12-15 21:41:53 +01:00
} else if (object.newTab) {
if (localDiff.added[tab.id]) {
2017-01-04 23:02:35 +01:00
$('<span class="node-diff-node-added"><span class="node-diff-status"><i class="fa fa-plus-square"></i> <span data-i18n="diff.type.flowAdded"></span></span></span>').appendTo(localCell);
2016-12-15 21:41:53 +01:00
} else {
if (tab.id) {
if (localDiff.changed[tab.id]) {
flowStats.local.changedCount++;
} else {
flowStats.local.unchangedCount++;
}
}
var localStats = $('<span>',{class:"node-diff-tab-stats"}).appendTo(localCell);
2017-01-04 23:02:35 +01:00
$('<span class="node-diff-status"></span>').html(RED._('diff.nodeCount',{count:localNodeCount})).appendTo(localStats);
2016-12-20 20:42:38 +01:00
if (flowStats.conflicts + flowStats.local.addedCount + flowStats.local.changedCount + flowStats.local.deletedCount > 0) {
$('<span class="node-diff-status"> [ </span>').appendTo(localStats);
if (flowStats.conflicts > 0) {
$('<span class="node-diff-node-conflict"><span class="node-diff-status"><i class="fa fa-exclamation"></i> '+flowStats.conflicts+'</span></span>').appendTo(localStats);
}
if (flowStats.local.addedCount > 0) {
$('<span class="node-diff-node-added"><span class="node-diff-status"><i class="fa fa-plus-square"></i> '+flowStats.local.addedCount+'</span></span>').appendTo(localStats);
}
if (flowStats.local.changedCount > 0) {
$('<span class="node-diff-node-changed"><span class="node-diff-status"><i class="fa fa-square"></i> '+flowStats.local.changedCount+'</span></span>').appendTo(localStats);
}
if (flowStats.local.deletedCount > 0) {
$('<span class="node-diff-node-deleted"><span class="node-diff-status"><i class="fa fa-minus-square"></i> '+flowStats.local.deletedCount+'</span></span>').appendTo(localStats);
}
$('<span class="node-diff-status"> ] </span>').appendTo(localStats);
2016-12-15 21:41:53 +01:00
}
2016-12-20 20:42:38 +01:00
2016-12-07 14:51:20 +01:00
}
2016-12-15 21:41:53 +01:00
} else {
localCell.addClass("node-diff-empty");
2016-12-07 14:51:20 +01:00
}
2016-12-15 21:41:53 +01:00
if (remoteDiff) {
if (remoteDiff.deleted[tab.id]) {
2017-01-04 23:02:35 +01:00
$('<span class="node-diff-node-deleted"><span class="node-diff-status"><i class="fa fa-minus-square"></i> <span data-i18n="diff.type.flowDeleted"></span></span></span>').appendTo(remoteCell);
2016-12-15 21:41:53 +01:00
} else if (object.remoteTab) {
if (remoteDiff.added[tab.id]) {
2017-01-04 23:02:35 +01:00
$('<span class="node-diff-node-added"><span class="node-diff-status"><i class="fa fa-plus-square"></i> <span data-i18n="diff.type.flowAdded"></span></span></span>').appendTo(remoteCell);
2016-12-15 21:41:53 +01:00
} else {
if (tab.id) {
if (remoteDiff.changed[tab.id]) {
flowStats.remote.changedCount++;
} else {
flowStats.remote.unchangedCount++;
}
}
var remoteStats = $('<span>',{class:"node-diff-tab-stats"}).appendTo(remoteCell);
2017-01-04 23:02:35 +01:00
$('<span class="node-diff-status"></span>').html(RED._('diff.nodeCount',{count:remoteNodeCount})).appendTo(remoteStats);
2016-12-20 20:42:38 +01:00
if (flowStats.conflicts + flowStats.remote.addedCount + flowStats.remote.changedCount + flowStats.remote.deletedCount > 0) {
$('<span class="node-diff-status"> [ </span>').appendTo(remoteStats);
if (flowStats.conflicts > 0) {
$('<span class="node-diff-node-conflict"><span class="node-diff-status"><i class="fa fa-exclamation"></i> '+flowStats.conflicts+'</span></span>').appendTo(remoteStats);
}
if (flowStats.remote.addedCount > 0) {
$('<span class="node-diff-node-added"><span class="node-diff-status"><i class="fa fa-plus-square"></i> '+flowStats.remote.addedCount+'</span></span>').appendTo(remoteStats);
}
if (flowStats.remote.changedCount > 0) {
$('<span class="node-diff-node-changed"><span class="node-diff-status"><i class="fa fa-square"></i> '+flowStats.remote.changedCount+'</span></span>').appendTo(remoteStats);
}
if (flowStats.remote.deletedCount > 0) {
$('<span class="node-diff-node-deleted"><span class="node-diff-status"><i class="fa fa-minus-square"></i> '+flowStats.remote.deletedCount+'</span></span>').appendTo(remoteStats);
}
$('<span class="node-diff-status"> ] </span>').appendTo(remoteStats);
2016-12-15 21:41:53 +01:00
}
}
} else {
remoteCell.addClass("node-diff-empty");
}
selectState = "";
2016-12-20 20:42:38 +01:00
if (flowStats.conflicts > 0) {
titleRow.addClass("node-diff-node-entry-conflict");
} else {
selectState = currentDiff.resolutions[tab.id];
2016-12-20 20:42:38 +01:00
}
if (tab.id) {
var hide = !(flowStats.conflicts > 0 &&(localDiff.deleted[tab.id] || remoteDiff.deleted[tab.id]));
// Tab parent row
createNodeConflictRadioBoxes(tab,titleRow,localCell,remoteCell, false, hide, selectState);
2016-12-20 20:42:38 +01:00
}
2016-12-07 14:51:20 +01:00
}
2016-12-20 20:42:38 +01:00
2016-12-07 14:51:20 +01:00
if (tabDiv.find(".node-diff-node-entry").length === 0) {
tabDiv.addClass("node-diff-tab-empty");
}
2017-01-04 23:02:35 +01:00
container.i18n();
2016-12-07 14:51:20 +01:00
}
});
return diffPanel;
2016-12-07 14:51:20 +01:00
}
2016-12-15 21:41:53 +01:00
function formatWireProperty(wires,allNodes) {
var result = $("<div>",{class:"node-diff-property-wires"})
var list = $("<ol></ol>");
var c = 0;
2016-12-07 14:51:20 +01:00
wires.forEach(function(p,i) {
2016-12-15 21:41:53 +01:00
var port = $("<li>").appendTo(list);
2016-12-07 14:51:20 +01:00
if (p && p.length > 0) {
2016-12-15 21:41:53 +01:00
$("<span>").html(i+1).appendTo(port);
2016-12-07 14:51:20 +01:00
var links = $("<ul>").appendTo(port);
p.forEach(function(d) {
2016-12-15 21:41:53 +01:00
c++;
var entry = $("<li>").appendTo(links);
var node = allNodes[d];
if (node) {
var def = RED.nodes.getType(node.type)||{};
createNode(node,def).appendTo(entry);
} else {
entry.html(d);
}
2016-12-07 14:51:20 +01:00
})
} else {
port.html('none');
}
})
2016-12-15 21:41:53 +01:00
if (c === 0) {
result.html("none");
} else {
list.appendTo(result);
}
2016-12-07 14:51:20 +01:00
return result;
}
function createNodeIcon(node,def) {
var nodeDiv = $("<div>",{class:"node-diff-node-entry-node"});
var colour = def.color;
var icon_url = RED.utils.getNodeIcon(def,node);
2016-12-07 14:51:20 +01:00
if (node.type === 'tab') {
colour = "#C0DEED";
}
nodeDiv.css('backgroundColor',colour);
var iconContainer = $('<div/>',{class:"palette_icon_container"}).appendTo(nodeDiv);
$('<div/>',{class:"palette_icon",style:"background-image: url("+icon_url+")"}).appendTo(iconContainer);
2016-12-07 14:51:20 +01:00
return nodeDiv;
}
2016-12-15 21:41:53 +01:00
function createNode(node,def) {
var nodeTitleDiv = $("<div>",{class:"node-diff-node-entry-title"})
createNodeIcon(node,def).appendTo(nodeTitleDiv);
var contentDiv = $('<div>',{class:"node-diff-node-description"}).appendTo(nodeTitleDiv);
var nodeLabel = node.label || node.name || node.id;
$('<span>',{class:"node-diff-node-label"}).html(nodeLabel).appendTo(contentDiv);
return nodeTitleDiv;
}
function createNodeDiffRow(node,stats) {
var localDiff = currentDiff.localDiff;
var remoteDiff = currentDiff.remoteDiff;
var conflicted = currentDiff.conflicts[node.id];
2016-12-15 21:41:53 +01:00
var hasChanges = false; // exists in original and local/remote but with changes
var unChanged = true; // existing in original,local,remote unchanged
2016-12-20 20:42:38 +01:00
var localChanged = false;
2016-12-15 21:41:53 +01:00
2016-12-07 14:51:20 +01:00
if (localDiff.added[node.id]) {
2016-12-15 21:41:53 +01:00
stats.local.addedCount++;
unChanged = false;
}
if (remoteDiff && remoteDiff.added[node.id]) {
stats.remote.addedCount++;
unChanged = false;
2016-12-07 14:51:20 +01:00
}
if (localDiff.deleted[node.id]) {
2016-12-15 21:41:53 +01:00
stats.local.deletedCount++;
unChanged = false;
}
if (remoteDiff && remoteDiff.deleted[node.id]) {
stats.remote.deletedCount++;
unChanged = false;
2016-12-07 14:51:20 +01:00
}
if (localDiff.changed[node.id]) {
2016-12-15 21:41:53 +01:00
stats.local.changedCount++;
2016-12-07 14:51:20 +01:00
hasChanges = true;
2016-12-15 21:41:53 +01:00
unChanged = false;
}
if (remoteDiff && remoteDiff.changed[node.id]) {
stats.remote.changedCount++;
hasChanges = true;
unChanged = false;
2016-12-07 14:51:20 +01:00
}
2016-12-20 20:42:38 +01:00
// console.log(node.id,localDiff.added[node.id],remoteDiff.added[node.id],localDiff.deleted[node.id],remoteDiff.deleted[node.id],localDiff.changed[node.id],remoteDiff.changed[node.id])
2016-12-15 21:41:53 +01:00
var def = RED.nodes.getType(node.type);
if (def === undefined) {
if (/^subflow:/.test(node.type)) {
def = {
icon:"subflow.png",
category: "subflows",
color: "#da9",
defaults:{name:{value:""}}
}
} else {
def = {};
2016-12-07 14:51:20 +01:00
}
}
2016-12-15 21:41:53 +01:00
var div = $("<div>",{class:"node-diff-node-entry collapsed"});
2016-12-20 20:42:38 +01:00
var row = $("<div>",{class:"node-diff-node-entry-header"}).appendTo(div);
2016-12-07 14:51:20 +01:00
2016-12-15 21:41:53 +01:00
var originalNodeDiv = $("<div>",{class:"node-diff-node-entry-cell"}).appendTo(row);
2016-12-20 20:42:38 +01:00
var localNodeDiv = $("<div>",{class:"node-diff-node-entry-cell node-diff-node-local"}).appendTo(row);
2016-12-15 21:41:53 +01:00
var remoteNodeDiv;
var chevron;
if (remoteDiff) {
2016-12-20 20:42:38 +01:00
remoteNodeDiv = $("<div>",{class:"node-diff-node-entry-cell node-diff-node-remote"}).appendTo(row);
2016-12-15 21:41:53 +01:00
}
$('<span class="node-diff-chevron"><i class="fa fa-angle-down"></i></span>').appendTo(originalNodeDiv);
2016-12-07 14:51:20 +01:00
2016-12-15 21:41:53 +01:00
if (unChanged) {
stats.local.unchangedCount++;
createNode(node,def).appendTo(originalNodeDiv);
localNodeDiv.addClass("node-diff-node-unchanged");
2017-01-04 23:02:35 +01:00
$('<span class="node-diff-status"><i class="fa fa-square-o"></i> <span data-i18n="diff.type.unchanged"></span></span>').appendTo(localNodeDiv);
2016-12-15 21:41:53 +01:00
if (remoteDiff) {
stats.remote.unchangedCount++;
remoteNodeDiv.addClass("node-diff-node-unchanged");
2017-01-04 23:02:35 +01:00
$('<span class="node-diff-status"><i class="fa fa-square-o"></i> <span data-i18n="diff.type.unchanged"></span></span>').appendTo(remoteNodeDiv);
2016-12-15 21:41:53 +01:00
}
div.addClass("node-diff-node-unchanged");
2016-12-15 21:41:53 +01:00
} else if (localDiff.added[node.id]) {
localNodeDiv.addClass("node-diff-node-added");
if (remoteNodeDiv) {
remoteNodeDiv.addClass("node-diff-empty");
}
2017-01-04 23:02:35 +01:00
$('<span class="node-diff-status"><i class="fa fa-plus-square"></i> <span data-i18n="diff.type.added"></span></span>').appendTo(localNodeDiv);
2016-12-15 21:41:53 +01:00
createNode(node,def).appendTo(originalNodeDiv);
} else if (remoteDiff && remoteDiff.added[node.id]) {
localNodeDiv.addClass("node-diff-empty");
remoteNodeDiv.addClass("node-diff-node-added");
2017-01-04 23:02:35 +01:00
$('<span class="node-diff-status"><i class="fa fa-plus-square"></i> <span data-i18n="diff.type.added"></span></span>').appendTo(remoteNodeDiv);
2016-12-15 21:41:53 +01:00
createNode(node,def).appendTo(originalNodeDiv);
} else {
createNode(node,def).appendTo(originalNodeDiv);
2016-12-23 13:53:59 +01:00
if (localDiff.moved[node.id]) {
var localN = localDiff.newConfig.all[node.id];
if (!localDiff.deleted[node.z] && node.z !== localN.z && node.z !== "" && !localDiff.newConfig.all[node.z]) {
localNodeDiv.addClass("node-diff-empty");
} else {
localNodeDiv.addClass("node-diff-node-moved");
var localMovedMessage = "";
if (node.z === localN.z) {
2017-01-04 23:02:35 +01:00
localMovedMessage = RED._("diff.type.movedFrom",{id:(localDiff.currentConfig.all[node.id].z||'global')});
2016-12-23 13:53:59 +01:00
} else {
2017-01-04 23:02:35 +01:00
localMovedMessage = RED._("diff.type.movedTo",{id:(localN.z||'global')});
2016-12-23 13:53:59 +01:00
}
$('<span class="node-diff-status"><i class="fa fa-caret-square-o-right"></i> '+localMovedMessage+'</span>').appendTo(localNodeDiv);
}
localChanged = true;
} else if (localDiff.deleted[node.z]) {
2016-12-15 21:41:53 +01:00
localNodeDiv.addClass("node-diff-empty");
2016-12-20 20:42:38 +01:00
localChanged = true;
2016-12-15 21:41:53 +01:00
} else if (localDiff.deleted[node.id]) {
localNodeDiv.addClass("node-diff-node-deleted");
2017-01-04 23:02:35 +01:00
$('<span class="node-diff-status"><i class="fa fa-minus-square"></i> <span data-i18n="diff.type.deleted"></span></span>').appendTo(localNodeDiv);
2016-12-20 20:42:38 +01:00
localChanged = true;
2016-12-15 21:41:53 +01:00
} else if (localDiff.changed[node.id]) {
2016-12-23 13:53:59 +01:00
if (localDiff.newConfig.all[node.id].z !== node.z) {
localNodeDiv.addClass("node-diff-empty");
} else {
localNodeDiv.addClass("node-diff-node-changed");
2017-01-04 23:02:35 +01:00
$('<span class="node-diff-status"><i class="fa fa-square"></i> <span data-i18n="diff.type.changed"></span></span>').appendTo(localNodeDiv);
2016-12-23 13:53:59 +01:00
localChanged = true;
}
2016-12-15 21:41:53 +01:00
} else {
2016-12-23 13:53:59 +01:00
if (localDiff.newConfig.all[node.id].z !== node.z) {
localNodeDiv.addClass("node-diff-empty");
} else {
stats.local.unchangedCount++;
localNodeDiv.addClass("node-diff-node-unchanged");
2017-01-04 23:02:35 +01:00
$('<span class="node-diff-status"><i class="fa fa-square-o"></i> <span data-i18n="diff.type.unchanged"></span></span>').appendTo(localNodeDiv);
2016-12-23 13:53:59 +01:00
}
2016-12-15 21:41:53 +01:00
}
2016-12-07 14:51:20 +01:00
2016-12-15 21:41:53 +01:00
if (remoteDiff) {
2016-12-23 13:53:59 +01:00
if (remoteDiff.moved[node.id]) {
var remoteN = remoteDiff.newConfig.all[node.id];
if (!remoteDiff.deleted[node.z] && node.z !== remoteN.z && node.z !== "" && !remoteDiff.newConfig.all[node.z]) {
remoteNodeDiv.addClass("node-diff-empty");
} else {
remoteNodeDiv.addClass("node-diff-node-moved");
var remoteMovedMessage = "";
if (node.z === remoteN.z) {
2017-01-04 23:02:35 +01:00
remoteMovedMessage = RED._("diff.type.movedFrom",{id:(remoteDiff.currentConfig.all[node.id].z||'global')});
2016-12-23 13:53:59 +01:00
} else {
2017-01-04 23:02:35 +01:00
remoteMovedMessage = RED._("diff.type.movedTo",{id:(remoteN.z||'global')});
2016-12-23 13:53:59 +01:00
}
$('<span class="node-diff-status"><i class="fa fa-caret-square-o-right"></i> '+remoteMovedMessage+'</span>').appendTo(remoteNodeDiv);
}
} else if (remoteDiff.deleted[node.z]) {
2016-12-15 21:41:53 +01:00
remoteNodeDiv.addClass("node-diff-empty");
} else if (remoteDiff.deleted[node.id]) {
remoteNodeDiv.addClass("node-diff-node-deleted");
2017-01-04 23:02:35 +01:00
$('<span class="node-diff-status"><i class="fa fa-minus-square"></i> <span data-i18n="diff.type.deleted"></span></span>').appendTo(remoteNodeDiv);
2016-12-15 21:41:53 +01:00
} else if (remoteDiff.changed[node.id]) {
2016-12-23 13:53:59 +01:00
if (remoteDiff.newConfig.all[node.id].z !== node.z) {
remoteNodeDiv.addClass("node-diff-empty");
} else {
remoteNodeDiv.addClass("node-diff-node-changed");
2017-01-04 23:02:35 +01:00
$('<span class="node-diff-status"><i class="fa fa-square"></i> <span data-i18n="diff.type.changed"></span></span>').appendTo(remoteNodeDiv);
2016-12-23 13:53:59 +01:00
}
2016-12-15 21:41:53 +01:00
} else {
2016-12-23 13:53:59 +01:00
if (remoteDiff.newConfig.all[node.id].z !== node.z) {
remoteNodeDiv.addClass("node-diff-empty");
} else {
stats.remote.unchangedCount++;
remoteNodeDiv.addClass("node-diff-node-unchanged");
2017-01-04 23:02:35 +01:00
$('<span class="node-diff-status"><i class="fa fa-square-o"></i> <span data-i18n="diff.type.unchanged"></span></span>').appendTo(remoteNodeDiv);
2016-12-23 13:53:59 +01:00
}
2016-12-15 21:41:53 +01:00
}
}
}
var localNode = {
node: localDiff.newConfig.all[node.id],
all: localDiff.newConfig.all,
diff: localDiff
};
var remoteNode;
if (remoteDiff) {
remoteNode = {
node:remoteDiff.newConfig.all[node.id]||null,
all: remoteDiff.newConfig.all,
diff: remoteDiff
}
}
2016-12-20 20:42:38 +01:00
createNodePropertiesTable(def,node,localNode,remoteNode).appendTo(div);
var selectState = "";
if (conflicted) {
stats.conflicts++;
if (!localNodeDiv.hasClass("node-diff-empty")) {
$('<span class="node-diff-node-conflict"><span class="node-diff-status"><i class="fa fa-exclamation"></i></span></span>').prependTo(localNodeDiv);
}
if (!remoteNodeDiv.hasClass("node-diff-empty")) {
$('<span class="node-diff-node-conflict"><span class="node-diff-status"><i class="fa fa-exclamation"></i></span></span>').prependTo(remoteNodeDiv);
}
div.addClass("node-diff-node-entry-conflict");
} else {
selectState = currentDiff.resolutions[node.id];
2016-12-15 21:41:53 +01:00
}
// Node row
2016-12-20 20:42:38 +01:00
createNodeConflictRadioBoxes(node,div,localNodeDiv,remoteNodeDiv,false,!conflicted,selectState);
2016-12-15 21:41:53 +01:00
row.click(function(evt) {
$(this).parent().toggleClass('collapsed');
});
2016-12-07 14:51:20 +01:00
return div;
}
2016-12-20 20:42:38 +01:00
function createNodePropertiesTable(def,node,localNodeObj,remoteNodeObj) {
var propertyElements = {};
2016-12-15 21:41:53 +01:00
var localNode = localNodeObj.node;
var remoteNode;
if (remoteNodeObj) {
remoteNode = remoteNodeObj.node;
}
2016-12-07 14:51:20 +01:00
var nodePropertiesDiv = $("<div>",{class:"node-diff-node-entry-properties"});
var nodePropertiesTable = $("<table>").appendTo(nodePropertiesDiv);
var nodePropertiesTableCols = $('<colgroup><col/><col/></colgroup>').appendTo(nodePropertiesTable);
if (remoteNode !== undefined) {
$("<col/>").appendTo(nodePropertiesTableCols);
}
var nodePropertiesTableBody = $("<tbody>").appendTo(nodePropertiesTable);
2016-12-07 14:51:20 +01:00
var row;
2016-12-15 21:41:53 +01:00
var localCell, remoteCell;
var element;
2016-12-15 21:41:53 +01:00
var currentValue, localValue, remoteValue;
var localChanged = false;
var remoteChanged = false;
var localChanges = 0;
var remoteChanges = 0;
var conflict = false;
var status;
row = $("<tr>").appendTo(nodePropertiesTableBody);
2016-12-23 13:53:59 +01:00
$("<td>",{class:"node-diff-property-cell-label"}).html("id").appendTo(row);
localCell = $("<td>",{class:"node-diff-property-cell node-diff-node-local"}).appendTo(row);
if (localNode) {
localCell.addClass("node-diff-node-unchanged");
$('<span class="node-diff-status"></span>').appendTo(localCell);
element = $('<span class="node-diff-element"></span>').appendTo(localCell);
propertyElements['local.id'] = RED.utils.createObjectElement(localNode.id).appendTo(element);
2016-12-23 13:53:59 +01:00
} else {
localCell.addClass("node-diff-empty");
}
if (remoteNode !== undefined) {
remoteCell = $("<td>",{class:"node-diff-property-cell node-diff-node-remote"}).appendTo(row);
remoteCell.addClass("node-diff-node-unchanged");
if (remoteNode) {
$('<span class="node-diff-status"></span>').appendTo(remoteCell);
element = $('<span class="node-diff-element"></span>').appendTo(remoteCell);
propertyElements['remote.id'] = RED.utils.createObjectElement(remoteNode.id).appendTo(element);
2016-12-23 13:53:59 +01:00
} else {
remoteCell.addClass("node-diff-empty");
}
}
2016-12-07 14:51:20 +01:00
if (node.hasOwnProperty('x')) {
2016-12-15 21:41:53 +01:00
if (localNode) {
if (localNode.x !== node.x || localNode.y !== node.y) {
localChanged = true;
localChanges++;
}
}
if (remoteNode) {
if (remoteNode.x !== node.x || remoteNode.y !== node.y) {
remoteChanged = true;
remoteChanges++;
}
}
2016-12-20 20:42:38 +01:00
if ( (remoteChanged && localChanged && (localNode.x !== remoteNode.x || localNode.y !== remoteNode.y)) ||
2016-12-15 21:41:53 +01:00
(!localChanged && remoteChanged && localNodeObj.diff.deleted[node.id]) ||
(localChanged && !remoteChanged && remoteNodeObj.diff.deleted[node.id])
) {
conflict = true;
}
row = $("<tr>").appendTo(nodePropertiesTableBody);
2016-12-15 21:41:53 +01:00
$("<td>",{class:"node-diff-property-cell-label"}).html("position").appendTo(row);
2016-12-20 20:42:38 +01:00
localCell = $("<td>",{class:"node-diff-property-cell node-diff-node-local"}).appendTo(row);
2016-12-15 21:41:53 +01:00
if (localNode) {
localCell.addClass("node-diff-node-"+(localChanged?"changed":"unchanged"));
2016-12-20 20:42:38 +01:00
$('<span class="node-diff-status">'+(localChanged?'<i class="fa fa-square"></i>':'')+'</span>').appendTo(localCell);
element = $('<span class="node-diff-element"></span>').appendTo(localCell);
propertyElements['local.position'] = RED.utils.createObjectElement({x:localNode.x,y:localNode.y},
{
path: "position",
exposeApi: true,
ontoggle: function(path,state) {
if (propertyElements['remote.'+path]) {
propertyElements['remote.'+path].prop('expand')(path,state)
}
}
}
).appendTo(element);
2016-12-15 21:41:53 +01:00
} else {
localCell.addClass("node-diff-empty");
}
2016-12-07 14:51:20 +01:00
2016-12-15 21:41:53 +01:00
if (remoteNode !== undefined) {
2016-12-20 20:42:38 +01:00
remoteCell = $("<td>",{class:"node-diff-property-cell node-diff-node-remote"}).appendTo(row);
2016-12-15 21:41:53 +01:00
remoteCell.addClass("node-diff-node-"+(remoteChanged?"changed":"unchanged"));
if (remoteNode) {
2016-12-20 20:42:38 +01:00
$('<span class="node-diff-status">'+(remoteChanged?'<i class="fa fa-square"></i>':'')+'</span>').appendTo(remoteCell);
element = $('<span class="node-diff-element"></span>').appendTo(remoteCell);
propertyElements['remote.position'] = RED.utils.createObjectElement({x:remoteNode.x,y:remoteNode.y},
{
path: "position",
exposeApi: true,
ontoggle: function(path,state) {
if (propertyElements['local.'+path]) {
propertyElements['local.'+path].prop('expand')(path,state);
}
}
}
).appendTo(element);
2016-12-15 21:41:53 +01:00
} else {
remoteCell.addClass("node-diff-empty");
}
2016-12-07 14:51:20 +01:00
}
}
2016-12-15 21:41:53 +01:00
//
localChanged = remoteChanged = conflict = false;
2016-12-07 14:51:20 +01:00
if (node.hasOwnProperty('wires')) {
2016-12-15 21:41:53 +01:00
currentValue = JSON.stringify(node.wires);
if (localNode) {
localValue = JSON.stringify(localNode.wires);
if (currentValue !== localValue) {
localChanged = true;
localChanges++;
}
}
if (remoteNode) {
remoteValue = JSON.stringify(remoteNode.wires);
if (currentValue !== remoteValue) {
remoteChanged = true;
remoteChanges++;
}
}
if ( (remoteChanged && localChanged && (localValue !== remoteValue)) ||
(!localChanged && remoteChanged && localNodeObj.diff.deleted[node.id]) ||
(localChanged && !remoteChanged && remoteNodeObj.diff.deleted[node.id])
){
conflict = true;
}
row = $("<tr>").appendTo(nodePropertiesTableBody);
2016-12-15 21:41:53 +01:00
$("<td>",{class:"node-diff-property-cell-label"}).html("wires").appendTo(row);
2016-12-20 20:42:38 +01:00
localCell = $("<td>",{class:"node-diff-property-cell node-diff-node-local"}).appendTo(row);
2016-12-15 21:41:53 +01:00
if (localNode) {
if (!conflict) {
localCell.addClass("node-diff-node-"+(localChanged?"changed":"unchanged"));
2016-12-20 20:42:38 +01:00
$('<span class="node-diff-status">'+(localChanged?'<i class="fa fa-square"></i>':'')+'</span>').appendTo(localCell);
2016-12-15 21:41:53 +01:00
} else {
localCell.addClass("node-diff-node-conflict");
$('<span class="node-diff-status"><i class="fa fa-exclamation"></i></span>').appendTo(localCell);
}
formatWireProperty(localNode.wires,localNodeObj.all).appendTo(localCell);
} else {
localCell.addClass("node-diff-empty");
2016-12-07 14:51:20 +01:00
}
2016-12-15 21:41:53 +01:00
if (remoteNode !== undefined) {
2016-12-20 20:42:38 +01:00
remoteCell = $("<td>",{class:"node-diff-property-cell node-diff-node-remote"}).appendTo(row);
2016-12-15 21:41:53 +01:00
if (remoteNode) {
if (!conflict) {
remoteCell.addClass("node-diff-node-"+(remoteChanged?"changed":"unchanged"));
2016-12-20 20:42:38 +01:00
$('<span class="node-diff-status">'+(remoteChanged?'<i class="fa fa-square"></i>':'')+'</span>').appendTo(remoteCell);
2016-12-15 21:41:53 +01:00
} else {
remoteCell.addClass("node-diff-node-conflict");
$('<span class="node-diff-status"><i class="fa fa-exclamation"></i></span>').appendTo(remoteCell);
}
formatWireProperty(remoteNode.wires,remoteNodeObj.all).appendTo(remoteCell);
} else {
remoteCell.addClass("node-diff-empty");
}
}
2016-12-07 14:51:20 +01:00
}
var properties = Object.keys(node).filter(function(p) { return p!='inputLabels'&&p!='outputLabels'&&p!='z'&&p!='wires'&&p!=='x'&&p!=='y'&&p!=='id'&&p!=='type'&&(!def.defaults||!def.defaults.hasOwnProperty(p))});
2016-12-07 14:51:20 +01:00
if (def.defaults) {
properties = properties.concat(Object.keys(def.defaults));
}
if (node.type !== 'tab') {
properties = properties.concat(['inputLabels','outputLabels']);
}
2016-12-07 14:51:20 +01:00
properties.forEach(function(d) {
2016-12-15 21:41:53 +01:00
localChanged = false;
remoteChanged = false;
conflict = false;
currentValue = JSON.stringify(node[d]);
if (localNode) {
localValue = JSON.stringify(localNode[d]);
if (currentValue !== localValue) {
localChanged = true;
localChanges++;
}
}
if (remoteNode) {
remoteValue = JSON.stringify(remoteNode[d]);
if (currentValue !== remoteValue) {
remoteChanged = true;
remoteChanges++;
}
2016-12-07 14:51:20 +01:00
}
2016-12-15 21:41:53 +01:00
if ( (remoteChanged && localChanged && (localValue !== remoteValue)) ||
(!localChanged && remoteChanged && localNodeObj.diff.deleted[node.id]) ||
(localChanged && !remoteChanged && remoteNodeObj.diff.deleted[node.id])
){
conflict = true;
}
2016-12-07 14:51:20 +01:00
row = $("<tr>").appendTo(nodePropertiesTableBody);
var propertyNameCell = $("<td>",{class:"node-diff-property-cell-label"}).html(d).appendTo(row);
2016-12-20 20:42:38 +01:00
localCell = $("<td>",{class:"node-diff-property-cell node-diff-node-local"}).appendTo(row);
2016-12-15 21:41:53 +01:00
if (localNode) {
if (!conflict) {
localCell.addClass("node-diff-node-"+(localChanged?"changed":"unchanged"));
2016-12-20 20:42:38 +01:00
$('<span class="node-diff-status">'+(localChanged?'<i class="fa fa-square"></i>':'')+'</span>').appendTo(localCell);
2016-12-15 21:41:53 +01:00
} else {
localCell.addClass("node-diff-node-conflict");
$('<span class="node-diff-status"><i class="fa fa-exclamation"></i></span>').appendTo(localCell);
}
element = $('<span class="node-diff-element"></span>').appendTo(localCell);
propertyElements['local.'+d] = RED.utils.createObjectElement(localNode[d],
{
path: d,
exposeApi: true,
ontoggle: function(path,state) {
if (propertyElements['remote.'+d]) {
propertyElements['remote.'+d].prop('expand')(path,state)
}
}
}
).appendTo(element);
2016-12-15 21:41:53 +01:00
} else {
localCell.addClass("node-diff-empty");
}
if (remoteNode !== undefined) {
2016-12-20 20:42:38 +01:00
remoteCell = $("<td>",{class:"node-diff-property-cell node-diff-node-remote"}).appendTo(row);
2016-12-15 21:41:53 +01:00
if (remoteNode) {
if (!conflict) {
remoteCell.addClass("node-diff-node-"+(remoteChanged?"changed":"unchanged"));
2016-12-20 20:42:38 +01:00
$('<span class="node-diff-status">'+(remoteChanged?'<i class="fa fa-square"></i>':'')+'</span>').appendTo(remoteCell);
2016-12-15 21:41:53 +01:00
} else {
remoteCell.addClass("node-diff-node-conflict");
$('<span class="node-diff-status"><i class="fa fa-exclamation"></i></span>').appendTo(remoteCell);
}
element = $('<span class="node-diff-element"></span>').appendTo(remoteCell);
propertyElements['remote.'+d] = RED.utils.createObjectElement(remoteNode[d],
{
path: d,
exposeApi: true,
ontoggle: function(path,state) {
if (propertyElements['local.'+d]) {
propertyElements['local.'+d].prop('expand')(path,state)
}
}
}
).appendTo(element);
2016-12-15 21:41:53 +01:00
} else {
remoteCell.addClass("node-diff-empty");
}
}
2017-08-20 23:59:51 +02:00
if (localNode && remoteNode && typeof localNode[d] === "string") {
if (/\n/.test(localNode[d]) || /\n/.test(remoteNode[d])) {
$('<button class="editor-button editor-button-small node-diff-text-diff-button"><i class="fa fa-file-o"> <i class="fa fa-caret-left"></i> <i class="fa fa-caret-right"></i> <i class="fa fa-file-o"></i></button>').click(function() {
showTextDiff(localNode[d],remoteNode[d]);
}).appendTo(propertyNameCell);
}
}
2016-12-15 21:41:53 +01:00
});
2016-12-20 20:42:38 +01:00
return nodePropertiesDiv;
}
function createNodeConflictRadioBoxes(node,row,localDiv,remoteDiv,propertiesTable,hide,state) {
var safeNodeId = "node-diff-selectbox-"+node.id.replace(/\./g,'-')+(propertiesTable?"-props":"");
var className = "";
if (node.z||propertiesTable) {
className = "node-diff-selectbox-tab-"+(propertiesTable?node.id:node.z).replace(/\./g,'-');
}
var titleRow = !propertiesTable && (node.type === 'tab' || node.type === 'subflow');
var changeHandler = function(evt) {
var className;
if (node.type === undefined) {
// TODO: handle globals
} else if (titleRow) {
className = "node-diff-selectbox-tab-"+node.id.replace(/\./g,'-');
$("."+className+"-"+this.value).prop('checked',true);
if (this.value === 'local') {
$("."+className+"-"+this.value).closest(".node-diff-node-entry").addClass("node-diff-select-local");
$("."+className+"-"+this.value).closest(".node-diff-node-entry").removeClass("node-diff-select-remote");
} else {
$("."+className+"-"+this.value).closest(".node-diff-node-entry").removeClass("node-diff-select-local");
$("."+className+"-"+this.value).closest(".node-diff-node-entry").addClass("node-diff-select-remote");
}
} else {
// Individual node or properties table
var parentId = "node-diff-selectbox-"+(propertiesTable?node.id:node.z).replace(/\./g,'-');
$('#'+parentId+"-local").prop('checked',false);
$('#'+parentId+"-remote").prop('checked',false);
var titleRowDiv = $('#'+parentId+"-local").closest(".node-diff-tab").find(".node-diff-tab-title");
titleRowDiv.removeClass("node-diff-select-local");
titleRowDiv.removeClass("node-diff-select-remote");
}
if (this.value === 'local') {
row.removeClass("node-diff-select-remote");
row.addClass("node-diff-select-local");
} else if (this.value === 'remote') {
row.addClass("node-diff-select-remote");
row.removeClass("node-diff-select-local");
}
refreshConflictHeader();
}
2016-12-07 14:51:20 +01:00
2016-12-20 20:42:38 +01:00
var localSelectDiv = $('<label>',{class:"node-diff-selectbox",for:safeNodeId+"-local"}).click(function(e) { e.stopPropagation();}).appendTo(localDiv);
var localRadio = $('<input>',{id:safeNodeId+"-local",type:'radio',value:"local",name:safeNodeId,class:className+"-local"+(titleRow?"":" node-diff-select-node")}).data('node-id',node.id).change(changeHandler).appendTo(localSelectDiv);
var remoteSelectDiv = $('<label>',{class:"node-diff-selectbox",for:safeNodeId+"-remote"}).click(function(e) { e.stopPropagation();}).appendTo(remoteDiv);
var remoteRadio = $('<input>',{id:safeNodeId+"-remote",type:'radio',value:"remote",name:safeNodeId,class:className+"-remote"+(titleRow?"":" node-diff-select-node")}).data('node-id',node.id).change(changeHandler).appendTo(remoteSelectDiv);
if (state === 'local') {
localRadio.prop('checked',true);
} else if (state === 'remote') {
remoteRadio.prop('checked',true);
2016-12-15 21:41:53 +01:00
}
2016-12-20 20:42:38 +01:00
if (hide||localDiv.hasClass("node-diff-empty") || remoteDiv.hasClass("node-diff-empty")) {
localSelectDiv.hide();
remoteSelectDiv.hide();
}
2016-12-15 21:41:53 +01:00
}
2016-12-20 20:42:38 +01:00
function refreshConflictHeader() {
var resolutionCount = 0;
$(".node-diff-selectbox>input:checked").each(function() {
if (currentDiff.conflicts[$(this).data('node-id')]) {
resolutionCount++;
}
currentDiff.resolutions[$(this).data('node-id')] = $(this).val();
})
var conflictCount = Object.keys(currentDiff.conflicts).length;
if (conflictCount - resolutionCount === 0) {
$("#node-diff-toolbar-resolved-conflicts").html('<span class="node-diff-node-added"><span class="node-diff-status"><i class="fa fa-check"></i></span></span> '+RED._("diff.unresolvedCount",{count:conflictCount - resolutionCount}));
} else {
$("#node-diff-toolbar-resolved-conflicts").html('<span class="node-diff-node-conflict"><span class="node-diff-status"><i class="fa fa-exclamation"></i></span></span> '+RED._("diff.unresolvedCount",{count:conflictCount - resolutionCount}));
}
if (conflictCount === resolutionCount) {
$("#node-diff-view-diff-merge").removeClass('disabled');
}
2016-12-07 14:51:20 +01:00
}
2016-12-20 20:42:38 +01:00
function getRemoteDiff(callback) {
2016-12-15 21:41:53 +01:00
$.ajax({
headers: {
"Accept":"application/json",
},
cache: false,
url: 'flows',
success: function(nodes) {
var localFlow = RED.nodes.createCompleteNodeSet();
var originalFlow = RED.nodes.originalFlow();
var remoteFlow = nodes.flows;
var localDiff = generateDiff(originalFlow,localFlow);
var remoteDiff = generateDiff(originalFlow,remoteFlow);
remoteDiff.rev = nodes.rev;
callback(resolveDiffs(localDiff,remoteDiff))
2016-12-15 21:41:53 +01:00
}
});
2016-12-20 20:42:38 +01:00
}
// function showLocalDiff() {
// var nns = RED.nodes.createCompleteNodeSet();
// var originalFlow = RED.nodes.originalFlow();
// var diff = generateDiff(originalFlow,nns);
// showDiff(diff);
// }
2016-12-20 20:42:38 +01:00
function showRemoteDiff(diff) {
if (diff === undefined) {
getRemoteDiff(showRemoteDiff);
} else {
showDiff(diff);
2016-12-20 20:42:38 +01:00
}
2016-12-15 21:41:53 +01:00
}
2016-12-07 14:51:20 +01:00
function parseNodes(nodeList) {
var tabOrder = [];
var tabs = {};
var subflows = {};
var globals = [];
var all = {};
nodeList.forEach(function(node) {
all[node.id] = node;
if (node.type === 'tab') {
tabOrder.push(node.id);
tabs[node.id] = {n:node,nodes:[]};
} else if (node.type === 'subflow') {
subflows[node.id] = {n:node,nodes:[]};
}
});
nodeList.forEach(function(node) {
if (node.type !== 'tab' && node.type !== 'subflow') {
if (tabs[node.z]) {
tabs[node.z].nodes.push(node);
} else if (subflows[node.z]) {
subflows[node.z].nodes.push(node);
} else {
globals.push(node);
}
}
});
return {
all: all,
tabOrder: tabOrder,
tabs: tabs,
subflows: subflows,
globals: globals
}
}
function generateDiff(currentNodes,newNodes) {
var currentConfig = parseNodes(currentNodes);
var newConfig = parseNodes(newNodes);
var added = {};
var deleted = {};
var changed = {};
2016-12-23 13:53:59 +01:00
var moved = {};
2016-12-07 14:51:20 +01:00
Object.keys(currentConfig.all).forEach(function(id) {
var node = RED.nodes.workspace(id)||RED.nodes.subflow(id)||RED.nodes.node(id);
if (!newConfig.all.hasOwnProperty(id)) {
2016-12-20 20:42:38 +01:00
deleted[id] = true;
2016-12-07 14:51:20 +01:00
} else if (JSON.stringify(currentConfig.all[id]) !== JSON.stringify(newConfig.all[id])) {
changed[id] = true;
2016-12-23 13:53:59 +01:00
if (currentConfig.all[id].z !== newConfig.all[id].z) {
moved[id] = true;
}
2016-12-07 14:51:20 +01:00
}
});
Object.keys(newConfig.all).forEach(function(id) {
2016-12-20 20:42:38 +01:00
if (!currentConfig.all.hasOwnProperty(id)) {
2016-12-07 14:51:20 +01:00
added[id] = true;
}
});
return {
currentConfig: currentConfig,
newConfig: newConfig,
added: added,
deleted: deleted,
changed: changed,
2016-12-23 13:53:59 +01:00
moved: moved
2016-12-07 14:51:20 +01:00
}
}
function resolveDiffs(localDiff,remoteDiff) {
2016-12-20 20:42:38 +01:00
var conflicted = {};
var resolutions = {};
2016-12-20 20:42:38 +01:00
var diff = {
localDiff: localDiff,
remoteDiff: remoteDiff,
conflicts: conflicted,
resolutions: resolutions
}
var seen = {};
var id,node;
2016-12-20 20:42:38 +01:00
for (id in localDiff.currentConfig.all) {
if (localDiff.currentConfig.all.hasOwnProperty(id)) {
seen[id] = true;
var localNode = localDiff.newConfig.all[id];
if (localDiff.changed[id] && remoteDiff.deleted[id]) {
conflicted[id] = true;
} else if (localDiff.deleted[id] && remoteDiff.changed[id]) {
conflicted[id] = true;
} else if (localDiff.changed[id] && remoteDiff.changed[id]) {
var remoteNode = remoteDiff.newConfig.all[id];
if (JSON.stringify(localNode) !== JSON.stringify(remoteNode)) {
conflicted[id] = true;
}
}
if (!conflicted[id]) {
if (remoteDiff.added[id]||remoteDiff.changed[id]||remoteDiff.deleted[id]) {
resolutions[id] = 'remote';
} else {
resolutions[id] = 'local';
}
}
2016-12-20 20:42:38 +01:00
}
2016-12-07 14:51:20 +01:00
}
2016-12-20 20:42:38 +01:00
for (id in localDiff.added) {
if (localDiff.added.hasOwnProperty(id)) {
node = localDiff.newConfig.all[id];
if (remoteDiff.deleted[node.z]) {
conflicted[id] = true;
// conflicted[node.z] = true;
} else {
resolutions[id] = 'local';
2016-12-20 20:42:38 +01:00
}
}
}
for (id in remoteDiff.added) {
if (remoteDiff.added.hasOwnProperty(id)) {
node = remoteDiff.newConfig.all[id];
if (localDiff.deleted[node.z]) {
conflicted[id] = true;
// conflicted[node.z] = true;
} else {
resolutions[id] = 'remote';
2016-12-20 20:42:38 +01:00
}
}
2016-12-07 14:51:20 +01:00
}
// console.log(diff.resolutions);
2016-12-20 20:42:38 +01:00
// console.log(conflicted);
return diff;
2016-12-07 14:51:20 +01:00
}
function showDiff(diff) {
if (diffVisible) {
return;
}
var localDiff = diff.localDiff;
var remoteDiff = diff.remoteDiff;
var conflicts = diff.conflicts;
currentDiff = diff;
2016-12-07 14:51:20 +01:00
var trayOptions = {
title: "Review Changes", //TODO: nls
width: Infinity,
buttons: [
{
text: RED._("common.label.cancel"),
click: function() {
RED.tray.close();
}
},
{
id: "node-diff-view-diff-merge",
text: RED._("deploy.confirm.button.merge"),
class: "primary disabled",
click: function() {
if (!$("#node-diff-view-diff-merge").hasClass('disabled')) {
refreshConflictHeader();
mergeDiff(currentDiff);
RED.tray.close();
}
}
}
],
resize: function(dimensions) {
// trayWidth = dimensions.width;
2016-12-07 14:51:20 +01:00
},
open: function(tray) {
var trayBody = tray.find('.editor-tray-body');
var diffPanel = buildDiffPanel(trayBody);
if (remoteDiff) {
$("#node-diff-view-diff-merge").show();
if (Object.keys(conflicts).length === 0) {
$("#node-diff-view-diff-merge").removeClass('disabled');
} else {
$("#node-diff-view-diff-merge").addClass('disabled');
}
} else {
$("#node-diff-view-diff-merge").hide();
}
refreshConflictHeader();
2016-12-07 14:51:20 +01:00
$("#node-dialog-view-diff-headers").empty();
// console.log("--------------");
// console.log(localDiff);
// console.log(remoteDiff);
var currentConfig = localDiff.currentConfig;
var newConfig = localDiff.newConfig;
conflicts = conflicts || {};
2016-12-07 14:51:20 +01:00
var el = {
diff: localDiff,
def: {
category: 'config',
color: '#f0f0f0'
},
tab: {
n: {},
nodes: currentConfig.globals
},
newTab: {
n: {},
nodes: newConfig.globals
}
2016-12-07 14:51:20 +01:00
};
2016-12-15 21:41:53 +01:00
if (remoteDiff !== undefined) {
diffPanel.addClass('node-diff-three-way');
$('<div data-i18n="diff.local"></div><div data-i18n="diff.remote"></div>').i18n().appendTo("#node-dialog-view-diff-headers");
el.remoteTab = {
n:{},
nodes:remoteDiff.newConfig.globals
};
2016-12-15 21:41:53 +01:00
el.remoteDiff = remoteDiff;
} else {
diffPanel.removeClass('node-diff-three-way');
2016-12-15 21:41:53 +01:00
}
diffList.editableList('addItem',el);
var seenTabs = {};
currentConfig.tabOrder.forEach(function(tabId) {
var tab = currentConfig.tabs[tabId];
2016-12-15 21:41:53 +01:00
var el = {
diff: localDiff,
def: RED.nodes.getType('tab'),
tab:tab
2016-12-15 21:41:53 +01:00
};
if (newConfig.tabs.hasOwnProperty(tabId)) {
el.newTab = newConfig.tabs[tabId];
}
if (remoteDiff !== undefined) {
el.remoteTab = remoteDiff.newConfig.tabs[tabId];
el.remoteDiff = remoteDiff;
}
seenTabs[tabId] = true;
diffList.editableList('addItem',el)
});
newConfig.tabOrder.forEach(function(tabId) {
if (!seenTabs[tabId]) {
seenTabs[tabId] = true;
var tab = newConfig.tabs[tabId];
var el = {
diff: localDiff,
def: RED.nodes.getType('tab'),
tab:tab,
newTab: tab
};
if (remoteDiff !== undefined) {
el.remoteDiff = remoteDiff;
}
diffList.editableList('addItem',el)
}
});
2016-12-15 21:41:53 +01:00
if (remoteDiff !== undefined) {
remoteDiff.newConfig.tabOrder.forEach(function(tabId) {
if (!seenTabs[tabId]) {
var tab = remoteDiff.newConfig.tabs[tabId];
// TODO how to recognise this is a remotely added flow
var el = {
diff: localDiff,
remoteDiff: remoteDiff,
def: RED.nodes.getType('tab'),
tab:tab,
remoteTab:tab
};
diffList.editableList('addItem',el)
}
});
2016-12-15 21:41:53 +01:00
}
var subflowId;
for (subflowId in currentConfig.subflows) {
if (currentConfig.subflows.hasOwnProperty(subflowId)) {
seenTabs[subflowId] = true;
el = {
diff: localDiff,
def: {
defaults:{},
icon:"subflow.png",
category: "subflows",
color: "#da9"
},
tab:currentConfig.subflows[subflowId]
}
if (newConfig.subflows.hasOwnProperty(subflowId)) {
el.newTab = newConfig.subflows[subflowId];
}
if (remoteDiff !== undefined) {
el.remoteTab = remoteDiff.newConfig.subflows[subflowId];
el.remoteDiff = remoteDiff;
}
diffList.editableList('addItem',el)
}
2016-12-15 21:41:53 +01:00
}
for (subflowId in newConfig.subflows) {
if (newConfig.subflows.hasOwnProperty(subflowId) && !seenTabs[subflowId]) {
seenTabs[subflowId] = true;
el = {
diff: localDiff,
def: {
defaults:{},
icon:"subflow.png",
category: "subflows",
color: "#da9"
},
tab:newConfig.subflows[subflowId],
newTab:newConfig.subflows[subflowId]
}
if (remoteDiff !== undefined) {
el.remoteDiff = remoteDiff;
}
diffList.editableList('addItem',el)
}
2016-12-07 14:51:20 +01:00
}
if (remoteDiff !== undefined) {
for (subflowId in remoteDiff.newConfig.subflows) {
if (remoteDiff.newConfig.subflows.hasOwnProperty(subflowId) && !seenTabs[subflowId]) {
el = {
diff: localDiff,
remoteDiff: remoteDiff,
def: {
defaults:{},
icon:"subflow.png",
category: "subflows",
color: "#da9"
},
tab:remoteDiff.newConfig.subflows[subflowId],
remoteTab: remoteDiff.newConfig.subflows[subflowId]
}
diffList.editableList('addItem',el)
}
2016-12-15 21:41:53 +01:00
}
}
$("#sidebar-shade").show();
},
close: function() {
diffVisible = false;
$("#sidebar-shade").hide();
2016-12-07 14:51:20 +01:00
},
show: function() {
2016-12-07 14:51:20 +01:00
}
}
RED.tray.show(trayOptions);
2016-12-07 14:51:20 +01:00
}
2016-12-20 20:42:38 +01:00
function mergeDiff(diff) {
var currentConfig = diff.localDiff.currentConfig;
var localDiff = diff.localDiff;
var remoteDiff = diff.remoteDiff;
var conflicts = diff.conflicts;
var resolutions = diff.resolutions;
var id;
for (id in conflicts) {
if (conflicts.hasOwnProperty(id)) {
if (!resolutions.hasOwnProperty(id)) {
console.log(diff);
throw new Error("No resolution for conflict on node",id);
}
2016-12-20 20:42:38 +01:00
}
}
var newConfig = [];
var node;
var nodeChangedStates = {};
var localChangedStates = {};
for (id in localDiff.newConfig.all) {
if (localDiff.newConfig.all.hasOwnProperty(id)) {
node = RED.nodes.node(id);
2016-12-20 20:42:38 +01:00
if (resolutions[id] === 'local') {
if (node) {
nodeChangedStates[id] = node.changed;
}
newConfig.push(localDiff.newConfig.all[id]);
} else if (resolutions[id] === 'remote') {
if (!remoteDiff.deleted[id] && remoteDiff.newConfig.all.hasOwnProperty(id)) {
if (node) {
nodeChangedStates[id] = node.changed;
2016-12-20 20:42:38 +01:00
}
localChangedStates[id] = true;
newConfig.push(remoteDiff.newConfig.all[id]);
2016-12-20 20:42:38 +01:00
}
} else {
console.log("Unresolved",id)
2016-12-20 20:42:38 +01:00
}
}
}
for (id in remoteDiff.added) {
if (remoteDiff.added.hasOwnProperty(id)) {
node = RED.nodes.node(id);
if (node) {
nodeChangedStates[id] = node.changed;
}
if (!localDiff.added.hasOwnProperty(id)) {
localChangedStates[id] = true;
newConfig.push(remoteDiff.newConfig.all[id]);
2016-12-20 20:42:38 +01:00
}
}
}
var historyEvent = {
t:"replace",
config: RED.nodes.createCompleteNodeSet(),
changed: nodeChangedStates,
dirty: RED.nodes.dirty(),
rev: RED.nodes.version()
}
2016-12-23 13:53:59 +01:00
RED.history.push(historyEvent);
RED.nodes.clear();
var imported = RED.nodes.import(newConfig);
imported[0].forEach(function(n) {
if (nodeChangedStates[n.id] || localChangedStates[n.id]) {
n.changed = true;
2016-12-20 20:42:38 +01:00
}
})
2016-12-20 20:42:38 +01:00
RED.nodes.version(remoteDiff.rev);
2016-12-20 20:42:38 +01:00
RED.view.redraw(true);
2016-12-20 22:13:39 +01:00
RED.palette.refresh();
RED.workspaces.refresh();
RED.sidebar.config.refresh();
2016-12-20 20:42:38 +01:00
}
2017-08-20 23:59:51 +02:00
function showTestFlowDiff(index) {
if (index === 1) {
var localFlow = RED.nodes.createCompleteNodeSet();
var originalFlow = RED.nodes.originalFlow();
showTextDiff(JSON.stringify(localFlow,null,4),JSON.stringify(originalFlow,null,4))
} else if (index === 2) {
var local = "1\n2\n3\n4\n5\nA\n6\n7\n8\n9\n";
var remote = "1\nA\n2\n3\nD\nE\n6\n7\n8\n9\n";
showTextDiff(local,remote);
} else if (index === 3) {
var local = "1\n2\n3\n4\n5\n6\n7\n8\n9\n10\n11\n12\n13\n14\n15\n16\n17\n18\n19\n20\n21\n22";
var remote = "1\nTWO\nTHREE\nEXTRA\n4\n5\n6\n7\n8\n9\n10\n11\n12\nTHIRTEEN\n14\n15\n16\n17\n18\n19\n20\n21\n22";
showTextDiff(local,remote);
}
}
function showTextDiff(textA,textB) {
var trayOptions = {
title: "Compare Changes", //TODO: nls
width: Infinity,
overlay: true,
buttons: [
{
text: RED._("common.label.done"),
click: function() {
RED.tray.close();
}
}
],
resize: function(dimensions) {
// trayWidth = dimensions.width;
},
open: function(tray) {
var trayBody = tray.find('.editor-tray-body');
var diffPanel = $('<div class="node-text-diff"></div>').appendTo(trayBody);
var codeTable = $("<table>").appendTo(diffPanel);
$('<colgroup><col width="50"><col width="50%"><col width="50"><col width="50%"></colgroup>').appendTo(codeTable);
var codeBody = $('<tbody>').appendTo(codeTable);
var diffSummary = diffText(textA||"",textB||"");
var aIndex = 0;
var bIndex = 0;
var diffLength = Math.max(diffSummary.a.length, diffSummary.b.length);
var diffLines = [];
var diffBlocks = [];
var currentBlock;
var blockLength = 0;
var blockType = 0;
for (var i=0;i<diffLength;i++) {
var diffLine = diffSummary[i];
var Adiff = (aIndex < diffSummary.a.length)?diffSummary.a[aIndex]:{type:2,line:""};
var Bdiff = (bIndex < diffSummary.b.length)?diffSummary.b[bIndex]:{type:2,line:""};
if (Adiff.type === 0 && Bdiff.type !== 0) {
Adiff = {type:2,line:""};
bIndex++;
} else if (Bdiff.type === 0 && Adiff.type !== 0) {
Bdiff = {type:2,line:""};
aIndex++;
} else {
aIndex++;
bIndex++;
}
diffLines.push({
a: Adiff,
b: Bdiff
});
if (currentBlock === undefined) {
currentBlock = {start:i,end:i};
blockLength = 0;
blockType = (Adiff.type === 0 && Bdiff.type === 0)?0:1;
} else {
if (Adiff.type === 0 && Bdiff.type === 0) {
// Unchanged line
if (blockType === 0) {
// still unchanged - extend the block
currentBlock.end = i;
blockLength++;
} else if (blockType === 1) {
// end of a change
currentBlock.end = i;
blockType = 2;
blockLength = 0;
} else if (blockType === 2) {
// post-change unchanged
currentBlock.end = i;
blockLength++;
if (blockLength === 8) {
currentBlock.end -= 5; // rollback the end
diffBlocks.push(currentBlock);
currentBlock = {start:i-5,end:i-5};
blockType = 0;
blockLength = 0;
}
}
} else {
// in a change
currentBlock.end = i;
blockLength++;
if (blockType === 0) {
if (currentBlock.end > 3) {
currentBlock.end -= 3;
currentBlock.empty = true;
diffBlocks.push(currentBlock);
currentBlock = {start:i-3,end:i-3};
}
blockType = 1;
} else if (blockType === 2) {
// we were in unchanged, but hit a change again
blockType = 1;
}
}
}
}
if (blockType === 0) {
currentBlock.empty = true;
}
currentBlock.end = diffLength;
diffBlocks.push(currentBlock);
console.table(diffBlocks);
var diffRow;
for (var b = 0; b<diffBlocks.length; b++) {
currentBlock = diffBlocks[b];
if (currentBlock.empty) {
diffRow = createExpandLine(currentBlock.start,currentBlock.end,diffLines).appendTo(codeBody);
} else {
for (var i=currentBlock.start;i<currentBlock.end;i++) {
var row = createDiffLine(diffLines[i]).appendTo(codeBody);
if (i === currentBlock.start) {
row.addClass("start-block");
} else if (i === currentBlock.end-1) {
row.addClass("end-block");
}
}
}
}
},
close: function() {
diffVisible = false;
},
show: function() {
}
}
RED.tray.show(trayOptions);
}
function createExpandLine(start,end,diffLines) {
diffRow = $('<tr class="node-text-diff-expand">');
var content = $('<td colspan="4"> <i class="fa fa-arrows-v"></i> </td>').appendTo(diffRow);
var label = $('<span></span>').appendTo(content);
if (end < diffLines.length-1) {
label.text("@@ -"+(diffLines[end-1].a.i+1)+" +"+(diffLines[end-1].b.i+1));
}
diffRow.click(function(evt) {
console.log(start,end,diffLines.length);
if (end - start > 20) {
var startPos = $(this).offset();
console.log(startPos);
if (start > 0) {
for (var i=start;i<start+10;i++) {
createDiffLine(diffLines[i]).addClass("unchanged").insertBefore($(this));
}
start += 10;
}
if (end < diffLines.length-1) {
for (var i=end-1;i>end-11;i--) {
createDiffLine(diffLines[i]).addClass("unchanged").insertAfter($(this));
}
end -= 10;
}
if (end < diffLines.length-1) {
label.text("@@ -"+(diffLines[end-1].a.i+1)+" +"+(diffLines[end-1].b.i+1));
}
var endPos = $(this).offset();
var delta = endPos.top - startPos.top;
$(".node-text-diff").scrollTop($(".node-text-diff").scrollTop() + delta);
} else {
for (var i=start;i<end;i++) {
createDiffLine(diffLines[i]).addClass("unchanged").insertBefore($(this));
}
$(this).remove();
}
});
return diffRow;
}
function createDiffLine(diffLine) {
var diffRow = $('<tr>');
var Adiff = diffLine.a;
var Bdiff = diffLine.b;
//console.log(diffLine);
var cellNo = $("<td>").text(Adiff.type === 2?"":Adiff.i).appendTo(diffRow);
var cellLine = $("<td>").text(Adiff.line).appendTo(diffRow);
if (Adiff.type === 2) {
cellNo.addClass('blank');
cellLine.addClass('blank');
} else if (Adiff.type === 1) {
cellNo.addClass('added');
cellLine.addClass('added');
} else if (Adiff.type === 4) {
cellNo.addClass('removed');
cellLine.addClass('removed');
}
cellNo = $("<td>").text(Bdiff.type === 2?"":Bdiff.i).appendTo(diffRow);
cellLine = $("<td>").text(Bdiff.line).appendTo(diffRow);
if (Bdiff.type === 2) {
cellNo.addClass('blank');
cellLine.addClass('blank');
} else if (Bdiff.type === 1) {
cellNo.addClass('added');
cellLine.addClass('added');
} else if (Bdiff.type === 4) {
cellNo.addClass('removed');
cellLine.addClass('removed');
}
return diffRow;
}
function diffText(string1, string2,ignoreWhitespace) {
var lines1 = string1.split(/\r?\n/);
var lines2 = string2.split(/\r?\n/);
var i = lines1.length;
var j = lines2.length;
var k;
var m;
var diffSummary = {a:[],b:[]};
var diffMap = [];
for (k = 0; k < i + 1; k++) {
diffMap[k] = [];
for (m = 0; m < j + 1; m++) {
diffMap[k][m] = 0;
}
}
var c = 0;
for (k = i - 1; k >= 0; k--) {
for (m = j - 1; m >=0; m--) {
c++;
if (compareLines(lines1[k],lines2[m],ignoreWhitespace) !== 1) {
diffMap[k][m] = diffMap[k+1][m+1]+1;
} else {
diffMap[k][m] = Math.max(diffMap[(k + 1)][m], diffMap[k][(m + 1)]);
}
}
}
//console.log(c);
k = 0;
m = 0;
while ((k < i) && (m < j)) {
var n = compareLines(lines1[k],lines2[m],ignoreWhitespace);
if (n !== 1) {
var d = 0;
if (n===0) {
d = 0;
} else if (n==2) {
d = 3;
}
diffSummary.a.push({i:k+1,j:m+1,line:lines1[k],type:d});
diffSummary.b.push({i:m+1,j:k+1,line:lines2[m],type:d});
k++;
m++;
} else if (diffMap[(k + 1)][m] >= diffMap[k][(m + 1)]) {
diffSummary.a.push({i:k+1,line:lines1[k],type:1});
k++;
} else {
diffSummary.b.push({i:m+1,line:lines2[m],type:4});
m++;
}
}
while ((k < i) || (m < j)) {
if (k == i) {
diffSummary.b.push({i:m+1,line:lines2[m],type:4});
m++;
} else if (m == j) {
diffSummary.a.push({i:k+1,line:lines1[k],type:1});
k++;
}
}
return diffSummary;
}
function compareLines(string1, string2, ignoreWhitespace) {
if (ignoreWhitespace) {
if (string1 === string2) {
return 0;
}
return string1.trim() === string2.trime() ? 2 : 1;
}
return string1 === string2 ? 0 : 1;
}
2016-12-07 14:51:20 +01:00
return {
2016-12-20 20:42:38 +01:00
init: init,
getRemoteDiff: getRemoteDiff,
showRemoteDiff: showRemoteDiff,
mergeDiff: mergeDiff
2016-12-07 14:51:20 +01:00
}
})();