RED.diff = (function() {
var currentDiff = {};
var diffVisible = false;
var diffList;
function init() {
// RED.actions.add("core:show-current-diff",showLocalDiff);
RED.actions.add("core:show-remote-diff",showRemoteDiff);
// RED.keyboard.add("*","ctrl-shift-l","core:show-current-diff");
RED.keyboard.add("*","ctrl-shift-r","core:show-remote-diff");
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 createDiffTable(container) {
var diffList = $('
').appendTo(container);
diffList.editableList({
addButton: false,
scrollOnAdd: false,
addItem: function(container,i,object) {
var localDiff = object.diff;
var remoteDiff = object.remoteDiff;
var tab = object.tab.n;
var def = object.def;
var conflicts = currentDiff.conflicts;
var tabDiv = $('
',{class:"node-diff-tab"}).appendTo(container);
tabDiv.addClass('collapsed');
var titleRow = $('
',{class:"node-diff-tab-title"}).appendTo(tabDiv);
var nodesDiv = $('
').appendTo(tabDiv);
var originalCell = $('
',{class:"node-diff-node-entry-cell"}).appendTo(titleRow);
var localCell = $('
',{class:"node-diff-node-entry-cell node-diff-node-local"}).appendTo(titleRow);
var remoteCell;
var selectState;
if (remoteDiff) {
remoteCell = $('
',{class:"node-diff-node-entry-cell node-diff-node-remote"}).appendTo(titleRow);
}
$('').appendTo(originalCell);
createNodeIcon(tab,def).appendTo(originalCell);
var tabForLabel = (object.newTab || object.tab).n;
var titleSpan = $('',{class:"node-diff-tab-title-meta"}).appendTo(originalCell);
if (tabForLabel.type === 'tab') {
titleSpan.html(tabForLabel.label||tabForLabel.id);
} else if (tab.type === 'subflow') {
titleSpan.html((tabForLabel.name||tabForLabel.id));
} else {
titleSpan.html(RED._("diff.globalNodes"));
}
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 = $("
",{class:"node-diff-node-entry node-diff-node-props collapsed"}).appendTo(nodesDiv);
var row = $("
",{class:"node-diff-node-entry-header"}).appendTo(div);
var originalNodeDiv = $("
",{class:"node-diff-node-entry-cell"}).appendTo(row);
var localNodeDiv = $("
",{class:"node-diff-node-entry-cell node-diff-node-local"}).appendTo(row);
var localChanged = false;
var remoteChanged = false;
if (!localDiff.newConfig.all[tab.id]) {
localNodeDiv.addClass("node-diff-empty");
} else if (localDiff.added[tab.id]) {
localNodeDiv.addClass("node-diff-node-added");
localChanged = true;
$('').appendTo(localNodeDiv);
} else if (localDiff.changed[tab.id]) {
localNodeDiv.addClass("node-diff-node-changed");
localChanged = true;
$('').appendTo(localNodeDiv);
} else {
localNodeDiv.addClass("node-diff-node-unchanged");
$('').appendTo(localNodeDiv);
}
var remoteNodeDiv;
if (remoteDiff) {
remoteNodeDiv = $("
",{class:"node-diff-node-entry-cell node-diff-node-remote"}).appendTo(row);
if (!remoteDiff.newConfig.all[tab.id]) {
remoteNodeDiv.addClass("node-diff-empty");
if (remoteDiff.deleted[tab.id]) {
remoteChanged = true;
}
} else if (remoteDiff.added[tab.id]) {
remoteNodeDiv.addClass("node-diff-node-added");
remoteChanged = true;
$('').appendTo(remoteNodeDiv);
} else if (remoteDiff.changed[tab.id]) {
remoteNodeDiv.addClass("node-diff-node-changed");
remoteChanged = true;
$('').appendTo(remoteNodeDiv);
} else {
remoteNodeDiv.addClass("node-diff-node-unchanged");
$('').appendTo(remoteNodeDiv);
}
}
$('').appendTo(originalNodeDiv);
$('').html(RED._("diff.flowProperties")).appendTo(originalNodeDiv);
row.click(function(evt) {
evt.preventDefault();
$(this).parent().toggleClass('collapsed');
});
createNodePropertiesTable(def,tab,localTabNode,remoteTabNode,conflicts).appendTo(div);
selectState = "";
if (conflicts[tab.id]) {
flowStats.conflicts++;
if (!localNodeDiv.hasClass("node-diff-empty")) {
$('').prependTo(localNodeDiv);
}
if (!remoteNodeDiv.hasClass("node-diff-empty")) {
$('').prependTo(remoteNodeDiv);
}
div.addClass("node-diff-node-entry-conflict");
} else {
selectState = currentDiff.resolutions[tab.id];
}
// Tab properties row
createNodeConflictRadioBoxes(tab,div,localNodeDiv,remoteNodeDiv,true,!conflicts[tab.id],selectState);
}
}
// var stats = $('',{class:"node-diff-tab-stats"}).appendTo(titleRow);
var localNodeCount = 0;
var remoteNodeCount = 0;
var seen = {};
object.tab.nodes.forEach(function(node) {
seen[node.id] = true;
createNodeDiffRow(node,flowStats).appendTo(nodesDiv)
});
if (object.newTab) {
localNodeCount = object.newTab.nodes.length;
object.newTab.nodes.forEach(function(node) {
if (!seen[node.id]) {
seen[node.id] = true;
createNodeDiffRow(node,flowStats).appendTo(nodesDiv)
}
});
}
if (object.remoteTab) {
remoteNodeCount = object.remoteTab.nodes.length;
object.remoteTab.nodes.forEach(function(node) {
if (!seen[node.id]) {
createNodeDiffRow(node,flowStats).appendTo(nodesDiv)
}
});
}
titleRow.click(function(evt) {
// 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');
}
// }
})
if (localDiff.deleted[tab.id]) {
$('').appendTo(localCell);
} else if (object.newTab) {
if (localDiff.added[tab.id]) {
$('').appendTo(localCell);
} else {
if (tab.id) {
if (localDiff.changed[tab.id]) {
flowStats.local.changedCount++;
} else {
flowStats.local.unchangedCount++;
}
}
var localStats = $('',{class:"node-diff-tab-stats"}).appendTo(localCell);
$('').html(RED._('diff.nodeCount',{count:localNodeCount})).appendTo(localStats);
if (flowStats.conflicts + flowStats.local.addedCount + flowStats.local.changedCount + flowStats.local.deletedCount > 0) {
$(' [ ').appendTo(localStats);
if (flowStats.conflicts > 0) {
$(' '+flowStats.conflicts+'').appendTo(localStats);
}
if (flowStats.local.addedCount > 0) {
$(' '+flowStats.local.addedCount+'').appendTo(localStats);
}
if (flowStats.local.changedCount > 0) {
$(' '+flowStats.local.changedCount+'').appendTo(localStats);
}
if (flowStats.local.deletedCount > 0) {
$(' '+flowStats.local.deletedCount+'').appendTo(localStats);
}
$(' ] ').appendTo(localStats);
}
}
} else {
localCell.addClass("node-diff-empty");
}
if (remoteDiff) {
if (remoteDiff.deleted[tab.id]) {
$('').appendTo(remoteCell);
} else if (object.remoteTab) {
if (remoteDiff.added[tab.id]) {
$('').appendTo(remoteCell);
} else {
if (tab.id) {
if (remoteDiff.changed[tab.id]) {
flowStats.remote.changedCount++;
} else {
flowStats.remote.unchangedCount++;
}
}
var remoteStats = $('',{class:"node-diff-tab-stats"}).appendTo(remoteCell);
$('').html(RED._('diff.nodeCount',{count:remoteNodeCount})).appendTo(remoteStats);
if (flowStats.conflicts + flowStats.remote.addedCount + flowStats.remote.changedCount + flowStats.remote.deletedCount > 0) {
$(' [ ').appendTo(remoteStats);
if (flowStats.conflicts > 0) {
$(' '+flowStats.conflicts+'').appendTo(remoteStats);
}
if (flowStats.remote.addedCount > 0) {
$(' '+flowStats.remote.addedCount+'').appendTo(remoteStats);
}
if (flowStats.remote.changedCount > 0) {
$(' '+flowStats.remote.changedCount+'').appendTo(remoteStats);
}
if (flowStats.remote.deletedCount > 0) {
$(' '+flowStats.remote.deletedCount+'').appendTo(remoteStats);
}
$(' ] ').appendTo(remoteStats);
}
}
} else {
remoteCell.addClass("node-diff-empty");
}
selectState = "";
if (flowStats.conflicts > 0) {
titleRow.addClass("node-diff-node-entry-conflict");
} else {
selectState = currentDiff.resolutions[tab.id];
}
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);
}
}
if (tabDiv.find(".node-diff-node-entry").length === 0) {
tabDiv.addClass("node-diff-tab-empty");
}
container.i18n();
}
});
return diffList;
}
function buildDiffPanel(container,diff,options) {
var diffPanel = $('').appendTo(container);
var diffHeaders = $('').appendTo(diffPanel);
if (options.mode === "merge") {
diffPanel.addClass("node-dialog-view-diff-panel-merge");
var toolbar = $('
'+
' '+
'
').prependTo(diffPanel);
}
var diffList = createDiffTable(diffPanel);
var localDiff = diff.localDiff;
var remoteDiff = diff.remoteDiff;
var conflicts = diff.conflicts;
var currentConfig = localDiff.currentConfig;
var newConfig = localDiff.newConfig;
if (remoteDiff !== undefined) {
diffPanel.addClass('node-diff-three-way');
var localTitle = options.oldRevTitle || RED._('diff.local');
var remoteTitle = options.newRevTitle || RED._('diff.remote');
$('').text(localTitle).appendTo(diffHeaders);
$('').text(remoteTitle).appendTo(diffHeaders);
} else {
diffPanel.removeClass('node-diff-three-way');
}
return {
list: diffList,
finish: function() {
var el = {
diff: localDiff,
def: {
category: 'config',
color: '#f0f0f0'
},
tab: {
n: {},
nodes: currentConfig.globals
},
newTab: {
n: {},
nodes: newConfig.globals
}
};
if (remoteDiff !== undefined) {
el.remoteTab = {
n:{},
nodes:remoteDiff.newConfig.globals
};
el.remoteDiff = remoteDiff;
}
diffList.editableList('addItem',el);
var seenTabs = {};
currentConfig.tabOrder.forEach(function(tabId) {
var tab = currentConfig.tabs[tabId];
var el = {
diff: localDiff,
def: RED.nodes.getType('tab'),
tab:tab
};
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)
}
});
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)
}
});
}
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)
}
}
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)
}
}
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)
}
}
}
}
};
}
function formatWireProperty(wires,allNodes) {
var result = $("
",{class:"node-diff-property-wires"})
var list = $("");
var c = 0;
wires.forEach(function(p,i) {
var port = $("
").appendTo(list);
if (p && p.length > 0) {
$("").html(i+1).appendTo(port);
var links = $("
").appendTo(port);
p.forEach(function(d) {
c++;
var entry = $("
").appendTo(links);
var node = allNodes[d];
if (node) {
var def = RED.nodes.getType(node.type)||{};
createNode(node,def).appendTo(entry);
} else {
entry.html(d);
}
})
} else {
port.html('none');
}
})
if (c === 0) {
result.html("none");
} else {
list.appendTo(result);
}
return result;
}
function createNodeIcon(node,def) {
var nodeDiv = $("
",{class:"node-diff-node-entry-node"});
var colour = def.color;
var icon_url = RED.utils.getNodeIcon(def,node);
if (node.type === 'tab') {
colour = "#C0DEED";
}
nodeDiv.css('backgroundColor',colour);
var iconContainer = $('',{class:"palette_icon_container"}).appendTo(nodeDiv);
$('',{class:"palette_icon",style:"background-image: url("+icon_url+")"}).appendTo(iconContainer);
return nodeDiv;
}
function createNode(node,def) {
var nodeTitleDiv = $("
",{class:"node-diff-node-entry-title"})
createNodeIcon(node,def).appendTo(nodeTitleDiv);
var contentDiv = $('
',{class:"node-diff-node-description"}).appendTo(nodeTitleDiv);
var nodeLabel = node.label || node.name || node.id;
$('',{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];
var hasChanges = false; // exists in original and local/remote but with changes
var unChanged = true; // existing in original,local,remote unchanged
var localChanged = false;
if (localDiff.added[node.id]) {
stats.local.addedCount++;
unChanged = false;
}
if (remoteDiff && remoteDiff.added[node.id]) {
stats.remote.addedCount++;
unChanged = false;
}
if (localDiff.deleted[node.id]) {
stats.local.deletedCount++;
unChanged = false;
}
if (remoteDiff && remoteDiff.deleted[node.id]) {
stats.remote.deletedCount++;
unChanged = false;
}
if (localDiff.changed[node.id]) {
stats.local.changedCount++;
hasChanges = true;
unChanged = false;
}
if (remoteDiff && remoteDiff.changed[node.id]) {
stats.remote.changedCount++;
hasChanges = true;
unChanged = false;
}
// 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])
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 = {};
}
}
var div = $("
",{class:"node-diff-node-entry collapsed"});
var row = $("
",{class:"node-diff-node-entry-header"}).appendTo(div);
var originalNodeDiv = $("
",{class:"node-diff-node-entry-cell"}).appendTo(row);
var localNodeDiv = $("
",{class:"node-diff-node-entry-cell node-diff-node-local"}).appendTo(row);
var remoteNodeDiv;
var chevron;
if (remoteDiff) {
remoteNodeDiv = $("
",{class:"node-diff-node-entry-cell node-diff-node-remote"}).appendTo(row);
}
$('').appendTo(originalNodeDiv);
if (unChanged) {
stats.local.unchangedCount++;
createNode(node,def).appendTo(originalNodeDiv);
localNodeDiv.addClass("node-diff-node-unchanged");
$('').appendTo(localNodeDiv);
if (remoteDiff) {
stats.remote.unchangedCount++;
remoteNodeDiv.addClass("node-diff-node-unchanged");
$('').appendTo(remoteNodeDiv);
}
div.addClass("node-diff-node-unchanged");
} else if (localDiff.added[node.id]) {
localNodeDiv.addClass("node-diff-node-added");
if (remoteNodeDiv) {
remoteNodeDiv.addClass("node-diff-empty");
}
$('').appendTo(localNodeDiv);
createNode(node,def).appendTo(originalNodeDiv);
} else if (remoteDiff && remoteDiff.added[node.id]) {
localNodeDiv.addClass("node-diff-empty");
remoteNodeDiv.addClass("node-diff-node-added");
$('').appendTo(remoteNodeDiv);
createNode(node,def).appendTo(originalNodeDiv);
} else {
createNode(node,def).appendTo(originalNodeDiv);
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) {
localMovedMessage = RED._("diff.type.movedFrom",{id:(localDiff.currentConfig.all[node.id].z||'global')});
} else {
localMovedMessage = RED._("diff.type.movedTo",{id:(localN.z||'global')});
}
$(' '+localMovedMessage+'').appendTo(localNodeDiv);
}
localChanged = true;
} else if (localDiff.deleted[node.z]) {
localNodeDiv.addClass("node-diff-empty");
localChanged = true;
} else if (localDiff.deleted[node.id]) {
localNodeDiv.addClass("node-diff-node-deleted");
$('').appendTo(localNodeDiv);
localChanged = true;
} else if (localDiff.changed[node.id]) {
if (localDiff.newConfig.all[node.id].z !== node.z) {
localNodeDiv.addClass("node-diff-empty");
} else {
localNodeDiv.addClass("node-diff-node-changed");
$('').appendTo(localNodeDiv);
localChanged = true;
}
} else {
if (localDiff.newConfig.all[node.id].z !== node.z) {
localNodeDiv.addClass("node-diff-empty");
} else {
stats.local.unchangedCount++;
localNodeDiv.addClass("node-diff-node-unchanged");
$('').appendTo(localNodeDiv);
}
}
if (remoteDiff) {
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) {
remoteMovedMessage = RED._("diff.type.movedFrom",{id:(remoteDiff.currentConfig.all[node.id].z||'global')});
} else {
remoteMovedMessage = RED._("diff.type.movedTo",{id:(remoteN.z||'global')});
}
$(' '+remoteMovedMessage+'').appendTo(remoteNodeDiv);
}
} else if (remoteDiff.deleted[node.z]) {
remoteNodeDiv.addClass("node-diff-empty");
} else if (remoteDiff.deleted[node.id]) {
remoteNodeDiv.addClass("node-diff-node-deleted");
$('').appendTo(remoteNodeDiv);
} else if (remoteDiff.changed[node.id]) {
if (remoteDiff.newConfig.all[node.id].z !== node.z) {
remoteNodeDiv.addClass("node-diff-empty");
} else {
remoteNodeDiv.addClass("node-diff-node-changed");
$('').appendTo(remoteNodeDiv);
}
} else {
if (remoteDiff.newConfig.all[node.id].z !== node.z) {
remoteNodeDiv.addClass("node-diff-empty");
} else {
stats.remote.unchangedCount++;
remoteNodeDiv.addClass("node-diff-node-unchanged");
$('').appendTo(remoteNodeDiv);
}
}
}
}
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
}
}
createNodePropertiesTable(def,node,localNode,remoteNode).appendTo(div);
var selectState = "";
if (conflicted) {
stats.conflicts++;
if (!localNodeDiv.hasClass("node-diff-empty")) {
$('').prependTo(localNodeDiv);
}
if (!remoteNodeDiv.hasClass("node-diff-empty")) {
$('').prependTo(remoteNodeDiv);
}
div.addClass("node-diff-node-entry-conflict");
} else {
selectState = currentDiff.resolutions[node.id];
}
// Node row
createNodeConflictRadioBoxes(node,div,localNodeDiv,remoteNodeDiv,false,!conflicted,selectState);
row.click(function(evt) {
$(this).parent().toggleClass('collapsed');
});
return div;
}
function createNodePropertiesTable(def,node,localNodeObj,remoteNodeObj) {
var propertyElements = {};
var localNode = localNodeObj.node;
var remoteNode;
if (remoteNodeObj) {
remoteNode = remoteNodeObj.node;
}
var nodePropertiesDiv = $("
",{class:"node-diff-node-entry-properties"});
var nodePropertiesTable = $("
").appendTo(nodePropertiesDiv);
var nodePropertiesTableCols = $('
').appendTo(nodePropertiesTable);
if (remoteNode !== undefined) {
$("
").appendTo(nodePropertiesTableCols);
}
var nodePropertiesTableBody = $("").appendTo(nodePropertiesTable);
var row;
var localCell, remoteCell;
var element;
var currentValue, localValue, remoteValue;
var localChanged = false;
var remoteChanged = false;
var localChanges = 0;
var remoteChanges = 0;
var conflict = false;
var status;
row = $("