/** * Copyright JS Foundation and other contributors, http://js.foundation * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. **/ RED.subflow = (function() { var _subflowEditTemplate = ''; var _subflowTemplateEditTemplate = ''; function findAvailableSubflowIOPosition(subflow,isInput) { var pos = {x:50,y:30}; if (!isInput) { pos.x += 110; } var ports = [].concat(subflow.out).concat(subflow.in); if (subflow.status) { ports.push(subflow.status); } ports.sort(function(A,B) { return A.x-B.x; }); for (var i=0; i output.i) { subflowMovedLinks.push(l); } } }); subflowRemovedLinks.forEach(function(l) { RED.nodes.removeLink(l)}); subflowMovedLinks.forEach(function(l) { l.sourcePort--; }); removedLinks = removedLinks.concat(subflowRemovedLinks); for (var j=output.i;j ').appendTo(toolbar); // Inputs $(' '+ '
'+ '0'+ '1'+ '
').appendTo(toolbar); // Outputs $('
'+ ''+ '
3
'+ ''+ '
').appendTo(toolbar); // Status $('').appendTo(toolbar); // $(' ').appendTo(toolbar); // $(' ').appendTo(toolbar); // Delete $(' ').appendTo(toolbar); toolbar.i18n(); $("#workspace-subflow-output-remove").on("click", function(event) { event.preventDefault(); var wasDirty = RED.nodes.dirty(); var wasChanged = activeSubflow.changed; var result = removeSubflowOutput(); if (result) { var inst = refresh(true); RED.history.push({ t:'delete', links:result.links, subflowOutputs: result.subflowOutputs, changed: wasChanged, dirty:wasDirty, subflow: { instances: inst.instances } }); RED.view.select(); RED.nodes.dirty(true); RED.view.redraw(true); } }); $("#workspace-subflow-output-add").on("click", function(event) { event.preventDefault(); addSubflowOutput(); }); $("#workspace-subflow-input-add").on("click", function(event) { event.preventDefault(); addSubflowInput(); }); $("#workspace-subflow-input-remove").on("click", function(event) { event.preventDefault(); var wasDirty = RED.nodes.dirty(); var wasChanged = activeSubflow.changed; activeSubflow.changed = true; var result = removeSubflowInput(); if (result) { var inst = refresh(true); RED.history.push({ t:'delete', links:result.links, changed: wasChanged, subflowInputs: result.subflowInputs, dirty:wasDirty, subflow: { instances: inst.instances } }); RED.view.select(); RED.nodes.dirty(true); RED.view.redraw(true); } }); $("#workspace-subflow-status").on("change", function(evt) { if (this.checked) { addSubflowStatus(); } else { var currentStatus = activeSubflow.status; var wasChanged = activeSubflow.changed; var result = removeSubflowStatus(); if (result) { activeSubflow.changed = true; var wasDirty = RED.nodes.dirty(); RED.history.push({ t:'delete', links:result.links, changed: wasChanged, dirty:wasDirty, subflow: { id: activeSubflow.id, status: currentStatus } }); RED.view.select(); RED.nodes.dirty(true); RED.view.redraw(); } } }) $("#workspace-subflow-edit").on("click", function(event) { RED.editor.editSubflow(RED.nodes.subflow(RED.workspaces.active())); event.preventDefault(); }); $("#workspace-subflow-delete").on("click", function(event) { event.preventDefault(); var startDirty = RED.nodes.dirty(); var historyEvent = removeSubflow(RED.workspaces.active()); historyEvent.t = 'delete'; historyEvent.dirty = startDirty; RED.history.push(historyEvent); }); refreshToolbar(activeSubflow); $("#red-ui-workspace-chart").css({"margin-top": "40px"}); $("#red-ui-workspace-toolbar").show(); } function hideWorkspaceToolbar() { $("#red-ui-workspace-toolbar").hide().empty(); $("#red-ui-workspace-chart").css({"margin-top": "0"}); } function removeSubflow(id) { var removedNodes = []; var removedLinks = []; var activeSubflow = RED.nodes.subflow(id); RED.nodes.eachNode(function(n) { if (n.type == "subflow:"+activeSubflow.id) { removedNodes.push(n); } if (n.z == activeSubflow.id) { removedNodes.push(n); } }); RED.nodes.eachConfig(function(n) { if (n.z == activeSubflow.id) { removedNodes.push(n); } }); var removedConfigNodes = []; for (var i=0;i 1) { RED.notify(RED._("subflow.errors.multipleInputsToSelection"),"error"); return; } var lastIndex = 0; RED.nodes.eachSubflow(function(sf) { var m = (new RegExp("^Subflow (\\d+)$")).exec(sf.name); if (m) { lastIndex = Math.max(lastIndex,m[1]); } }); var name = "Subflow "+(lastIndex+1); var subflowId = RED.nodes.id(); var subflow = { type:"subflow", id:subflowId, name:name, info:"", in: Object.keys(candidateInputNodes).map(function(v,i) { var index = i; return { type:"subflow", direction:"in", x:snapToGrid(candidateInputNodes[v].x-(candidateInputNodes[v].w/2)-80 - offsetX), y:snapToGrid(candidateInputNodes[v].y - offsetY), z:subflowId, i:index, id:RED.nodes.id(), wires:[{id:candidateInputNodes[v].id}] }}), out: candidateOutputs.map(function(v,i) { var index = i; return { type:"subflow", direction:"out", x:snapToGrid(v.source.x+(v.source.w/2)+80 - offsetX), y:snapToGrid(v.source.y - offsetY), z:subflowId, i:index, id:RED.nodes.id(), wires:[{id:v.source.id,port:v.sourcePort}] }}) }; RED.nodes.addSubflow(subflow); var subflowInstance = { id:RED.nodes.id(), type:"subflow:"+subflow.id, x: center[0], y: center[1], z: RED.workspaces.active(), inputs: subflow.in.length, outputs: subflow.out.length, h: Math.max(30/*node_height*/,(subflow.out.length||0) * 15), changed:true } subflowInstance._def = RED.nodes.getType(subflowInstance.type); RED.editor.validateNode(subflowInstance); RED.nodes.add(subflowInstance); candidateInputs.forEach(function(l) { var link = {source:l.source, sourcePort:l.sourcePort, target: subflowInstance}; new_links.push(link); RED.nodes.addLink(link); }); candidateOutputs.forEach(function(output,i) { output.targets.forEach(function(target) { var link = {source:subflowInstance, sourcePort:i, target: target}; new_links.push(link); RED.nodes.addLink(link); }); }); subflow.in.forEach(function(input) { input.wires.forEach(function(wire) { var link = {source: input, sourcePort: 0, target: RED.nodes.node(wire.id) } new_links.push(link); RED.nodes.addLink(link); }); }); subflow.out.forEach(function(output,i) { output.wires.forEach(function(wire) { var link = {source: RED.nodes.node(wire.id), sourcePort: wire.port , target: output } new_links.push(link); RED.nodes.addLink(link); }); }); for (i=0;i -1) { otherNode.links.splice(i,1); } } } return isLocalLink; }); } n.x -= offsetX; n.y -= offsetY; n.z = subflow.id; } RED.history.push({ t:'createSubflow', nodes:[subflowInstance.id], links:new_links, subflow: { subflow: subflow, offsetX: offsetX, offsetY: offsetY }, activeWorkspace: RED.workspaces.active(), removedLinks: removedLinks, dirty:RED.nodes.dirty() }); RED.view.select(null); RED.editor.validateNode(subflow); RED.nodes.dirty(true); RED.view.redraw(true); } return { init: init, createSubflow: createSubflow, convertToSubflow: convertToSubflow, removeSubflow: removeSubflow, refresh: refresh, removeInput: removeSubflowInput, removeOutput: removeSubflowOutput, removeStatus: removeSubflowStatus } })();