🐛 Fix issues in read-only mode #39

This commit is contained in:
Jan Oberhauser 2020-05-24 14:06:22 +02:00
parent 2cdfb69e0c
commit 5718330e29
2 changed files with 112 additions and 97 deletions

View file

@ -65,6 +65,7 @@ export const nodeBase = mixins(nodeIndex).extend({
'name', 'name',
'nodeId', 'nodeId',
'instance', 'instance',
'isReadOnly',
], ],
methods: { methods: {
__addNode (node: INodeUi) { __addNode (node: INodeUi) {
@ -182,7 +183,7 @@ export const nodeBase = mixins(nodeIndex).extend({
endpoint: inputData.endpoint, endpoint: inputData.endpoint,
endpointStyle: inputData.endpointStyle, endpointStyle: inputData.endpointStyle,
isSource: false, isSource: false,
isTarget: true, isTarget: !this.isReadOnly,
parameters: { parameters: {
nodeIndex: this.nodeIndex, nodeIndex: this.nodeIndex,
type: inputName, type: inputName,
@ -246,7 +247,7 @@ export const nodeBase = mixins(nodeIndex).extend({
maxConnections: inputData.maxConnections, maxConnections: inputData.maxConnections,
endpoint: inputData.endpoint, endpoint: inputData.endpoint,
endpointStyle: inputData.endpointStyle, endpointStyle: inputData.endpointStyle,
isSource: true, isSource: !this.isReadOnly,
isTarget: false, isTarget: false,
parameters: { parameters: {
nodeIndex: this.nodeIndex, nodeIndex: this.nodeIndex,
@ -275,61 +276,63 @@ export const nodeBase = mixins(nodeIndex).extend({
this.instance.addEndpoint(this.nodeName, newEndpointData); this.instance.addEndpoint(this.nodeName, newEndpointData);
}); });
// Make nodes draggable if (this.isReadOnly === false) {
this.instance.draggable(this.nodeName, { // Make nodes draggable
grid: [10, 10], this.instance.draggable(this.nodeName, {
start: (params: { e: MouseEvent }) => { grid: [10, 10],
if (params.e && !this.$store.getters.isNodeSelected(this.data.name)) { start: (params: { e: MouseEvent }) => {
// Only the node which gets dragged directly gets an event, for all others it is if (params.e && !this.$store.getters.isNodeSelected(this.data.name)) {
// undefined. So check if the currently dragged node is selected and if not clear // Only the node which gets dragged directly gets an event, for all others it is
// the drag-selection. // undefined. So check if the currently dragged node is selected and if not clear
this.instance.clearDragSelection(); // the drag-selection.
this.$store.commit('resetSelectedNodes'); this.instance.clearDragSelection();
} this.$store.commit('resetSelectedNodes');
this.$store.commit('addActiveAction', 'dragActive');
},
stop: (params: { e: MouseEvent}) => {
if (this.$store.getters.isActionActive('dragActive')) {
const moveNodes = this.$store.getters.getSelectedNodes.slice();
const selectedNodeNames = moveNodes.map((node: INodeUi) => node.name);
if (!selectedNodeNames.includes(this.data.name)) {
// If the current node is not in selected add it to the nodes which
// got moved manually
moveNodes.push(this.data);
} }
// This does for some reason just get called once for the node that got clicked this.$store.commit('addActiveAction', 'dragActive');
// even though "start" and "drag" gets called for all. So lets do for now },
// some dirty DOM query to get the new positions till I have more time to stop: (params: { e: MouseEvent }) => {
// create a proper solution if (this.$store.getters.isActionActive('dragActive')) {
let newNodePositon: XYPositon; const moveNodes = this.$store.getters.getSelectedNodes.slice();
moveNodes.forEach((node: INodeUi) => { const selectedNodeNames = moveNodes.map((node: INodeUi) => node.name);
const nodeElement = `node-${this.getNodeIndex(node.name)}`; if (!selectedNodeNames.includes(this.data.name)) {
const element = document.getElementById(nodeElement); // If the current node is not in selected add it to the nodes which
if (element === null) { // got moved manually
return; moveNodes.push(this.data);
} }
newNodePositon = [ // This does for some reason just get called once for the node that got clicked
parseInt(element.style.left!.slice(0, -2), 10), // even though "start" and "drag" gets called for all. So lets do for now
parseInt(element.style.top!.slice(0, -2), 10), // some dirty DOM query to get the new positions till I have more time to
]; // create a proper solution
let newNodePositon: XYPositon;
moveNodes.forEach((node: INodeUi) => {
const nodeElement = `node-${this.getNodeIndex(node.name)}`;
const element = document.getElementById(nodeElement);
if (element === null) {
return;
}
const updateInformation = { newNodePositon = [
name: node.name, parseInt(element.style.left!.slice(0, -2), 10),
properties: { parseInt(element.style.top!.slice(0, -2), 10),
// @ts-ignore, draggable does not have definitions ];
position: newNodePositon,
},
};
this.$store.commit('updateNodeProperties', updateInformation); const updateInformation = {
}); name: node.name,
} properties: {
}, // @ts-ignore, draggable does not have definitions
filter: '.node-description, .node-description .node-name, .node-description .node-subtitle', position: newNodePositon,
}); },
};
this.$store.commit('updateNodeProperties', updateInformation);
});
}
},
filter: '.node-description, .node-description .node-name, .node-description .node-subtitle',
});
}
}, },
isCtrlKeyPressed (e: MouseEvent | KeyboardEvent): boolean { isCtrlKeyPressed (e: MouseEvent | KeyboardEvent): boolean {

View file

@ -20,6 +20,7 @@
:id="'node-' + getNodeIndex(nodeData.name)" :id="'node-' + getNodeIndex(nodeData.name)"
:key="getNodeIndex(nodeData.name)" :key="getNodeIndex(nodeData.name)"
:name="nodeData.name" :name="nodeData.name"
:isReadOnly="isReadOnly"
:instance="instance" :instance="instance"
></node> ></node>
</div> </div>
@ -102,6 +103,9 @@
<script lang="ts"> <script lang="ts">
import Vue from 'vue'; import Vue from 'vue';
import {
OverlaySpec,
} from 'jsplumb';
import { MessageBoxInputData } from 'element-ui/types/message-box'; import { MessageBoxInputData } from 'element-ui/types/message-box';
import { jsPlumb, Endpoint, OnConnectionBindInfo } from 'jsplumb'; import { jsPlumb, Endpoint, OnConnectionBindInfo } from 'jsplumb';
import { NODE_NAME_PREFIX, PLACEHOLDER_EMPTY_WORKFLOW_ID } from '@/constants'; import { NODE_NAME_PREFIX, PLACEHOLDER_EMPTY_WORKFLOW_ID } from '@/constants';
@ -1013,21 +1017,9 @@ export default mixins(
} }
}, },
initNodeView () { initNodeView () {
this.instance.importDefaults({ const connectionOverlays: OverlaySpec[] = [];
// notice the 'curviness' argument to this Bezier curve. if (this.isReadOnly === false) {
// the curves on this page are far smoother connectionOverlays.push.apply(connectionOverlays, [
// than the curves on the first demo, which use the default curviness value.
// Connector: ["Bezier", { curviness: 80 }],
Connector: ['Bezier', { curviness: 40 }],
// @ts-ignore
Endpoint: ['Dot', { radius: 5 }],
DragOptions: { cursor: 'pointer', zIndex: 5000 },
PaintStyle: { strokeWidth: 2, stroke: '#334455' },
EndpointStyle: { radius: 9, fill: '#acd', stroke: 'red' },
// EndpointStyle: {},
HoverPaintStyle: { stroke: '#ff6d5a', lineWidth: 4 },
EndpointHoverStyle: { fill: '#ff6d5a', stroke: '#acd' },
ConnectionOverlays: [
[ [
'Arrow', 'Arrow',
{ {
@ -1045,7 +1037,24 @@ export default mixins(
location: 0.5, location: 0.5,
}, },
], ],
], ]);
}
this.instance.importDefaults({
// notice the 'curviness' argument to this Bezier curve.
// the curves on this page are far smoother
// than the curves on the first demo, which use the default curviness value.
// Connector: ["Bezier", { curviness: 80 }],
Connector: ['Bezier', { curviness: 40 }],
// @ts-ignore
Endpoint: ['Dot', { radius: 5 }],
DragOptions: { cursor: 'pointer', zIndex: 5000 },
PaintStyle: { strokeWidth: 2, stroke: '#334455' },
EndpointStyle: { radius: 9, fill: '#acd', stroke: 'red' },
// EndpointStyle: {},
HoverPaintStyle: { stroke: '#ff6d5a', lineWidth: 4 },
EndpointHoverStyle: { fill: '#ff6d5a', stroke: '#acd' },
ConnectionOverlays: connectionOverlays,
Container: '#node-view', Container: '#node-view',
}); });
@ -1100,41 +1109,43 @@ export default mixins(
info.connection.setConnector(['Straight']); info.connection.setConnector(['Straight']);
} }
// Display the connection-delete button only on hover
let timer: NodeJS.Timeout | undefined;
info.connection.bind('mouseover', (connection: IConnection) => {
if (timer !== undefined) {
clearTimeout(timer);
}
const overlay = info.connection.getOverlay('remove-connection');
overlay.setVisible(true);
});
info.connection.bind('mouseout', (connection: IConnection) => {
timer = setTimeout(() => {
const overlay = info.connection.getOverlay('remove-connection');
overlay.setVisible(false);
timer = undefined;
}, 500);
});
// @ts-ignore // @ts-ignore
info.connection.removeOverlay('drop-add-node'); info.connection.removeOverlay('drop-add-node');
// @ts-ignore if (this.isReadOnly === false) {
info.connection.addOverlay([ // Display the connection-delete button only on hover
'Label', let timer: NodeJS.Timeout | undefined;
{ info.connection.bind('mouseover', (connection: IConnection) => {
id: 'remove-connection', if (timer !== undefined) {
label: '<span class="delete-connection clickable" title="Delete Connection">x</span>', clearTimeout(timer);
cssClass: 'remove-connection-label', }
visible: false, const overlay = info.connection.getOverlay('remove-connection');
events: { overlay.setVisible(true);
mousedown: () => { });
this.__removeConnectionByConnectionInfo(info, true); info.connection.bind('mouseout', (connection: IConnection) => {
timer = setTimeout(() => {
const overlay = info.connection.getOverlay('remove-connection');
overlay.setVisible(false);
timer = undefined;
}, 500);
});
// @ts-ignore
info.connection.addOverlay([
'Label',
{
id: 'remove-connection',
label: '<span class="delete-connection clickable" title="Delete Connection">x</span>',
cssClass: 'remove-connection-label',
visible: false,
events: {
mousedown: () => {
this.__removeConnectionByConnectionInfo(info, true);
},
}, },
}, },
}, ]);
]); }
// Display input names if they exist on connection // Display input names if they exist on connection
const targetNodeTypeData: INodeTypeDescription = this.$store.getters.nodeType(targetNode.type); const targetNodeTypeData: INodeTypeDescription = this.$store.getters.nodeType(targetNode.type);
@ -1329,6 +1340,7 @@ export default mixins(
// @ts-ignore // @ts-ignore
this.instance.connect({ this.instance.connect({
uuids: uuid, uuids: uuid,
detachable: !this.isReadOnly,
}); });
} else { } else {
// When nodes get connected it gets saved automatically to the storage // When nodes get connected it gets saved automatically to the storage