",{class:"node-diff-node-entry-node"});
+ var colour = def.color;
+ var icon_url = "arrow-in.png";
+ if (node.type === 'tab') {
+ colour = "#C0DEED";
+ icon_url = "subflow.png";
+ } else if (def.category === 'config') {
+ icon_url = "cog.png";
+ } else if (node.type === 'unknown') {
+ icon_url = "alert.png";
+ } else {
+ icon_url = def.icon;
+ }
+ nodeDiv.css('backgroundColor',colour);
+
+ var iconContainer = $('
',{class:"palette_icon_container"}).appendTo(nodeDiv);
+ $('
',{class:"palette_icon",style:"background-image: url(icons/"+icon_url+")"}).appendTo(iconContainer);
+
+ return nodeDiv;
+ }
+ function createNodeDiffRow(node,stats,localDiff) {
+ var realNode = RED.nodes.node(node.id);
+ var hasChanges = false;
+ if (localDiff.added[node.id]) {
+ stats.addedCount++;
+ }
+ if (localDiff.deleted[node.id]) {
+ stats.deletedCount++;
+ }
+ if (localDiff.changed[node.id]) {
+ stats.changedCount++;
+ hasChanges = true;
+ }
+
+ var def = RED.nodes.getType(node.type)||{};
+ var div = $("
",{class:"node-diff-node-entry collapsed"});
+ var nodeTitleDiv = $("
",{class:"node-diff-node-entry-title"}).appendTo(div);
+ var status = $('
').appendTo(nodeTitleDiv);
+ var nodeLabel = node.label || node.name || node.id;
+
+ if (hasChanges) {
+ nodeTitleDiv.addClass("node-diff-node-changed");
+ $('
').appendTo(status);
+ var newNode = localDiff.newConfig.all[node.id];
+ if (newNode) {
+ nodeLabel = newNode.label || newNode.name || newNode.id;
+ nodeTitleDiv.click(function(evt) {
+ evt.preventDefault();
+ $(this).parent().toggleClass('collapsed');
+ })
+ createNodePropertiesTable(node,newNode,def).appendTo(div);
+ $('
').appendTo(nodeTitleDiv);
+ }
+ } else if (localDiff.deleted[node.id]){
+ $('
').appendTo(nodeTitleDiv);
+ nodeTitleDiv.addClass("node-diff-node-deleted");
+ $('').appendTo(status);
+ } else if (localDiff.added[node.id]) {
+ $('').appendTo(nodeTitleDiv);
+ nodeTitleDiv.addClass("node-diff-node-added")
+ $('').appendTo(status);
+ } else {
+ $('').appendTo(nodeTitleDiv);
+ nodeTitleDiv.addClass("node-diff-node-unchanged");
+ div.addClass("hide");
+ }
+
+ createNodeIcon(node,def).appendTo(nodeTitleDiv);
+
+ var contentDiv = $('',{class:"node-diff-node-description"}).appendTo(nodeTitleDiv);
+
+ $('
',{class:"node-diff-node-label"}).html(nodeLabel).appendTo(contentDiv);
+ $('',{class:"node-diff-node-meta"}).html(node.id).appendTo(nodeTitleDiv);
+
+ //$('',{class:"red-ui-search-result-node-type"}).html(node.type).appendTo(contentDiv);
+ //$('
',{class:"red-ui-search-result-node-id"}).html(node.id).appendTo(contentDiv);
+
+ return div;
+ }
+ function createNodePropertiesTable(node,newNode,def) {
+ var nodePropertiesDiv = $("
",{class:"node-diff-node-entry-properties"});
+
+ var nodePropertiesTable = $("
").appendTo(nodePropertiesDiv);
+ var row;
+ if (node.hasOwnProperty('x')) {
+ if (newNode.x !== node.x || newNode.y !== node.y) {
+ var currentPosition = RED.utils.createObjectElement({x:node.x,y:node.y});
+ var newPosition = RED.utils.createObjectElement({x:newNode.x,y:newNode.y});
+ row = $("position | | |
").appendTo(nodePropertiesTable);
+ currentPosition.appendTo(row.children()[1]);
+ newPosition.appendTo(row.children()[2]);
+
+ }
+ }
+ if (node.hasOwnProperty('wires')) {
+ var localValue = JSON.stringify(node.wires);
+ var remoteValue = JSON.stringify(newNode.wires);
+ if (localValue !== remoteValue) {
+ row = $("wires | | |
").appendTo(nodePropertiesTable);
+ formatWireProperty(node.wires).appendTo(row.children()[1]);
+ formatWireProperty(newNode.wires).appendTo(row.children()[2]);
+ }
+
+ }
+ var properties = Object.keys(node).filter(function(p) { return p!='z'&&p!='wires'&&p!=='x'&&p!=='y'&&p!=='id'&&p!=='type'&&(!def.defaults||!def.defaults.hasOwnProperty(p))});
+ if (def.defaults) {
+ properties = properties.concat(Object.keys(def.defaults));
+ }
+ properties.forEach(function(d) {
+ var localValue = JSON.stringify(node[d]);
+ var remoteValue = JSON.stringify(newNode[d]);
+
+ if (remoteValue !== localValue) {
+ var formattedProperty = RED.utils.createObjectElement(node[d]);
+ var newFormattedProperty = RED.utils.createObjectElement(newNode[d]);
+ var row = $(""+d+' | | |
').appendTo(nodePropertiesTable);
+ formattedProperty.appendTo(row.children()[1]);
+ newFormattedProperty.appendTo(row.children()[2]);
+ }
+ })
+ return nodePropertiesDiv;
+ }
+
+
+
+ function showlocalDiff() {
+ var nns = RED.nodes.createCompleteNodeSet();
+ var originalFlow = RED.nodes.originalFlow();
+ var diff = generateDiff(originalFlow,nns);
+ showDiff(diff);
+ }
+
+
+ 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 pending = RED.nodes.pending();
+ var added = {};
+ var deleted = {};
+ var changed = {};
+ var conflicted = {};
+
+ 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)) {
+ if (!pending.added.hasOwnProperty(id)) {
+ deleted[id] = true;
+ conflicted[id] = node&&node.changed;
+ }
+ } else if (JSON.stringify(currentConfig.all[id]) !== JSON.stringify(newConfig.all[id])) {
+ changed[id] = true;
+ conflicted[id] = node.changed;
+ }
+ });
+ Object.keys(newConfig.all).forEach(function(id) {
+ if (!currentConfig.all.hasOwnProperty(id) && !pending.deleted.hasOwnProperty(id)) {
+ added[id] = true;
+ }
+ });
+
+ // console.log("Added",added);
+ // console.log("Deleted",deleted);
+ // console.log("Changed",changed);
+ // console.log("Conflicted",conflicted);
+ //
+ // var formatString = function(id) {
+ // return conflicted[id]?"!":(added[id]?"+":(deleted[id]?"-":(changed[id]?"~":" ")));
+ // }
+ // newConfig.tabOrder.forEach(function(tabId) {
+ // var tab = newConfig.tabs[tabId];
+ // console.log(formatString(tabId),"Flow:",tab.n.label, "("+tab.n.id+")");
+ // tab.nodes.forEach(function(node) {
+ // console.log(" ",formatString(node.id),node.type,node.name || node.id);
+ // })
+ // if (currentConfig.tabs[tabId]) {
+ // currentConfig.tabs[tabId].nodes.forEach(function(node) {
+ // if (deleted[node.id]) {
+ // console.log(" ",formatString(node.id),node.type,node.name || node.id);
+ // }
+ // })
+ // }
+ // });
+ // currentConfig.tabOrder.forEach(function(tabId) {
+ // if (deleted[tabId]) {
+ // var tab = currentConfig.tabs[tabId];
+ // console.log(formatString(tabId),"Flow:",tab.n.label, "("+tab.n.id+")");
+ // }
+ // });
+
+ return {
+ currentConfig: currentConfig,
+ newConfig: newConfig,
+ added: added,
+ deleted: deleted,
+ changed: changed,
+ conflicted: conflicted
+ }
+ }
+
+ function formatNodeProperty(prop) {
+ var formattedProperty = prop;
+ if (formattedProperty === null) {
+ formattedProperty = 'null';
+ } else if (formattedProperty === undefined) {
+ formattedProperty = 'undefined';
+ } else if (typeof formattedProperty === 'object') {
+ formattedProperty = JSON.stringify(formattedProperty);
+ }
+ if (/\n/.test(formattedProperty)) {
+ formattedProperty = ""+formattedProperty+"
"
+ }
+ return formattedProperty;
+ }
+
+ function showDiff(localDiff) {
+ var el;
+ var list = $("#node-dialog-view-diff-diff");
+ list.editableList('empty');
+
+ var currentConfig = localDiff.currentConfig;
+ var newConfig = localDiff.newConfig;
+
+ list.editableList('addItem',{
+ diff: localDiff,
+ def: {
+ category: 'config',
+ color: '#f0f0f0'
+ },
+ tab: {
+ n: {},
+ nodes: currentConfig.globals
+ },
+ newTab: {
+ n: {},
+ nodes: newConfig.globals
+ }
+ });
+
+ var seenTabs = {};
+
+ currentConfig.tabOrder.forEach(function(tabId) {
+ var tab = currentConfig.tabs[tabId];
+ var el = {
+ diff: localDiff,
+ def: {},
+ tab:tab
+ };
+ if (newConfig.tabs.hasOwnProperty(tabId)) {
+ el.newTab = newConfig.tabs[tabId];
+ }
+ seenTabs[tabId] = true;
+ list.editableList('addItem',el)
+ });
+ newConfig.tabOrder.forEach(function(tabId) {
+ if (!seenTabs[tabId]) {
+ var tab = newConfig.tabs[tabId];
+ var el = {
+ diff: localDiff,
+ def: {},
+ tab:tab
+ };
+ list.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];
+ }
+ list.editableList('addItem',el)
+ }
+ }
+ for (subflowId in newConfig.subflows) {
+ if (newConfig.subflows.hasOwnProperty(subflowId) && !seenTabs[subflowId]) {
+ el = {
+ diff: localDiff,
+ def: {
+ defaults:{},
+ icon:"subflow.png",
+ category: "subflows",
+ color: "#da9"
+ },
+ tab:newConfig.subflows[subflowId]
+ }
+ list.editableList('addItem',el)
+ }
+ }
+
+ $("#node-diff-filter-changed").addClass("selected");
+ $("#node-diff-filter-all").removeClass("selected");
+
+ $("#node-dialog-view-diff").dialog("open");
+ }
+
+
+ return {
+ init: init
+ }
+})();