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/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-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-tools.js",
|
||||
"packages/node_modules/@node-red/editor-client/src/js/ui/sidebar.js",
|
||||
|
@ -308,11 +308,9 @@ RED.popover = (function() {
|
||||
// DOWN
|
||||
if (currentItem.length > 0) {
|
||||
if (currentItem.index() === menuOptions.length-1) {
|
||||
console.log("WARP TO TOP")
|
||||
// Wrap to top of list
|
||||
list.children().first().children().first().focus();
|
||||
} else {
|
||||
console.log("GO DOWN ONE")
|
||||
currentItem.next().children().first().focus();
|
||||
}
|
||||
} else {
|
||||
@ -323,11 +321,9 @@ RED.popover = (function() {
|
||||
// UP
|
||||
if (currentItem.length > 0) {
|
||||
if (currentItem.index() === 0) {
|
||||
console.log("WARP TO BOTTOM")
|
||||
// Wrap to bottom of list
|
||||
list.children().last().children().first().focus();
|
||||
} else {
|
||||
console.log("GO UP ONE")
|
||||
currentItem.prev().children().first().focus();
|
||||
}
|
||||
} 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,10 +546,44 @@ RED.view = (function() {
|
||||
}
|
||||
});
|
||||
|
||||
RED.view.annotations.init();
|
||||
RED.view.navigator.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() {
|
||||
var gridTicks = [];
|
||||
for (var i=0;i<space_width;i+=+gridSize) {
|
||||
@ -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) {
|
||||
if (d.z !== RED.workspaces.active()) {
|
||||
return;
|
||||
@ -3938,31 +3947,11 @@ RED.view = (function() {
|
||||
|
||||
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);
|
||||
|
||||
RED.hooks.trigger("viewAddNode",{node:d,el:this})
|
||||
});
|
||||
|
||||
node.each(function(d,i) {
|
||||
if (d.dirty) {
|
||||
var self = this;
|
||||
@ -4202,10 +4191,10 @@ RED.view = (function() {
|
||||
);
|
||||
faIcon.attr("y",(d.h+13)/2);
|
||||
}
|
||||
this.__changeBadge__.setAttribute("transform", "translate("+(d.w-10)+", -2)");
|
||||
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__.classList.toggle("hide", d.valid);
|
||||
// this.__changeBadge__.setAttribute("transform", "translate("+(d.w-10)+", -2)");
|
||||
// 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__.classList.toggle("hide", d.valid);
|
||||
|
||||
thisNode.selectAll(".red-ui-flow-port-input").each(function(d,i) {
|
||||
var port = d3.select(this);
|
||||
@ -4254,8 +4243,6 @@ RED.view = (function() {
|
||||
// });
|
||||
}
|
||||
|
||||
RED.hooks.trigger("viewAddNode",{node:d,el:this})
|
||||
|
||||
if (d.dirtyStatus) {
|
||||
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(
|
||||
activeLinks,
|
||||
@ -5300,6 +5289,8 @@ RED.view = (function() {
|
||||
},
|
||||
redrawStatus: redrawStatus,
|
||||
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-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-selected-color: #{$node-selected-color};
|
||||
--red-ui-port-selected-color: #{$port-selected-color};
|
||||
|
Loading…
Reference in New Issue
Block a user