2020-04-27 12:17:19 +02:00
|
|
|
RED.sidebar.info.outliner = (function() {
|
|
|
|
|
|
|
|
var treeList;
|
2020-04-27 16:23:39 +02:00
|
|
|
var searchInput;
|
2020-05-01 18:39:54 +02:00
|
|
|
var projectInfo;
|
2020-04-27 12:17:19 +02:00
|
|
|
var flowList;
|
|
|
|
var subflowList;
|
|
|
|
var globalConfigNodes;
|
|
|
|
|
|
|
|
var objects = {};
|
|
|
|
|
|
|
|
var objectBacklog = {};
|
|
|
|
|
2020-05-01 18:39:54 +02:00
|
|
|
function getFlowData() {
|
2020-04-27 12:17:19 +02:00
|
|
|
var flowData = [
|
|
|
|
{
|
2020-05-06 17:15:12 +02:00
|
|
|
label: RED._("menu.label.flows"),
|
2020-04-27 12:17:19 +02:00
|
|
|
expanded: true,
|
2020-05-01 18:39:54 +02:00
|
|
|
children: []
|
2020-04-27 12:17:19 +02:00
|
|
|
},
|
|
|
|
{
|
2020-05-06 17:15:12 +02:00
|
|
|
label: RED._("menu.label.subflows"),
|
2020-04-27 12:17:19 +02:00
|
|
|
children: []
|
2020-05-01 18:39:54 +02:00
|
|
|
},
|
|
|
|
{
|
|
|
|
id: "__global__",
|
2020-05-06 17:15:12 +02:00
|
|
|
label: RED._("sidebar.info.globalConfig"),
|
2020-05-01 18:39:54 +02:00
|
|
|
children: []
|
2020-04-27 12:17:19 +02:00
|
|
|
}
|
|
|
|
]
|
|
|
|
flowList = flowData[0];
|
|
|
|
subflowList = flowData[1];
|
2020-05-01 18:39:54 +02:00
|
|
|
globalConfigNodes = flowData[2];
|
|
|
|
|
2020-04-27 12:17:19 +02:00
|
|
|
return flowData;
|
|
|
|
}
|
|
|
|
|
|
|
|
function getProjectLabel(p) {
|
|
|
|
var div = $('<div>',{class:"red-ui-info-outline-item red-ui-info-outline-item-flow"});
|
2020-05-01 18:39:54 +02:00
|
|
|
div.css("width", "calc(100% - 40px)");
|
2020-04-27 12:17:19 +02:00
|
|
|
var contentDiv = $('<div>',{class:"red-ui-search-result-description red-ui-info-outline-item-label"}).appendTo(div);
|
|
|
|
contentDiv.text(p.name);
|
|
|
|
var controls = $('<div>',{class:"red-ui-info-outline-item-controls"}).appendTo(div);
|
2020-05-01 18:39:54 +02:00
|
|
|
var editProjectButton = $('<button class="red-ui-button red-ui-button-small" style="position:absolute;right:5px;top: 3px;"><i class="fa fa-ellipsis-h"></i></button>')
|
2020-04-27 12:17:19 +02:00
|
|
|
.appendTo(controls)
|
|
|
|
.on("click", function(evt) {
|
|
|
|
evt.preventDefault();
|
|
|
|
RED.projects.editProject();
|
|
|
|
});
|
|
|
|
RED.popover.tooltip(editProjectButton,RED._('sidebar.project.showProjectSettings'));
|
|
|
|
return div;
|
|
|
|
}
|
|
|
|
|
|
|
|
var empties = {};
|
|
|
|
function getEmptyItem(id) {
|
|
|
|
var item = {
|
|
|
|
empty: true,
|
|
|
|
element: $('<div class="red-ui-info-outline-item red-ui-info-outline-item-empty">').text("empty")
|
|
|
|
}
|
|
|
|
empties[id] = item;
|
|
|
|
return item;
|
|
|
|
}
|
|
|
|
|
|
|
|
function getNodeLabelText(n) {
|
|
|
|
var label = n.name || n.id;
|
|
|
|
if (n._def.label) {
|
|
|
|
try {
|
|
|
|
label = (typeof n._def.label === "function" ? n._def.label.call(n) : n._def.label)||"";
|
|
|
|
} catch(err) {
|
|
|
|
console.log("Definition error: "+type+".label",err);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return label;
|
|
|
|
}
|
|
|
|
|
|
|
|
function getNodeLabel(n) {
|
|
|
|
var div = $('<div>',{class:"red-ui-info-outline-item"});
|
2020-05-01 18:39:54 +02:00
|
|
|
RED.utils.createNodeIcon(n).appendTo(div);
|
2020-04-27 12:17:19 +02:00
|
|
|
var contentDiv = $('<div>',{class:"red-ui-search-result-description"}).appendTo(div);
|
|
|
|
var labelText = getNodeLabelText(n);
|
|
|
|
var label = $('<div>',{class:"red-ui-search-result-node-label red-ui-info-outline-item-label"}).appendTo(contentDiv);
|
|
|
|
if (labelText) {
|
|
|
|
label.text(labelText)
|
|
|
|
} else {
|
|
|
|
label.html(" ")
|
|
|
|
}
|
|
|
|
|
|
|
|
addControls(n, div);
|
|
|
|
|
|
|
|
return div;
|
|
|
|
}
|
|
|
|
|
|
|
|
function getFlowLabel(n) {
|
|
|
|
var div = $('<div>',{class:"red-ui-info-outline-item red-ui-info-outline-item-flow"});
|
|
|
|
var contentDiv = $('<div>',{class:"red-ui-search-result-description red-ui-info-outline-item-label"}).appendTo(div);
|
|
|
|
contentDiv.text(typeof n === "string"? n : n.label);
|
|
|
|
addControls(n, div);
|
|
|
|
return div;
|
|
|
|
}
|
|
|
|
|
|
|
|
function getSubflowLabel(n) {
|
|
|
|
|
|
|
|
var div = $('<div>',{class:"red-ui-info-outline-item"});
|
2020-05-01 18:39:54 +02:00
|
|
|
RED.utils.createNodeIcon(n).appendTo(div);
|
2020-04-27 12:17:19 +02:00
|
|
|
var contentDiv = $('<div>',{class:"red-ui-search-result-description"}).appendTo(div);
|
|
|
|
var labelText = getNodeLabelText(n);
|
|
|
|
var label = $('<div>',{class:"red-ui-search-result-node-label red-ui-info-outline-item-label"}).appendTo(contentDiv);
|
|
|
|
if (labelText) {
|
|
|
|
label.text(labelText)
|
|
|
|
} else {
|
|
|
|
label.html(" ")
|
|
|
|
}
|
|
|
|
|
|
|
|
addControls(n, div);
|
|
|
|
|
|
|
|
return div;
|
|
|
|
|
|
|
|
|
|
|
|
// var div = $('<div>',{class:"red-ui-info-outline-item red-ui-info-outline-item-flow"});
|
|
|
|
// var contentDiv = $('<div>',{class:"red-ui-search-result-description red-ui-info-outline-item-label"}).appendTo(div);
|
|
|
|
// contentDiv.text(n.name || n.id);
|
|
|
|
// addControls(n, div);
|
|
|
|
// return div;
|
|
|
|
}
|
|
|
|
|
|
|
|
function addControls(n,div) {
|
|
|
|
if (n.type === 'group') {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
var controls = $('<div>',{class:"red-ui-info-outline-item-controls red-ui-info-outline-item-hover-controls"}).appendTo(div);
|
|
|
|
if (n._def.button) {
|
|
|
|
$('<button type="button" class="red-ui-info-outline-item-control-action red-ui-button red-ui-button-small"><i class="fa fa-toggle-right"></i></button>').appendTo(controls).on("click",function(evt) {
|
|
|
|
evt.preventDefault();
|
|
|
|
evt.stopPropagation();
|
|
|
|
RED.view.clickNodeButton(n);
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if (n.type !== 'group') {
|
|
|
|
$('<button type="button" class="red-ui-info-outline-item-control-reveal red-ui-button red-ui-button-small"><i class="fa fa-eye"></i></button>').appendTo(controls).on("click",function(evt) {
|
|
|
|
evt.preventDefault();
|
|
|
|
evt.stopPropagation();
|
|
|
|
RED.view.reveal(n.id);
|
|
|
|
})
|
|
|
|
}
|
|
|
|
if (n.type !== 'group' && n.type !== 'subflow') {
|
|
|
|
$('<button type="button" class="red-ui-info-outline-item-control-disable red-ui-button red-ui-button-small"><i class="fa fa-circle-thin"></i><i class="fa fa-ban"></i></button>').appendTo(controls).on("click",function(evt) {
|
|
|
|
evt.preventDefault();
|
|
|
|
evt.stopPropagation();
|
|
|
|
if (n.type === 'tab') {
|
|
|
|
if (n.disabled) {
|
|
|
|
RED.workspaces.enable(n.id)
|
|
|
|
} else {
|
|
|
|
RED.workspaces.disable(n.id)
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
// TODO: this ought to be a utility function in RED.nodes
|
|
|
|
var historyEvent = {
|
|
|
|
t: "edit",
|
|
|
|
node: n,
|
|
|
|
changed: n.changed,
|
|
|
|
changes: {
|
|
|
|
d: n.d
|
|
|
|
},
|
|
|
|
dirty:RED.nodes.dirty()
|
|
|
|
}
|
|
|
|
if (n.d) {
|
|
|
|
delete n.d;
|
|
|
|
} else {
|
|
|
|
n.d = true;
|
|
|
|
}
|
|
|
|
n.dirty = true;
|
|
|
|
n.changed = true;
|
|
|
|
RED.events.emit("nodes:change",n);
|
|
|
|
RED.nodes.dirty(true)
|
|
|
|
RED.view.redraw();
|
|
|
|
}
|
|
|
|
});
|
|
|
|
} else {
|
|
|
|
$('<div class="red-ui-info-outline-item-control-spacer">').appendTo(controls)
|
|
|
|
}
|
|
|
|
controls.find("button").on("dblclick", function(evt) {
|
|
|
|
evt.preventDefault();
|
|
|
|
evt.stopPropagation();
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
|
|
|
function onProjectLoad(activeProject) {
|
2020-05-01 18:39:54 +02:00
|
|
|
var newFlowData = getFlowData();
|
|
|
|
getProjectLabel(activeProject).appendTo(projectInfo);
|
2020-04-27 12:17:19 +02:00
|
|
|
treeList.treeList('data',newFlowData);
|
|
|
|
}
|
|
|
|
|
|
|
|
function build() {
|
2020-05-01 18:39:54 +02:00
|
|
|
var container = $("<div>", {class:"red-ui-info-outline"}).css({'height': '100%'});
|
2020-05-06 17:15:12 +02:00
|
|
|
var toolbar = $("<div>", {class:"red-ui-sidebar-header red-ui-info-toolbar"}).appendTo(container);
|
2020-04-27 12:17:19 +02:00
|
|
|
|
2020-05-06 17:15:12 +02:00
|
|
|
searchInput = $('<input type="text" data-i18n="[placeholder]menu.label.search">').appendTo(toolbar).searchBox({
|
2020-05-01 18:39:54 +02:00
|
|
|
delay: 300,
|
|
|
|
change: function() {
|
|
|
|
var val = $(this).val();
|
|
|
|
var searchResults = RED.search.search(val);
|
|
|
|
if (val) {
|
|
|
|
var resultMap = {};
|
|
|
|
for (var i=0,l=searchResults.length;i<l;i++) {
|
|
|
|
resultMap[searchResults[i].node.id] = true;
|
2020-04-27 12:17:19 +02:00
|
|
|
}
|
2020-05-01 18:39:54 +02:00
|
|
|
var c = treeList.treeList('filter',function(item) {
|
|
|
|
if (item.depth === 0) {
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
return item.id && objects[item.id] && resultMap[item.id]
|
|
|
|
},true)
|
|
|
|
} else {
|
|
|
|
treeList.treeList('filter',null);
|
2020-05-01 18:51:44 +02:00
|
|
|
var selected = treeList.treeList('selected');
|
|
|
|
if (selected.id) {
|
|
|
|
treeList.treeList('show',selected.id);
|
|
|
|
}
|
2020-04-27 12:17:19 +02:00
|
|
|
|
|
|
|
}
|
2020-05-01 18:39:54 +02:00
|
|
|
}
|
|
|
|
});
|
2020-04-27 12:17:19 +02:00
|
|
|
|
2020-05-01 18:39:54 +02:00
|
|
|
projectInfo = $('<div class="red-ui-treeList-label red-ui-info-outline-project"><span class="red-ui-treeList-icon"><i class="fa fa-archive"></i></span></div>').appendTo(container)
|
2020-04-27 12:17:19 +02:00
|
|
|
|
2020-05-01 18:39:54 +02:00
|
|
|
// <div class="red-ui-info-outline-item red-ui-info-outline-item-flow" style=";"><div class="red-ui-search-result-description red-ui-info-outline-item-label">Space Monkey</div><div class="red-ui-info-outline-item-controls"><button class="red-ui-button red-ui-button-small" style="position:absolute;right:5px;"><i class="fa fa-ellipsis-h"></i></button></div></div></div>').appendTo(container)
|
2020-04-27 12:17:19 +02:00
|
|
|
|
2020-05-01 18:39:54 +02:00
|
|
|
treeList = $("<div>").css({width: "100%"}).appendTo(container).treeList({
|
|
|
|
data:getFlowData()
|
|
|
|
})
|
|
|
|
// treeList.on('treelistselect', function(e,item) {
|
|
|
|
// console.log(item)
|
|
|
|
// RED.view.reveal(item.id);
|
|
|
|
// })
|
|
|
|
// treeList.treeList('data',[ ... ] )
|
|
|
|
treeList.on('treelistconfirm', function(e,item) {
|
|
|
|
var node = RED.nodes.node(item.id);
|
|
|
|
if (node) {
|
|
|
|
if (node._def.category === "config") {
|
|
|
|
RED.editor.editConfig("", node.type, node.id);
|
|
|
|
} else {
|
|
|
|
RED.editor.edit(node);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
})
|
2020-04-27 12:17:19 +02:00
|
|
|
|
2020-05-01 18:39:54 +02:00
|
|
|
RED.events.on("projects:load", onProjectLoad)
|
2020-04-27 12:17:19 +02:00
|
|
|
|
2020-05-01 18:39:54 +02:00
|
|
|
RED.events.on("flows:add", onFlowAdd)
|
|
|
|
RED.events.on("flows:remove", onObjectRemove)
|
|
|
|
RED.events.on("flows:change", onFlowChange)
|
|
|
|
RED.events.on("flows:reorder", onFlowsReorder)
|
2020-04-27 12:17:19 +02:00
|
|
|
|
2020-05-01 18:39:54 +02:00
|
|
|
RED.events.on("subflows:add", onSubflowAdd)
|
|
|
|
RED.events.on("subflows:remove", onObjectRemove)
|
|
|
|
RED.events.on("subflows:change", onSubflowChange)
|
2020-04-27 12:17:19 +02:00
|
|
|
|
2020-05-01 18:39:54 +02:00
|
|
|
RED.events.on("nodes:add",onNodeAdd);
|
|
|
|
RED.events.on("nodes:remove",onObjectRemove);
|
|
|
|
RED.events.on("nodes:change",onNodeChange);
|
2020-04-27 12:17:19 +02:00
|
|
|
|
2020-05-01 18:39:54 +02:00
|
|
|
RED.events.on("groups:add",onNodeAdd);
|
|
|
|
RED.events.on("groups:remove",onObjectRemove);
|
|
|
|
RED.events.on("groups:change",onNodeChange);
|
2020-04-27 12:17:19 +02:00
|
|
|
|
2020-05-01 18:39:54 +02:00
|
|
|
RED.events.on("view:selection-changed", onSelectionChanged);
|
|
|
|
|
|
|
|
|
|
|
|
// ["links","nodes","flows","subflows","groups"].forEach(function(t) {
|
|
|
|
// ["add","remove","change"].forEach(function(v) {
|
|
|
|
// RED.events.on(t+":"+v, function(n) { console.log(t+":"+v,n)})
|
|
|
|
// })
|
|
|
|
// })
|
|
|
|
// RED.events.on("workspace:clear", function() { console.log("workspace:clear")})
|
|
|
|
return container;
|
2020-04-27 12:17:19 +02:00
|
|
|
}
|
|
|
|
function onFlowAdd(ws) {
|
|
|
|
objects[ws.id] = {
|
|
|
|
id: ws.id,
|
|
|
|
element: getFlowLabel(ws),
|
|
|
|
children:[getEmptyItem(ws.id)],
|
|
|
|
deferBuild: true,
|
|
|
|
icon: "red-ui-icons red-ui-icons-flow"
|
|
|
|
}
|
|
|
|
flowList.treeList.addChild(objects[ws.id])
|
|
|
|
objects[ws.id].element.toggleClass("red-ui-info-outline-item-disabled", !!ws.disabled)
|
|
|
|
objects[ws.id].treeList.container.toggleClass("red-ui-info-outline-item-disabled", !!ws.disabled)
|
|
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
function onFlowChange(n) {
|
|
|
|
var existingObject = objects[n.id];
|
|
|
|
existingObject.element.find(".red-ui-info-outline-item-label").text(n.label || n.id);
|
|
|
|
existingObject.element.toggleClass("red-ui-info-outline-item-disabled", !!n.disabled)
|
|
|
|
existingObject.treeList.container.toggleClass("red-ui-info-outline-item-disabled", !!n.disabled)
|
|
|
|
}
|
|
|
|
function onFlowsReorder(order) {
|
|
|
|
var indexMap = {};
|
|
|
|
order.forEach(function(id,index) {
|
|
|
|
indexMap[id] = index;
|
|
|
|
})
|
|
|
|
|
|
|
|
flowList.treeList.sortChildren(function(A,B) {
|
|
|
|
if (A.id === "__global__") { return -1 }
|
|
|
|
if (B.id === "__global__") { return 1 }
|
|
|
|
return indexMap[A.id] - indexMap[B.id]
|
|
|
|
})
|
|
|
|
}
|
|
|
|
function onSubflowAdd(sf) {
|
|
|
|
objects[sf.id] = {
|
|
|
|
id: sf.id,
|
2020-05-01 18:39:54 +02:00
|
|
|
element: getNodeLabel(sf),
|
2020-04-27 12:17:19 +02:00
|
|
|
children:[getEmptyItem(sf.id)],
|
|
|
|
deferBuild: true
|
|
|
|
}
|
|
|
|
subflowList.treeList.addChild(objects[sf.id])
|
|
|
|
}
|
2020-05-01 18:39:54 +02:00
|
|
|
function onSubflowChange(sf) {
|
|
|
|
var existingObject = objects[sf.id];
|
|
|
|
existingObject.treeList.replaceElement(getNodeLabel(sf));
|
2020-04-27 12:17:19 +02:00
|
|
|
// existingObject.element.find(".red-ui-info-outline-item-label").text(n.name || n.id);
|
2020-05-01 18:39:54 +02:00
|
|
|
RED.nodes.eachNode(function(n) {
|
|
|
|
if (n.type == "subflow:"+sf.id) {
|
|
|
|
var sfInstance = objects[n.id];
|
|
|
|
sfInstance.treeList.replaceElement(getNodeLabel(n));
|
|
|
|
}
|
|
|
|
});
|
2020-04-27 12:17:19 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
function onNodeChange(n) {
|
|
|
|
var existingObject = objects[n.id];
|
|
|
|
var parent = n.g||n.z;
|
|
|
|
|
|
|
|
var nodeLabelText = getNodeLabelText(n);
|
|
|
|
if (nodeLabelText) {
|
|
|
|
existingObject.element.find(".red-ui-info-outline-item-label").text(nodeLabelText);
|
|
|
|
} else {
|
|
|
|
existingObject.element.find(".red-ui-info-outline-item-label").html(" ");
|
|
|
|
}
|
|
|
|
|
|
|
|
if (parent !== existingObject.parent.id) {
|
|
|
|
existingObject.treeList.remove();
|
|
|
|
if (!parent) {
|
|
|
|
globalConfigNodes.treeList.addChild(existingObject);
|
|
|
|
} else {
|
|
|
|
objects[parent].treeList.addChild(existingObject)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
existingObject.element.toggleClass("red-ui-info-outline-item-disabled", !!n.d)
|
|
|
|
}
|
|
|
|
function onObjectRemove(n) {
|
|
|
|
var existingObject = objects[n.id];
|
|
|
|
existingObject.treeList.remove();
|
|
|
|
delete objects[n.d]
|
|
|
|
var parent = existingObject.parent;
|
|
|
|
if (parent.children.length === 0) {
|
|
|
|
parent.treeList.addChild(getEmptyItem(parent.id));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
function onNodeAdd(n) {
|
|
|
|
objects[n.id] = {
|
|
|
|
id: n.id,
|
|
|
|
element: getNodeLabel(n)
|
|
|
|
}
|
|
|
|
if (n.type === "group") {
|
|
|
|
objects[n.id].children = [];
|
|
|
|
objects[n.id].deferBuild = true;
|
|
|
|
}
|
|
|
|
var parent = n.g||n.z;
|
|
|
|
if (parent) {
|
|
|
|
if (objects[parent]) {
|
|
|
|
if (empties[parent]) {
|
|
|
|
empties[parent].treeList.remove();
|
|
|
|
delete empties[parent];
|
|
|
|
}
|
|
|
|
objects[parent].treeList.addChild(objects[n.id])
|
|
|
|
} else {
|
|
|
|
// The parent hasn't been added yet
|
|
|
|
console.log("missing",parent)
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
// No parent - add to Global flow list
|
|
|
|
globalConfigNodes.treeList.addChild(objects[n.id])
|
|
|
|
}
|
|
|
|
objects[n.id].element.toggleClass("red-ui-info-outline-item-disabled", !!n.d)
|
|
|
|
}
|
|
|
|
|
|
|
|
function onSelectionChanged(selection) {
|
2020-05-01 18:39:54 +02:00
|
|
|
treeList.treeList('clearSelection');
|
|
|
|
// // console.log(selection);
|
|
|
|
// if (selection.nodes) {
|
|
|
|
// selection.nodes.forEach(function(n) {
|
|
|
|
// // console.log("..",n.id);
|
|
|
|
// treeList.treeList('show',n.id);
|
|
|
|
// if (objects[n.id].treeList) {
|
|
|
|
// objects[n.id].treeList.select(true);
|
|
|
|
// }
|
|
|
|
//
|
|
|
|
// });
|
|
|
|
// }
|
2020-04-27 12:17:19 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
return {
|
2020-04-27 16:23:39 +02:00
|
|
|
build: build,
|
|
|
|
search: function(val) {
|
|
|
|
searchInput.searchBox('value',val)
|
2020-05-01 18:39:54 +02:00
|
|
|
},
|
|
|
|
reveal: function(node) {
|
|
|
|
treeList.treeList('select', objects[node.id])
|
2020-04-27 16:23:39 +02:00
|
|
|
}
|
2020-04-27 12:17:19 +02:00
|
|
|
}
|
|
|
|
})();
|