mirror of
https://github.com/node-red/node-red.git
synced 2023-10-10 13:36:53 +02:00
Merge pull request #3032 from node-red/view-annotations
Add RED.view.annotations api
This commit is contained in:
commit
5b980e8c13
@ -170,6 +170,7 @@ module.exports = function(grunt) {
|
|||||||
"packages/node_modules/@node-red/editor-client/src/js/ui/workspaces.js",
|
"packages/node_modules/@node-red/editor-client/src/js/ui/workspaces.js",
|
||||||
"packages/node_modules/@node-red/editor-client/src/js/ui/statusBar.js",
|
"packages/node_modules/@node-red/editor-client/src/js/ui/statusBar.js",
|
||||||
"packages/node_modules/@node-red/editor-client/src/js/ui/view.js",
|
"packages/node_modules/@node-red/editor-client/src/js/ui/view.js",
|
||||||
|
"packages/node_modules/@node-red/editor-client/src/js/ui/view-annotations.js",
|
||||||
"packages/node_modules/@node-red/editor-client/src/js/ui/view-navigator.js",
|
"packages/node_modules/@node-red/editor-client/src/js/ui/view-navigator.js",
|
||||||
"packages/node_modules/@node-red/editor-client/src/js/ui/view-tools.js",
|
"packages/node_modules/@node-red/editor-client/src/js/ui/view-tools.js",
|
||||||
"packages/node_modules/@node-red/editor-client/src/js/ui/sidebar.js",
|
"packages/node_modules/@node-red/editor-client/src/js/ui/sidebar.js",
|
||||||
|
@ -308,11 +308,9 @@ RED.popover = (function() {
|
|||||||
// DOWN
|
// DOWN
|
||||||
if (currentItem.length > 0) {
|
if (currentItem.length > 0) {
|
||||||
if (currentItem.index() === menuOptions.length-1) {
|
if (currentItem.index() === menuOptions.length-1) {
|
||||||
console.log("WARP TO TOP")
|
|
||||||
// Wrap to top of list
|
// Wrap to top of list
|
||||||
list.children().first().children().first().focus();
|
list.children().first().children().first().focus();
|
||||||
} else {
|
} else {
|
||||||
console.log("GO DOWN ONE")
|
|
||||||
currentItem.next().children().first().focus();
|
currentItem.next().children().first().focus();
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
@ -323,11 +321,9 @@ RED.popover = (function() {
|
|||||||
// UP
|
// UP
|
||||||
if (currentItem.length > 0) {
|
if (currentItem.length > 0) {
|
||||||
if (currentItem.index() === 0) {
|
if (currentItem.index() === 0) {
|
||||||
console.log("WARP TO BOTTOM")
|
|
||||||
// Wrap to bottom of list
|
// Wrap to bottom of list
|
||||||
list.children().last().children().first().focus();
|
list.children().last().children().first().focus();
|
||||||
} else {
|
} else {
|
||||||
console.log("GO UP ONE")
|
|
||||||
currentItem.prev().children().first().focus();
|
currentItem.prev().children().first().focus();
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
151
packages/node_modules/@node-red/editor-client/src/js/ui/view-annotations.js
vendored
Normal file
151
packages/node_modules/@node-red/editor-client/src/js/ui/view-annotations.js
vendored
Normal file
@ -0,0 +1,151 @@
|
|||||||
|
RED.view.annotations = (function() {
|
||||||
|
|
||||||
|
var annotations = {};
|
||||||
|
|
||||||
|
function init() {
|
||||||
|
RED.hooks.add("viewRedrawNode.annotations", function(evt) {
|
||||||
|
try {
|
||||||
|
if (evt.node.__pendingAnnotation__) {
|
||||||
|
addAnnotation(evt.node.__pendingAnnotation__,evt);
|
||||||
|
delete evt.node.__pendingAnnotation__;
|
||||||
|
}
|
||||||
|
var badgeDX = 0;
|
||||||
|
var controlDX = 0;
|
||||||
|
for (var i=0,l=evt.el.__annotations__.length;i<l;i++) {
|
||||||
|
var annotation = evt.el.__annotations__[i];
|
||||||
|
if (annotations.hasOwnProperty(annotation.id)) {
|
||||||
|
var opts = annotations[annotation.id];
|
||||||
|
var showAnnotation = true;
|
||||||
|
var isBadge = opts.type === 'badge';
|
||||||
|
if (opts.show !== undefined) {
|
||||||
|
if (typeof opts.show === "string") {
|
||||||
|
showAnnotation = !!evt.node[opts.show]
|
||||||
|
} else if (typeof opts.show === "function"){
|
||||||
|
showAnnotation = opts.show(evt.node)
|
||||||
|
} else {
|
||||||
|
showAnnotation = !!opts.show;
|
||||||
|
}
|
||||||
|
annotation.element.classList.toggle("hide", !showAnnotation);
|
||||||
|
}
|
||||||
|
if (isBadge) {
|
||||||
|
if (showAnnotation) {
|
||||||
|
var rect = annotation.element.getBoundingClientRect();
|
||||||
|
badgeDX += rect.width;
|
||||||
|
annotation.element.setAttribute("transform", "translate("+(evt.node.w-3-badgeDX)+", -8)");
|
||||||
|
badgeDX += 4;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (showAnnotation) {
|
||||||
|
var rect = annotation.element.getBoundingClientRect();
|
||||||
|
annotation.element.setAttribute("transform", "translate("+(3+controlDX)+", -12)");
|
||||||
|
controlDX += rect.width + 4;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
annotation.element.parentNode.removeChild(annotation.element);
|
||||||
|
evt.el.__annotations__.splice(i,1);
|
||||||
|
i--;
|
||||||
|
l--;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}catch(err) {
|
||||||
|
console.log(err)
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Register a new node annotation
|
||||||
|
* @param {string} id - unique identifier
|
||||||
|
* @param {type} opts - annotations options
|
||||||
|
*
|
||||||
|
* opts: {
|
||||||
|
* type: "badge"
|
||||||
|
* class: "",
|
||||||
|
* element: function(node),
|
||||||
|
* show: string|function(node),
|
||||||
|
* filter: function(node) -> boolean
|
||||||
|
* }
|
||||||
|
*/
|
||||||
|
function register(id, opts) {
|
||||||
|
if (opts.type !== 'badge') {
|
||||||
|
throw new Error("Unsupported annotation type: "+opts.type);
|
||||||
|
}
|
||||||
|
annotations[id] = opts
|
||||||
|
RED.hooks.add("viewAddNode.annotation-"+id, function(evt) {
|
||||||
|
if (opts.filter && !opts.filter(evt.node)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
addAnnotation(id,evt);
|
||||||
|
});
|
||||||
|
|
||||||
|
var nodes = RED.view.getActiveNodes();
|
||||||
|
nodes.forEach(function(n) {
|
||||||
|
n.__pendingAnnotation__ = id;
|
||||||
|
})
|
||||||
|
RED.view.redraw();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
function addAnnotation(id,evt) {
|
||||||
|
var opts = annotations[id];
|
||||||
|
evt.el.__annotations__ = evt.el.__annotations__ || [];
|
||||||
|
var annotationGroup = document.createElementNS("http://www.w3.org/2000/svg","g");
|
||||||
|
annotationGroup.setAttribute("class",opts.class || "");
|
||||||
|
evt.el.__annotations__.push({
|
||||||
|
id:id,
|
||||||
|
element: annotationGroup
|
||||||
|
});
|
||||||
|
var annotation = opts.element(evt.node);
|
||||||
|
if (opts.tooltip) {
|
||||||
|
annotation.addEventListener("mouseenter", getAnnotationMouseEnter(annotation,evt.node,opts.tooltip));
|
||||||
|
annotation.addEventListener("mouseleave", annotationMouseLeave);
|
||||||
|
}
|
||||||
|
annotationGroup.appendChild(annotation);
|
||||||
|
evt.el.appendChild(annotationGroup);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
function unregister(id) {
|
||||||
|
delete annotations[id]
|
||||||
|
RED.hooks.remove("*.annotation-"+id);
|
||||||
|
RED.view.redraw();
|
||||||
|
}
|
||||||
|
|
||||||
|
var badgeHoverTimeout;
|
||||||
|
var badgeHover;
|
||||||
|
function getAnnotationMouseEnter(annotation,node,tooltip) {
|
||||||
|
return function() {
|
||||||
|
var text = typeof tooltip === "function"?tooltip(node):tooltip;
|
||||||
|
if (text) {
|
||||||
|
clearTimeout(badgeHoverTimeout);
|
||||||
|
badgeHoverTimeout = setTimeout(function() {
|
||||||
|
var pos = RED.view.getElementPosition(annotation);
|
||||||
|
var rect = annotation.getBoundingClientRect();
|
||||||
|
badgeHoverTimeout = null;
|
||||||
|
badgeHover = RED.view.showTooltip(
|
||||||
|
(pos[0]+rect.width/2),
|
||||||
|
(pos[1]),
|
||||||
|
text,
|
||||||
|
"top"
|
||||||
|
);
|
||||||
|
},500);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
function annotationMouseLeave() {
|
||||||
|
clearTimeout(badgeHoverTimeout);
|
||||||
|
if (badgeHover) {
|
||||||
|
badgeHover.remove();
|
||||||
|
badgeHover = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
init: init,
|
||||||
|
register:register,
|
||||||
|
unregister:unregister
|
||||||
|
}
|
||||||
|
|
||||||
|
})();
|
@ -546,9 +546,43 @@ RED.view = (function() {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
RED.view.annotations.init();
|
||||||
RED.view.navigator.init();
|
RED.view.navigator.init();
|
||||||
RED.view.tools.init();
|
RED.view.tools.init();
|
||||||
|
|
||||||
|
|
||||||
|
RED.view.annotations.register("red-ui-flow-node-changed",{
|
||||||
|
type: "badge",
|
||||||
|
class: "red-ui-flow-node-changed",
|
||||||
|
element: function() {
|
||||||
|
var changeBadge = document.createElementNS("http://www.w3.org/2000/svg","circle");
|
||||||
|
changeBadge.setAttribute("cx",5);
|
||||||
|
changeBadge.setAttribute("cy",5);
|
||||||
|
changeBadge.setAttribute("r",5);
|
||||||
|
return changeBadge;
|
||||||
|
},
|
||||||
|
show: function(n) { return n.changed||n.moved }
|
||||||
|
})
|
||||||
|
|
||||||
|
RED.view.annotations.register("red-ui-flow-node-error",{
|
||||||
|
type: "badge",
|
||||||
|
class: "red-ui-flow-node-error",
|
||||||
|
element: function(d) {
|
||||||
|
var errorBadge = document.createElementNS("http://www.w3.org/2000/svg","path");
|
||||||
|
errorBadge.setAttribute("d","M 0,9 l 10,0 -5,-8 z");
|
||||||
|
return errorBadge
|
||||||
|
},
|
||||||
|
tooltip: function(d) {
|
||||||
|
if (d.validationErrors && d.validationErrors.length > 0) {
|
||||||
|
return RED._("editor.errors.invalidProperties")+"\n - "+d.validationErrors.join("\n - ")
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
show: function(n) { return !n.valid }
|
||||||
|
})
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
function updateGrid() {
|
function updateGrid() {
|
||||||
var gridTicks = [];
|
var gridTicks = [];
|
||||||
@ -3597,31 +3631,6 @@ RED.view = (function() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function errorBadgeMouseEnter(e) {
|
|
||||||
var d = this.__data__;
|
|
||||||
if (d.validationErrors && d.validationErrors.length > 0) {
|
|
||||||
clearTimeout(portLabelHoverTimeout);
|
|
||||||
var node = this;
|
|
||||||
portLabelHoverTimeout = setTimeout(function() {
|
|
||||||
var pos = getElementPosition(node);
|
|
||||||
portLabelHoverTimeout = null;
|
|
||||||
portLabelHover = showTooltip(
|
|
||||||
(pos[0]),
|
|
||||||
(pos[1]),
|
|
||||||
RED._("editor.errors.invalidProperties")+"\n - "+d.validationErrors.join("\n - "),
|
|
||||||
"top"
|
|
||||||
);
|
|
||||||
},500);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
function errorBadgeMouseLeave() {
|
|
||||||
clearTimeout(portLabelHoverTimeout);
|
|
||||||
if (portLabelHover) {
|
|
||||||
portLabelHover.remove();
|
|
||||||
portLabelHover = null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function redrawStatus(d,nodeEl) {
|
function redrawStatus(d,nodeEl) {
|
||||||
if (d.z !== RED.workspaces.active()) {
|
if (d.z !== RED.workspaces.active()) {
|
||||||
return;
|
return;
|
||||||
@ -3938,31 +3947,11 @@ RED.view = (function() {
|
|||||||
|
|
||||||
nodeContents.appendChild(statusEl);
|
nodeContents.appendChild(statusEl);
|
||||||
|
|
||||||
|
|
||||||
var changeBadgeG = document.createElementNS("http://www.w3.org/2000/svg","g");
|
|
||||||
changeBadgeG.setAttribute("class","red-ui-flow-node-changed hide");
|
|
||||||
changeBadgeG.setAttribute("transform","translate(20, -2)");
|
|
||||||
node[0][0].__changeBadge__ = changeBadgeG;
|
|
||||||
var changeBadge = document.createElementNS("http://www.w3.org/2000/svg","circle");
|
|
||||||
changeBadge.setAttribute("r",5);
|
|
||||||
changeBadgeG.appendChild(changeBadge);
|
|
||||||
nodeContents.appendChild(changeBadgeG);
|
|
||||||
|
|
||||||
|
|
||||||
var errorBadgeG = document.createElementNS("http://www.w3.org/2000/svg","g");
|
|
||||||
errorBadgeG.setAttribute("class","red-ui-flow-node-error hide");
|
|
||||||
errorBadgeG.setAttribute("transform","translate(0, -2)");
|
|
||||||
node[0][0].__errorBadge__ = errorBadgeG;
|
|
||||||
var errorBadge = document.createElementNS("http://www.w3.org/2000/svg","path");
|
|
||||||
errorBadge.setAttribute("d","M -5,4 l 10,0 -5,-8 z");
|
|
||||||
errorBadgeG.appendChild(errorBadge);
|
|
||||||
errorBadge.__data__ = d;
|
|
||||||
errorBadge.addEventListener("mouseenter", errorBadgeMouseEnter);
|
|
||||||
errorBadge.addEventListener("mouseleave", errorBadgeMouseLeave);
|
|
||||||
nodeContents.appendChild(errorBadgeG);
|
|
||||||
|
|
||||||
node[0][0].appendChild(nodeContents);
|
node[0][0].appendChild(nodeContents);
|
||||||
|
|
||||||
|
RED.hooks.trigger("viewAddNode",{node:d,el:this})
|
||||||
});
|
});
|
||||||
|
|
||||||
node.each(function(d,i) {
|
node.each(function(d,i) {
|
||||||
if (d.dirty) {
|
if (d.dirty) {
|
||||||
var self = this;
|
var self = this;
|
||||||
@ -4202,10 +4191,10 @@ RED.view = (function() {
|
|||||||
);
|
);
|
||||||
faIcon.attr("y",(d.h+13)/2);
|
faIcon.attr("y",(d.h+13)/2);
|
||||||
}
|
}
|
||||||
this.__changeBadge__.setAttribute("transform", "translate("+(d.w-10)+", -2)");
|
// this.__changeBadge__.setAttribute("transform", "translate("+(d.w-10)+", -2)");
|
||||||
this.__changeBadge__.classList.toggle("hide", !(d.changed||d.moved));
|
// this.__changeBadge__.classList.toggle("hide", !(d.changed||d.moved));
|
||||||
this.__errorBadge__.setAttribute("transform", "translate("+(d.w-10-((d.changed||d.moved)?14:0))+", -2)");
|
// this.__errorBadge__.setAttribute("transform", "translate("+(d.w-10-((d.changed||d.moved)?14:0))+", -2)");
|
||||||
this.__errorBadge__.classList.toggle("hide", d.valid);
|
// this.__errorBadge__.classList.toggle("hide", d.valid);
|
||||||
|
|
||||||
thisNode.selectAll(".red-ui-flow-port-input").each(function(d,i) {
|
thisNode.selectAll(".red-ui-flow-port-input").each(function(d,i) {
|
||||||
var port = d3.select(this);
|
var port = d3.select(this);
|
||||||
@ -4254,8 +4243,6 @@ RED.view = (function() {
|
|||||||
// });
|
// });
|
||||||
}
|
}
|
||||||
|
|
||||||
RED.hooks.trigger("viewAddNode",{node:d,el:this})
|
|
||||||
|
|
||||||
if (d.dirtyStatus) {
|
if (d.dirtyStatus) {
|
||||||
redrawStatus(d,this);
|
redrawStatus(d,this);
|
||||||
}
|
}
|
||||||
@ -4270,6 +4257,8 @@ RED.view = (function() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
RED.hooks.trigger("viewRedrawNode",{node:d,el:this})
|
||||||
});
|
});
|
||||||
var link = linkLayer.selectAll(".red-ui-flow-link").data(
|
var link = linkLayer.selectAll(".red-ui-flow-link").data(
|
||||||
activeLinks,
|
activeLinks,
|
||||||
@ -5300,6 +5289,8 @@ RED.view = (function() {
|
|||||||
},
|
},
|
||||||
redrawStatus: redrawStatus,
|
redrawStatus: redrawStatus,
|
||||||
showQuickAddDialog:showQuickAddDialog,
|
showQuickAddDialog:showQuickAddDialog,
|
||||||
calculateNodeDimensions: calculateNodeDimensions
|
calculateNodeDimensions: calculateNodeDimensions,
|
||||||
|
getElementPosition:getElementPosition,
|
||||||
|
showTooltip:showTooltip
|
||||||
};
|
};
|
||||||
})();
|
})();
|
||||||
|
@ -81,6 +81,11 @@
|
|||||||
--red-ui-node-status-changed-border: #{$node-status-changed-border};
|
--red-ui-node-status-changed-border: #{$node-status-changed-border};
|
||||||
--red-ui-node-status-changed-background: #{$node-status-changed-background};
|
--red-ui-node-status-changed-background: #{$node-status-changed-background};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
--red-ui-node-border: #{$node-border};
|
||||||
|
--red-ui-node-port-background:#{$node-port-background};
|
||||||
|
|
||||||
--red-ui-node-label-color: #{$node-label-color};
|
--red-ui-node-label-color: #{$node-label-color};
|
||||||
--red-ui-node-selected-color: #{$node-selected-color};
|
--red-ui-node-selected-color: #{$node-selected-color};
|
||||||
--red-ui-port-selected-color: #{$port-selected-color};
|
--red-ui-port-selected-color: #{$port-selected-color};
|
||||||
|
Loading…
Reference in New Issue
Block a user