1
0
mirror of https://github.com/node-red/node-red.git synced 2023-10-10 13:36:53 +02:00

Add more consistent events in the editor

This introduces a much more consistent set of events within the editor
for whenever a element is added, removed or modified.

The events emited on the `RED.events` event system. The event names
take the form: `"<thing>:<action>"`.

`<thing>` can be one of:
 - nodes
 - flows
 - subflows
 - groups
 - links

`<action>` can be one of:
 - add
 - remove
 - change

The payload of the events is the object in question.

There is also:
 - flows:reorder    - when tabs are reordered. Payload is array of flow ids.
 - workspace:clear  - when the workspace is emptied - part of switching projects

The `nodes:change` event was already used by RED.nodes.dirty() to cause
the Deploy button to become active. This renames that event to:
 - workspace:dirty  - Payload is boolean flag for the dirty state

This commit also updates the Palette to use the subflows:change event to
only redraw subflows that have actually changed rather than refresh them
all whenever one of them *might* have changed. This removes a noticable
flicker of the icon which was needlessly being redrawn.
This commit is contained in:
Nick O'Leary 2020-04-20 21:30:03 +01:00
parent ae3e250269
commit 373267c53b
No known key found for this signature in database
GPG Key ID: 4F2157149161A6C9
10 changed files with 167 additions and 89 deletions

View File

@ -32,11 +32,16 @@
} }
} }
} }
function emit(evt,arg) { function emit() {
var evt = arguments[0]
var args = Array.prototype.slice.call(arguments,1);
if (RED.events.DEBUG) {
console.log(evt,args);
}
if (handlers[evt]) { if (handlers[evt]) {
for (var i=0;i<handlers[evt].length;i++) { for (var i=0;i<handlers[evt].length;i++) {
try { try {
handlers[evt][i](arg); handlers[evt][i].apply(null, args);
} catch(err) { } catch(err) {
console.log("RED.events.emit error: ["+evt+"] "+(err.toString())); console.log("RED.events.emit error: ["+evt+"] "+(err.toString()));
console.log(err); console.log(err);

View File

@ -260,9 +260,12 @@ RED.history = (function() {
} }
node.dirty = true; node.dirty = true;
} }
RED.events.emit("nodes:change",node);
} }
} }
}
if (subflow) {
RED.events.emit("subflows:change", subflow);
} }
} else if (ev.t == "move") { } else if (ev.t == "move") {
inverseEv = { inverseEv = {
@ -323,6 +326,17 @@ RED.history = (function() {
ev.node[i] = ev.changes[i]; ev.node[i] = ev.changes[i];
} }
} }
var eventType;
switch(ev.node.type) {
case 'tab': eventType = "flows"; break;
case 'group': eventType = "groups"; break;
case 'subflow': eventType = "subflows"; break;
default: eventType = "nodes"; break;
}
eventType += ":change";
RED.events.emit(eventType,ev.node);
if (ev.node.type === 'tab' && ev.changes.hasOwnProperty('disabled')) { if (ev.node.type === 'tab' && ev.changes.hasOwnProperty('disabled')) {
$("#red-ui-tab-"+(ev.node.id.replace(".","-"))).toggleClass('red-ui-workspace-disabled',!!ev.node.disabled); $("#red-ui-tab-"+(ev.node.id.replace(".","-"))).toggleClass('red-ui-workspace-disabled',!!ev.node.disabled);
$("#red-ui-workspace").toggleClass("red-ui-workspace-disabled",!!ev.node.disabled); $("#red-ui-workspace").toggleClass("red-ui-workspace-disabled",!!ev.node.disabled);
@ -559,7 +573,6 @@ RED.history = (function() {
RED.nodes.dirty(ev.dirty); RED.nodes.dirty(ev.dirty);
RED.view.updateActive(); RED.view.updateActive();
RED.view.select(null); RED.view.select(null);
RED.palette.refresh();
RED.workspaces.refresh(); RED.workspaces.refresh();
RED.sidebar.config.refresh(); RED.sidebar.config.refresh();
RED.subflow.refresh(); RED.subflow.refresh();

View File

@ -36,7 +36,7 @@ RED.nodes = (function() {
function setDirty(d) { function setDirty(d) {
dirty = d; dirty = d;
RED.events.emit("nodes:change",{dirty:dirty}); RED.events.emit("workspace:dirty",{dirty:dirty});
} }
var registry = (function() { var registry = (function() {
@ -228,6 +228,7 @@ RED.nodes = (function() {
} }
function addLink(l) { function addLink(l) {
links.push(l); links.push(l);
RED.events.emit("links:add",l);
} }
function getNode(id) { function getNode(id) {
@ -260,7 +261,7 @@ RED.nodes = (function() {
delete nodeTabMap[node.z][node.id]; delete nodeTabMap[node.z][node.id];
} }
removedLinks = links.filter(function(l) { return (l.source === node) || (l.target === node); }); removedLinks = links.filter(function(l) { return (l.source === node) || (l.target === node); });
removedLinks.forEach(function(l) {links.splice(links.indexOf(l), 1); }); removedLinks.forEach(removeLink);
var updatedConfigNode = false; var updatedConfigNode = false;
for (var d in node._def.defaults) { for (var d in node._def.defaults) {
if (node._def.defaults.hasOwnProperty(d)) { if (node._def.defaults.hasOwnProperty(d)) {
@ -317,6 +318,7 @@ RED.nodes = (function() {
} }
nodeTabMap[z][node.id] = node; nodeTabMap[z][node.id] = node;
node.z = z; node.z = z;
RED.events.emit("nodes:change",node);
} }
function moveGroupToTab(group, z) { function moveGroupToTab(group, z) {
var index = groupsByZ[group.z].indexOf(group); var index = groupsByZ[group.z].indexOf(group);
@ -324,6 +326,7 @@ RED.nodes = (function() {
groupsByZ[z] = groupsByZ[z] || []; groupsByZ[z] = groupsByZ[z] || [];
groupsByZ[z].push(group); groupsByZ[z].push(group);
group.z = z; group.z = z;
RED.events.emit("groups:change",group);
} }
function removeLink(l) { function removeLink(l) {
@ -331,6 +334,7 @@ RED.nodes = (function() {
if (index != -1) { if (index != -1) {
links.splice(index,1); links.splice(index,1);
} }
RED.events.emit("links:remove",l);
} }
function addWorkspace(ws,targetIndex) { function addWorkspace(ws,targetIndex) {
@ -343,18 +347,20 @@ RED.nodes = (function() {
} else { } else {
workspacesOrder.splice(targetIndex,0,ws.id); workspacesOrder.splice(targetIndex,0,ws.id);
} }
RED.events.emit('flows:add',ws);
} }
function getWorkspace(id) { function getWorkspace(id) {
return workspaces[id]; return workspaces[id];
} }
function removeWorkspace(id) { function removeWorkspace(id) {
delete workspaces[id]; var ws = workspaces[id];
delete nodeTabMap[id];
workspacesOrder.splice(workspacesOrder.indexOf(id),1);
var removedNodes = []; var removedNodes = [];
var removedLinks = []; var removedLinks = [];
var removedGroups = []; var removedGroups = [];
if (ws) {
delete workspaces[id];
delete nodeTabMap[id];
workspacesOrder.splice(workspacesOrder.indexOf(id),1);
var n; var n;
var node; var node;
for (n=0;n<nodes.length;n++) { for (n=0;n<nodes.length;n++) {
@ -381,6 +387,9 @@ RED.nodes = (function() {
var result = removeNode(removedNodes[n].id); var result = removeNode(removedNodes[n].id);
removedLinks = removedLinks.concat(result.links); removedLinks = removedLinks.concat(result.links);
} }
RED.events.emit('flows:remove',ws);
}
return {nodes:removedNodes,links:removedLinks, groups: removedGroups}; return {nodes:removedNodes,links:removedLinks, groups: removedGroups};
} }
@ -438,14 +447,18 @@ RED.nodes = (function() {
} }
}); });
sf._def = RED.nodes.getType("subflow:"+sf.id); sf._def = RED.nodes.getType("subflow:"+sf.id);
RED.events.emit("subflows:add",sf);
} }
function getSubflow(id) { function getSubflow(id) {
return subflows[id]; return subflows[id];
} }
function removeSubflow(sf) { function removeSubflow(sf) {
if (subflows[sf.id]) {
delete subflows[sf.id]; delete subflows[sf.id];
delete nodeTabMap[sf.id]; delete nodeTabMap[sf.id];
registry.removeNodeType("subflow:"+sf.id); registry.removeNodeType("subflow:"+sf.id);
RED.events.emit("subflows:remove",sf);
}
} }
function subflowContains(sfid,nodeid) { function subflowContains(sfid,nodeid) {
@ -1508,6 +1521,7 @@ RED.nodes = (function() {
groupsByZ = {}; groupsByZ = {};
var subflowIds = Object.keys(subflows); var subflowIds = Object.keys(subflows);
subflows = {};
subflowIds.forEach(function(id) { subflowIds.forEach(function(id) {
RED.subflow.removeSubflow(id) RED.subflow.removeSubflow(id)
}); });
@ -1524,6 +1538,8 @@ RED.nodes = (function() {
RED.sidebar.config.refresh(); RED.sidebar.config.refresh();
RED.sidebar.info.refresh(); RED.sidebar.info.refresh();
RED.events.emit("workspace:clear");
// var node_defs = {}; // var node_defs = {};
// var nodes = []; // var nodes = [];
// var configNodes = {}; // var configNodes = {};
@ -1539,6 +1555,7 @@ RED.nodes = (function() {
groupsByZ[group.z] = groupsByZ[group.z] || []; groupsByZ[group.z] = groupsByZ[group.z] || [];
groupsByZ[group.z].push(group); groupsByZ[group.z].push(group);
groups[group.id] = group; groups[group.id] = group;
RED.events.emit("groups:add",group);
} }
function removeGroup(group) { function removeGroup(group) {
var i = groupsByZ[group.z].indexOf(group); var i = groupsByZ[group.z].indexOf(group);
@ -1553,6 +1570,7 @@ RED.nodes = (function() {
RED.group.markDirty(group); RED.group.markDirty(group);
delete groups[group.id]; delete groups[group.id];
RED.events.emit("groups:remove",group);
} }

View File

@ -108,7 +108,7 @@ RED.deploy = (function() {
RED.events.on('nodes:change',function(state) { RED.events.on('workspace:dirty',function(state) {
if (state.dirty) { if (state.dirty) {
window.onbeforeunload = function() { window.onbeforeunload = function() {
return RED._("deploy.confirm.undeployedChanges"); return RED._("deploy.confirm.undeployedChanges");

View File

@ -1469,6 +1469,7 @@ RED.editor = (function() {
editing_node.dirty = true; editing_node.dirty = true;
validateNode(editing_node); validateNode(editing_node);
RED.events.emit("editor:save",editing_node); RED.events.emit("editor:save",editing_node);
RED.events.emit("nodes:change",editing_node);
RED.tray.close(); RED.tray.close();
} }
} }
@ -1989,6 +1990,7 @@ RED.editor = (function() {
RED.view.redraw(true); RED.view.redraw(true);
if (!configAdding) { if (!configAdding) {
RED.events.emit("editor:save",editing_config_node); RED.events.emit("editor:save",editing_config_node);
RED.events.emit("nodes:change",editing_config_node);
} }
RED.tray.close(function() { RED.tray.close(function() {
updateConfigNodeSelect(configProperty,configType,editing_config_node.id,prefix); updateConfigNodeSelect(configProperty,configType,editing_config_node.id,prefix);
@ -2222,7 +2224,6 @@ RED.editor = (function() {
changes.env = editing_node.env; changes.env = editing_node.env;
changed = true; changed = true;
} }
RED.palette.refresh();
if (changed) { if (changed) {
var wasChanged = editing_node.changed; var wasChanged = editing_node.changed;
@ -2242,6 +2243,7 @@ RED.editor = (function() {
validateNode(n); validateNode(n);
} }
}); });
RED.events.emit("subflows:change",editing_node);
RED.nodes.dirty(true); RED.nodes.dirty(true);
var historyEvent = { var historyEvent = {
t:'edit', t:'edit',
@ -2535,6 +2537,7 @@ RED.editor = (function() {
changed:wasChanged changed:wasChanged
}; };
RED.history.push(historyEvent); RED.history.push(historyEvent);
RED.events.emit("groups:change",editing_node);
} }
editing_node.dirty = true; editing_node.dirty = true;
RED.tray.close(); RED.tray.close();

View File

@ -311,6 +311,11 @@ RED.group = (function() {
} else { } else {
delete n.g; delete n.g;
} }
if (n.type === 'group') {
RED.events.emit("groups:change",n)
} else {
RED.events.emit("nodes:change",n)
}
}) })
RED.nodes.removeGroup(g); RED.nodes.removeGroup(g);
return nodes; return nodes;
@ -491,6 +496,11 @@ RED.group = (function() {
group.y = Math.min(group.y,n.y-n.h/2-25); group.y = Math.min(group.y,n.y-n.h/2-25);
group.w = Math.max(group.w,n.x+n.w/2+25+((n._def.button && n._def.align=="right")?20:0) - group.x); group.w = Math.max(group.w,n.x+n.w/2+25+((n._def.button && n._def.align=="right")?20:0) - group.x);
group.h = Math.max(group.h,n.y+n.h/2+25-group.y); group.h = Math.max(group.h,n.y+n.h/2+25-group.y);
if (n.type === 'group') {
RED.events.emit("groups:change",n)
} else {
RED.events.emit("nodes:change",n)
}
} }
} }
@ -520,6 +530,11 @@ RED.group = (function() {
} else { } else {
delete n.g; delete n.g;
} }
if (n.type === 'group') {
RED.events.emit("groups:change",n)
} else {
RED.events.emit("nodes:change",n)
}
} }
markDirty(group); markDirty(group);
} }

View File

@ -181,8 +181,12 @@ RED.palette = (function() {
function setIcon(element,sf) { function setIcon(element,sf) {
var icon_url = RED.utils.getNodeIcon(sf._def); var icon_url = RED.utils.getNodeIcon(sf._def);
var iconContainer = element.find(".red-ui-palette-icon-container"); var iconContainer = element.find(".red-ui-palette-icon-container");
var currentIcon = iconContainer.attr("data-palette-icon");
if (currentIcon !== icon_url) {
iconContainer.attr("data-palette-icon", icon_url);
RED.utils.createIconElement(icon_url, iconContainer, true); RED.utils.createIconElement(icon_url, iconContainer, true);
} }
}
function getPaletteNode(type) { function getPaletteNode(type) {
return $(".red-ui-palette-node[data-palette-type='"+type+"']"); return $(".red-ui-palette-node[data-palette-type='"+type+"']");
@ -224,6 +228,7 @@ RED.palette = (function() {
var iconContainer = $('<div/>', { var iconContainer = $('<div/>', {
class: "red-ui-palette-icon-container"+(((!def.align && def.inputs !== 0 && def.outputs === 0) || "right" === def.align) ? " red-ui-palette-icon-container-right" : "") class: "red-ui-palette-icon-container"+(((!def.align && def.inputs !== 0 && def.outputs === 0) || "right" === def.align) ? " red-ui-palette-icon-container-right" : "")
}).appendTo(d); }).appendTo(d);
iconContainer.attr("data-palette-icon", icon_url);
RED.utils.createIconElement(icon_url, iconContainer, true); RED.utils.createIconElement(icon_url, iconContainer, true);
} }
@ -452,9 +457,10 @@ RED.palette = (function() {
categoryNode.show(); categoryNode.show();
paletteNode.show(); paletteNode.show();
} }
function refreshNodeTypes() { function refreshNodeTypes() {
RED.nodes.eachSubflow(function(sf) { RED.nodes.eachSubflow(refreshSubflow)
}
function refreshSubflow(sf) {
var paletteNode = getPaletteNode('subflow:'+sf.id); var paletteNode = getPaletteNode('subflow:'+sf.id);
var portInput = paletteNode.find(".red-ui-palette-port-input"); var portInput = paletteNode.find(".red-ui-palette-port-input");
var portOutput = paletteNode.find(".red-ui-palette-port-output"); var portOutput = paletteNode.find(".red-ui-palette-port-output");
@ -480,7 +486,13 @@ RED.palette = (function() {
} else if (portOutput.length !== 0 && sf.out.length === 0) { } else if (portOutput.length !== 0 && sf.out.length === 0) {
portOutput.remove(); portOutput.remove();
} }
var currentLabel = paletteNode.attr("data-palette-label");
var currentInfo = paletteNode.attr("data-palette-info");
if (currentLabel !== sf.name || currentInfo !== sf.info) {
paletteNode.attr("data-palette-info",sf.info);
setLabel(sf.type+":"+sf.id,paletteNode,sf.name,RED.utils.renderMarkdown(sf.info||"")); setLabel(sf.type+":"+sf.id,paletteNode,sf.name,RED.utils.renderMarkdown(sf.info||""));
}
setIcon(paletteNode,sf); setIcon(paletteNode,sf);
var currentCategory = paletteNode.data('category'); var currentCategory = paletteNode.data('category');
@ -506,7 +518,6 @@ RED.palette = (function() {
} }
paletteNode.css("backgroundColor", sf.color); paletteNode.css("backgroundColor", sf.color);
});
} }
function filterChange(val) { function filterChange(val) {
@ -544,6 +555,8 @@ RED.palette = (function() {
$('<div class="red-ui-component-footer"></div>').appendTo("#red-ui-palette"); $('<div class="red-ui-component-footer"></div>').appendTo("#red-ui-palette");
$('<div id="red-ui-palette-shade" class="hide"></div>').appendTo("#red-ui-palette"); $('<div id="red-ui-palette-shade" class="hide"></div>').appendTo("#red-ui-palette");
$("#red-ui-palette > .red-ui-palette-spinner").show();
RED.events.on('registry:node-type-added', function(nodeType) { RED.events.on('registry:node-type-added', function(nodeType) {
var def = RED.nodes.getType(nodeType); var def = RED.nodes.getType(nodeType);
@ -585,7 +598,8 @@ RED.palette = (function() {
} }
}); });
$("#red-ui-palette > .red-ui-palette-spinner").show(); RED.events.on("subflows:change",refreshSubflow);
$("#red-ui-palette-search input").searchBox({ $("#red-ui-palette-search input").searchBox({

View File

@ -106,7 +106,7 @@ RED.subflow = (function() {
RED.view.redraw(); RED.view.redraw();
$("#red-ui-subflow-input-add").addClass("active"); $("#red-ui-subflow-input-add").addClass("active");
$("#red-ui-subflow-input-remove").removeClass("active"); $("#red-ui-subflow-input-remove").removeClass("active");
RED.palette.refresh(); RED.events.emit("subflows:change",subflow);
} }
function removeSubflowInput() { function removeSubflowInput() {
@ -128,7 +128,7 @@ RED.subflow = (function() {
$("#red-ui-subflow-input-add").removeClass("active"); $("#red-ui-subflow-input-add").removeClass("active");
$("#red-ui-subflow-input-remove").addClass("active"); $("#red-ui-subflow-input-remove").addClass("active");
activeSubflow.changed = true; activeSubflow.changed = true;
RED.palette.refresh(); RED.events.emit("subflows:change",activeSubflow);
return {subflowInputs: [ removedInput ], links:removedInputLinks}; return {subflowInputs: [ removedInput ], links:removedInputLinks};
} }
@ -169,7 +169,7 @@ RED.subflow = (function() {
RED.nodes.dirty(true); RED.nodes.dirty(true);
RED.view.redraw(); RED.view.redraw();
$("#red-ui-subflow-output .spinner-value").text(subflow.out.length); $("#red-ui-subflow-output .spinner-value").text(subflow.out.length);
RED.palette.refresh(); RED.events.emit("subflows:change",subflow);
} }
function removeSubflowOutput(removedSubflowOutputs) { function removeSubflowOutput(removedSubflowOutputs) {
@ -209,7 +209,7 @@ RED.subflow = (function() {
} }
} }
activeSubflow.changed = true; activeSubflow.changed = true;
RED.palette.refresh(); RED.events.emit("subflows:change",activeSubflow);
return {subflowOutputs: removedSubflowOutputs, links: removedLinks} return {subflowOutputs: removedSubflowOutputs, links: removedLinks}
} }
@ -244,6 +244,7 @@ RED.subflow = (function() {
RED.view.select(); RED.view.select();
RED.nodes.dirty(true); RED.nodes.dirty(true);
RED.view.redraw(); RED.view.redraw();
RED.events.emit("subflows:change",subflow);
$("#red-ui-subflow-status").prop("checked",!!subflow.status); $("#red-ui-subflow-status").prop("checked",!!subflow.status);
$("#red-ui-subflow-status").parent().parent().toggleClass("active",!!subflow.status); $("#red-ui-subflow-status").parent().parent().toggleClass("active",!!subflow.status);
} }

View File

@ -393,6 +393,8 @@ RED.view = (function() {
historyEvent.removedLinks = [spliceLink]; historyEvent.removedLinks = [spliceLink];
} }
RED.nodes.add(nn);
var group = $(ui.helper).data("group"); var group = $(ui.helper).data("group");
if (group) { if (group) {
RED.group.addToGroup(group, nn); RED.group.addToGroup(group, nn);
@ -409,7 +411,6 @@ RED.view = (function() {
} }
RED.history.push(historyEvent); RED.history.push(historyEvent);
RED.nodes.add(nn);
RED.editor.validateNode(nn); RED.editor.validateNode(nn);
RED.nodes.dirty(true); RED.nodes.dirty(true);
// auto select dropped node - so info shows (if visible) // auto select dropped node - so info shows (if visible)
@ -4528,6 +4529,7 @@ if (DEBUG_EVENTS) { console.warn("nodeMouseDown", mouse_mode,d); }
} }
node.dirty = true; node.dirty = true;
node.changed = true; node.changed = true;
RED.events.emit("nodes:change",node);
} }
} }
} }

View File

@ -140,6 +140,7 @@ RED.workspaces = (function() {
}); });
RED.view.redraw(); RED.view.redraw();
} }
RED.events.emit("flows:change",workspace);
} }
RED.tray.close(); RED.tray.close();
} }
@ -380,6 +381,7 @@ RED.workspaces = (function() {
} }
workspace.changed = true; workspace.changed = true;
RED.history.push(historyEvent); RED.history.push(historyEvent);
RED.events.emit("flows:change",workspace);
RED.nodes.dirty(true); RED.nodes.dirty(true);
RED.sidebar.config.refresh(); RED.sidebar.config.refresh();
var selection = RED.view.selection(); var selection = RED.view.selection();
@ -412,9 +414,14 @@ RED.workspaces = (function() {
} }
function setWorkspaceOrder(order) { function setWorkspaceOrder(order) {
RED.nodes.setWorkspaceOrder(order.filter(function(id) { var newOrder = order.filter(function(id) {
return RED.nodes.workspace(id) !== undefined; return RED.nodes.workspace(id) !== undefined;
})); })
var currentOrder = RED.nodes.getWorkspaceOrder();
if (JSON.stringify(newOrder) !== JSON.stringify(currentOrder)) {
RED.nodes.setWorkspaceOrder(newOrder);
RED.events.emit("flows:reorder",newOrder);
}
workspace_tabs.order(order); workspace_tabs.order(order);
} }