diff options
Diffstat (limited to 'winery/org.eclipse.winery.topologymodeler/src/main/webapp/index.jsp')
-rw-r--r-- | winery/org.eclipse.winery.topologymodeler/src/main/webapp/index.jsp | 1490 |
1 files changed, 1490 insertions, 0 deletions
diff --git a/winery/org.eclipse.winery.topologymodeler/src/main/webapp/index.jsp b/winery/org.eclipse.winery.topologymodeler/src/main/webapp/index.jsp new file mode 100644 index 0000000..2a582ba --- /dev/null +++ b/winery/org.eclipse.winery.topologymodeler/src/main/webapp/index.jsp @@ -0,0 +1,1490 @@ +<%-- +/******************************************************************************* + * Copyright (c) 2012-2013 University of Stuttgart. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * and the Apache License 2.0 which both accompany this distribution, + * and are available at http://www.eclipse.org/legal/epl-v10.html + * and http://www.apache.org/licenses/LICENSE-2.0 + * + * Contributors: + * Uwe Breitenbücher - initial API and implementation and/or initial documentation + * Oliver Kopp - integration with the repository, adapted to TOSCA v1.0 + * Yves Schubert - switch to bootstrap 3 + *******************************************************************************/ +--%> + +<%@page language="java" contentType="text/html; charset=utf-8" pageEncoding="utf-8"%> +<%@page buffer="none" %> +<%@page import="java.util.Collection"%> +<%@page import="java.util.List"%> +<%@page import="java.util.LinkedList"%> +<%@page import="java.util.Map"%> +<%@page import="java.util.SortedSet"%> +<%@page import="javax.xml.namespace.QName"%> +<%@page import="org.apache.commons.lang3.StringUtils"%> +<%@page import="org.eclipse.winery.model.tosca.TArtifactTemplate"%> +<%@page import="org.eclipse.winery.model.tosca.TArtifactType"%> +<%@page import="org.eclipse.winery.model.tosca.TCapability"%> +<%@page import="org.eclipse.winery.model.tosca.TCapabilityType"%> +<%@page import="org.eclipse.winery.model.tosca.TEntityTemplate"%> +<%@page import="org.eclipse.winery.model.tosca.TTopologyTemplate"%> +<%@page import="org.eclipse.winery.model.tosca.TNodeTemplate"%> +<%@page import="org.eclipse.winery.model.tosca.TNodeType"%> +<%@page import="org.eclipse.winery.model.tosca.TPolicyType"%> +<%@page import="org.eclipse.winery.model.tosca.TRelationshipType"%> +<%@page import="org.eclipse.winery.model.tosca.TRelationshipTemplate"%> +<%@page import="org.eclipse.winery.model.tosca.TRelationshipTemplate.SourceElement"%> +<%@page import="org.eclipse.winery.model.tosca.TRelationshipTemplate.TargetElement"%> +<%@page import="org.eclipse.winery.model.tosca.TRequirement"%> +<%@page import="org.eclipse.winery.model.tosca.TRequirementType"%> +<%@page import="org.eclipse.winery.common.constants.Namespaces" %> +<%@page import="org.eclipse.winery.common.ids.definitions.ArtifactTemplateId"%> +<%@page import="org.eclipse.winery.common.ids.definitions.ServiceTemplateId" %> +<%@page import="org.eclipse.winery.common.interfaces.QNameWithName"%> +<%@page import="org.eclipse.winery.common.constants.QNames" %> +<%@page import="org.eclipse.winery.common.ModelUtilities"%> +<%@page import="org.eclipse.winery.common.Util"%> +<%@page import="org.eclipse.winery.repository.client.WineryRepositoryClientFactory"%> +<%@page import="org.eclipse.winery.repository.client.IWineryRepositoryClient"%> +<%@page import="org.eclipse.winery.repository.client.WineryRepositoryClient"%> +<%@page import="org.eclipse.winery.topologymodeler.WineryUtil"%> +<%@page import="com.sun.jersey.api.client.WebResource"%> +<%@page import="com.sun.jersey.api.client.Client"%> +<%@page import="com.sun.jersey.api.client.ClientResponse"%> +<%@page import="com.sun.jersey.api.client.config.ClientConfig"%> +<%@page import="com.sun.jersey.api.client.config.DefaultClientConfig"%> + +<%-- nc.. = non-common .. --%> +<%@taglib prefix="ncnt" tagdir="/WEB-INF/tags/templates/nodetemplates" %> +<%@taglib prefix="ncrt" tagdir="/WEB-INF/tags/templates/relationshiptemplates" %> +<%@taglib prefix="tntrq" tagdir="/WEB-INF/tags/templates/nodetemplates/reqscaps" %> + +<%@taglib prefix="ct" tagdir="/WEB-INF/tags/common" %> +<%@taglib prefix="tmpl" tagdir="/WEB-INF/tags/common/templates" %> +<%@taglib prefix="nt" tagdir="/WEB-INF/tags/common/templates/nodetemplates" %> +<%@taglib prefix="ntrq" tagdir="/WEB-INF/tags/common/templates/nodetemplates/reqscaps" %> +<%@taglib prefix="pol" tagdir="/WEB-INF/tags/common/policies" %> + +<%@taglib prefix="t" tagdir="/WEB-INF/tags" %> + +<%@taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%> +<%@taglib prefix="wc" uri="http://www.eclipse.org/winery/functions" %> + +<%@taglib prefix="tc" tagdir="/WEB-INF/tags/common/topologycompletion"%> + +<% + String repositoryURL = request.getParameter("repositoryURL"); + if (StringUtils.isEmpty(repositoryURL)) { + repositoryURL = "http://localhost:8080/winery"; + } else if (repositoryURL.endsWith("/")) { + repositoryURL = repositoryURL.substring(0, repositoryURL.length()-1); + } + + String ns = request.getParameter("ns"); + if (StringUtils.isEmpty(ns)) { +%> + A namespace has to be provided by using the query parameter “ns.” Please start the modeler using the <a href="<%=repositoryURL%>">repository</a>. +<% + return; + } + + String id = request.getParameter("id"); + if (StringUtils.isEmpty(id)) { +%> + An id has to be provided by using the query parameter “id.” Please start the modeler using the <a href="<%=repositoryURL%>">repository</a>. +<% + return; + } + + // initialize client dependend on useproxy URL parameter + IWineryRepositoryClient client; + if (request.getParameterMap().containsKey("useproxy")) { + // debugging - using fiddler: + client = new WineryRepositoryClient(true); + System.out.println("Using a proxy..."); + } else { + // production: + client = WineryRepositoryClientFactory.getWineryRepositoryClient(); + } + + client.addRepository(repositoryURL); + + if (!client.primaryRepositoryAvailable()) { +%> + The repository is not available. +<% + return; + } + + QName serviceTemplateQName = new QName(ns, id); + TTopologyTemplate topologyTemplate = client.getTopologyTemplate(serviceTemplateQName); + if (topologyTemplate == null) { +%> + Something went wrong in the repository: topology template not found. +<% + return; + } + + String topologyTemplateURL = repositoryURL + "/servicetemplates/" + Util.DoubleURLencode(serviceTemplateQName) + "/topologytemplate/"; + + String serviceTemplateName = client.getName(new ServiceTemplateId(serviceTemplateQName)); + + Collection<TRelationshipType> relationshipTypes = client.getAllTypes(TRelationshipType.class); +%> +<!DOCTYPE html> +<html> +<head> + <title>Winery Topologymodeler – <%= serviceTemplateName %></title> + <meta http-equiv="content-type" content="text/html;charset=utf-8" /> + + <link rel="icon" href="favicon.png" type="image/png"> + + <link rel="stylesheet" href="components/bootstrap/dist/css/bootstrap.css" /> + <link rel="stylesheet" href="components/bootstrap/dist/css/bootstrap-theme.css" /> + <link rel="stylesheet" href="components/bootstrap-spinedit/css/bootstrap-spinedit.css" /> + + <link rel="stylesheet" href="components/blueimp-file-upload/css/jquery.fileupload.css" /> + <link rel="stylesheet" href="components/blueimp-file-upload/css/jquery.fileupload-ui.css" /> + + <link type="text/css" href="components/pnotify/jquery.pnotify.default.css" media="all" rel="stylesheet" /> + <link type="text/css" href="components/pnotify/jquery.pnotify.default.icons.css" media="all" rel="stylesheet" /> + + <!-- select2 --> + <link type="text/css" href="components/select2/select2.css" media="all" rel="stylesheet" /> + <link type="text/css" href="components/select2/select2-bootstrap.css" media="all" rel="stylesheet" /> + + <!-- x-editable --> + <link type="text/css" href="components/x-editable/dist/bootstrap3-editable/css/bootstrap-editable.css" media="all" rel="stylesheet" /> + + <link rel="stylesheet" type="text/css" href="http://eclipse.org/orion/editor/releases/6.0/built-editor.css"/> + + <!-- Winery as last: Winrey also overwrites some definitions from above --> + <link rel="stylesheet" href="css/winery-common.css" /> + <link rel="stylesheet" href="css/topologytemplatecontent.css" /> + <link rel="stylesheet" href="css/topologymodeler.css" /> +</head> + +<body data-demo-id="drawingarea" data-library="jquery"> + +<div id="loading">loading...</div> + +<script type='text/javascript' src='${pageContext.request.contextPath}/components/requirejs/require.js'></script> +<script> + require.config({ + baseUrl: "${pageContext.request.contextPath}/js", + paths: { + "datatables": "../components/datatables/media/js/jquery.dataTables", + "jquery": "../components/jquery/jquery", + + "jquery.fileupload": "../components/blueimp-file-upload/js/jquery.fileupload", + "jquery.fileupload-ui": "../components/blueimp-file-upload/js/jquery.fileupload-ui", + "jquery.fileupload-process": "../components/blueimp-file-upload/js/jquery.fileupload-process", + "jquery.ui.widget": "../components/blueimp-file-upload/js/vendor/jquery.ui.widget", + + // required for jsplumb + "jquery.ui": "../3rdparty/jquery-ui/js/jquery-ui", + + "jsplumb": "../components/jsPlumb/dist/js/jquery.jsPlumb-1.5.4", + + "keyboardjs": "../components/KeyboardJS/keyboard", + "orioneditor": "http://eclipse.org/orion/editor/releases/6.0/built-editor-amd", + "pnotify": "../components/pnotify/jquery.pnotify", + "select2": "../components/select2/select2", + "tmpl": "../components/blueimp-tmpl/js/tmpl", + "XMLWriter": "../components/XMLWriter/XMLWriter" + } + }); +</script> + +<script type='text/javascript' src='components/jquery/jquery.js'></script> + +<script type='text/javascript' src='3rdparty/jquery-ui/js/jquery-ui.js'></script> + +<script type='text/javascript' src='components/bootstrap/dist/js/bootstrap.js'></script> + +<script type='text/javascript' src='components/bootstrap-spinedit/js/bootstrap-spinedit.js'></script> + +<!-- udpate of jquery widget by jQuery-File-Upload, which requires jQuery UI 1.9 at least --> +<!-- <script type="text/javascript" src="components/jQuery-File-Upload/js/vendor/jquery.ui.widget.js"></script> --> + +<script type='text/javascript' src='components/jsPlumb/dist/js/jquery.jsPlumb-1.5.4.js'></script> + +<script type="text/javascript" src="components/jquery-typing/plugin/jquery.typing-0.3.2.js"></script> + +<script type="text/javascript" src="components/select2/select2.js"></script> + +<script type="text/javascript" src="components/x-editable/dist/bootstrap3-editable/js/bootstrap-editable.js"></script> + +<script type="text/javascript" src="js/winery-common.js"></script> +<script type="text/javascript" src="js/winery-topologymodeler.js"></script> + +<jsp:include page="/jsp/shared/dialogs.jsp" /> + +<% + // only required for generating the CSS for each node type + Collection<TNodeType> allNodeTypes = client.getAllTypes(TNodeType.class); +%> + +<tmpl:CSSForTypes nodeTypes="<%=allNodeTypes%>" relationshipTypes="<%=relationshipTypes%>"/> + +<tmpl:propertiesBasic /> + +<t:about /> + +<script> +// global variable hodling data for relationship templates +if (!winery) winery = {}; + +// winery.connections is a hashmap from jsPlumb id to a data structure with +// .id = winery id; // The two ids DO NOT match. Explanation is at winery-common-topologyrendering.js +// ... +winery.connections = {}; + +// all x-editable popups should be placed in a way to fit "perfectly" on the screen +$.fn.editable.defaults.placement = "auto"; + +//configuration for pnotify +require(["jquery", "pnotify"], function() { + $.pnotify.defaults.styling = "bootstrap3"; +}); +</script> + +<%-- Begin: Add&Edit Req/Cap --%> + +<%List<QName> allTypes = client.getQNameListOfAllTypes(TRequirementType.class);%> +<tntrq:addorupdatereqorcap requirementOrCapability="requirement" shortName="Req" cssClassPrefix="requirements" headerLabel="Requirement" allTypes="<%=allTypes%>" clazz="<%=TRequirement.class%>" repositoryURL="<%=repositoryURL%>" /> + +<%allTypes = client.getQNameListOfAllTypes(TCapabilityType.class);%> +<tntrq:addorupdatereqorcap requirementOrCapability="capability" shortName="Cap" cssClassPrefix="capabilities" headerLabel="Capability" allTypes="<%=allTypes%>" clazz="<%=TCapability.class%>" repositoryURL="<%=repositoryURL%>" /> + +<%-- End: Add&Edit Req/Cap --%> + +<%allTypes = client.getQNameListOfAllTypes(TPolicyType.class);%> +<pol:policydiag allPolicyTypes="<%=allTypes%>" repositoryURL="<%=repositoryURL%>" /> + +<script> +"use strict"; + +// for debugging +//$.pnotify.defaults.remove = false; + +// global data structure +// .repositoryURL - the URL of the repository +// DOES NOT end with / +winery.repositoryURL = "<%=repositoryURL%>"; + +</script> + +<script> +/** + * Uses global variables currentlySelectedNodeTemplate and currentlySelectedDeploymentArtifactDiv + * + * @param atDelete (optional). Function to be called if the DA has been successfully deleted + */ +function askForDeploymentArtifactDeletion(atDelete) { + // we have to remove it on both the node template locally and on the server + // reason: if the user does NOT save after deletion, the repository would present him + // the DA again. Possibly with a dangeling reference to the artifact template, + // which might have been deleted if this DA was the last reference to it + + var daName = currentlySelectedDeploymentArtifactDiv.children("div.name").text(); + var url = "<%=topologyTemplateURL%>nodetemplates/" + encodeID(currentlySelectedNodeTemplate) + "/deploymentartifacts/" + daName; + deleteResource("this deployment artifact", url, function() { + currentlySelectedDeploymentArtifactDiv.remove(); + $("#DeploymentArtifactInfo").modal("hide"); + if (atDelete) { + atDelete(); + } + }); +} + +/** + * Queries the user for deletion of the currently selected DA. + * If the associated artifact template points to the current DA only, he is also ask if he wants to delete that template, too. + */ +function deleteDeploymentArtifact() { + var templateURL = $("#DAArtifactTemplate").attr("href"); + // an artifact template exists + // we have to ask the user if the wants to delete is as well + // IF this deployment artifact is the only reference to it + // The user has to be first asked for DA deletion and then for artifact template deletion + // Therefore, we pass a function to be executed AFTER deletion of the deployment artifact. + if (templateURL) { + // check for count + $.ajax({ + type: "GET", + async: false, + url: templateURL + "?referenceCount", + dataType: "text", + error: function(jqXHR, textStatus, errorThrown) { + vShowAJAXError("Could not get count of artifact template usage", jqXHR, errorThrown); + }, + success: function(resData, textStatus, jqXHR) { + if (resData == "1") { + var atDelete = function() { + deleteResource("the associated artifact template", templateURL, function() {}); + }; + askForDeploymentArtifactDeletion(atDelete); + } else { + // more than one reference to the artifact template + // just ask for deletion of the DA and not of the AT + askForDeploymentArtifactDeletion(); + } + } + }); + } else { + askForDeploymentArtifactDeletion(); + } +} + +/** + * The user might have updated the XML information + * This has to be copied into the "storage" of the currently selected node template + * + * Uses global variable currentlySelectedDeploymentArtifactDiv + */ +function updateDeploymentArtifact() { + require(["winery-support-common"], function(wsc) { + var newVal = $("#DAXML").val(); + if (wsc.checkXMLValidityAndShowErrorIfInvalid(newVal)) { + currentlySelectedDeploymentArtifactDiv.children("textarea").val(newVal); + $("#DeploymentArtifactInfo").modal("hide"); + } + }); +} +</script> +<div class="modal fade" id="DeploymentArtifactInfo"> + <div class="modal-dialog"> + <div class="modal-content"> + <div class="modal-header"> + <button type="button" class="close" data-dismiss="modal" aria-hidden="true">×</button> + <h4 class="modal-title">Artifact Information</h4> + </div> + <div class="modal-body"> + <form><fieldset> + <div class="form-group"> + <label for="DADname" class="control-label">Name</label> + <div id="DAname" class="form-control"></div> + </div> + + <div class="form-group"> + <label for="DAArtifactType" class="control-label">Artifact Type</label> + <a id="DAArtifactType" class="form-control" target="_blank"></a> + </div> + <div class="form-group"> + <label for="DAArtifactTemplate" class="control-label">Artifact Template</label> + <a id="DAArtifactTemplate" class="form-control" target="_blank"></a> + </div> + <div class="form-group"> + <label for=DAXML" class="control-label">XML</label> + <textarea id="DAXML" cols=50 rows=7 class="form-control"></textarea> + </div> + </fieldset></form> + </div> + <div class="modal-footer"> + <button type="button" class="btn btn-default" data-dismiss="modal">Cancel</button> + <button type="button" class="btn btn-danger" onclick="deleteDeploymentArtifact();">Delete</button> + <button type="button" class="btn btn-primary" onclick="updateDeploymentArtifact();">Ok</button> + </div> + </div> + </div> +</div> + +<!-- BEGIN TOPOLOGY COMPLETION --> +<tc:selectionDialogs repositoryURL='<%=repositoryURL%>' serviceTemplateName='<%=serviceTemplateName%>' topologyTemplateURL='<%=topologyTemplateURL%>'/> +<!-- END TOPOLOGY COMPLETION --> + +<ct:artifactcreationdialog + URL="getURLForDeploymanetArtifactGeneration()" + repositoryURL="<%=repositoryURL%>" + name="Deployment" + onSuccessfulArtifactCreationFunction="artifactAddedSuccessfully" + allNamespaces="<%=client.getNamespaces()%>" + isDeploymentArtifact="true" + allArtifactTypes="<%=client.getQNameListOfAllTypes(TArtifactType.class)%>" + defaultNSForArtifactTemplate="<%=ns%>" + > +</ct:artifactcreationdialog> + +<script> +function getURLForDeploymanetArtifactGeneration() { + return "<%=topologyTemplateURL%>nodetemplates/" + encodeID(currentlySelectedNodeTemplate) + "/deploymentartifacts/" +} +</script> + +<% +// we want to display the name of the artifact template, not the id +Collection<QNameWithName> artifactTemplateList = client.getListOfAllInstances(ArtifactTemplateId.class); +%> + +<div id="winery"> + <ncnt:propertiesOfOneNodeTemplate repositoryURL="<%=repositoryURL%>"/> + <ncrt:propertiesOfOneRelationshipTemplate relationshipTypes="<%=relationshipTypes%>" repositoryURL="<%=repositoryURL%>"/> + + <div id="topbar"> + + <button class="btn btn-success topbutton" onclick="winery.events.fire(winery.events.name.command.SAVE);" id="saveBtn" data-loading-text="Saving...">Save</button> + <div class="btn-group"> + <button class="btn btn-default" onclick="doLayout();">Layout</button> + <button class="btn btn-default" onclick="horizontalAlignment();">Align-h (|)</button> + <button class="btn btn-default" onclick="verticalAlignment();">Align-v (-)</button> + </div> + + <tmpl:toggleButtons /> + + <%-- confusing, because DELETE at this place in the management part deletes the whole entity, not just the selected one + <button class="btn btn-danger selectionOnly" onclick="winery.events.fire(winery.events.name.command.DELETE_SELECTION);">Delete</button> + --%> + + <button data-toggle="button" class="btn btn-default" onclick="togglePrintView(!$(this).hasClass('active'));">Print View</button> + + <div class="btn-group"> + <button type="button" class="btn btn-default dropdown-toggle" data-toggle="dropdown" aria-expanded="false">Other <span class="caret"></span></button> + + <ul class="dropdown-menu" role="menu"> + <li><a href="#" onclick="completeTopology();">Complete Topology</a></li> + <li><a id="exportCSARbtn" href="<%=topologyTemplateURL%>../?csar" target="_blank">Export CSAR</a></li> + <li><a href="#" onclick="showAbout();">about</a></li> + </ul> + </div> + + + <script> + $("#exportCSARbtn").tooltip({ + placement: 'bottom', + html: false, + title: "Hold CTRL key to export XML only." + }); + $("#exportCSARbtn").on("click", function(evt) { + var url = $(this).attr("href"); + if (evt.ctrlKey) { + url = url.replace(/csar$/, "definitions"); + } + window.open(url); + return false; + }); + </script> + + <script> + function togglePrintView(showPrintView) { + if (showPrintView) { + winery.events.fire(winery.events.name.command.UNSELECT_ALL_NODETEMPLATES); + if (hidePalette) hidePalette(); + // showTypes(true); + $("#drawingarea").addClass("printview"); + $("#drawingarea").removeClass("editview"); + + // move labels 10 px up + // we have to do it here as jsPlumb currently paints the label on the line instead of above of it + // See https://groups.google.com/d/msg/jsplumb/zdyAdWcRta0/K6F2MrHBH1AJ + $(".relationshipTypeLabel").each(function(i, e) { + var pos = $(e).offset(); + pos.top = pos.top - 10; + $(e).offset(pos); + }); + } else { + $("#drawingarea").removeClass("printview"); + $("#drawingarea").addClass("editview"); + + // move labels 10 px down + // we have to do it here as jsPlumb currently paints the label on the line instead of above of it + $(".relationshipTypeLabel").each(function(i, e) { + var pos = $(e).offset(); + pos.top = pos.top + 10; + $(e).offset(pos); + }); + } + } + </script> + </div> + + <tmpl:defineCreateConnectorEndpointsFunction relationshipTypes="<%=relationshipTypes%>"/> + <t:palette client="<%=client%>" relationshipTypes="<%=relationshipTypes%>" repositoryURL="<%=repositoryURL%>"/> + + <div id="selectionbox"> + </div> + + <div class="unselectable" id="editorArea"> + <div id="drawingarea" class="unselectable editview"> + +<% + List<TEntityTemplate> templateList = topologyTemplate.getNodeTemplateOrRelationshipTemplate(); + List<TRelationshipTemplate> relationshipTemplates = new LinkedList<TRelationshipTemplate>(); + for (TEntityTemplate template: templateList) { + if (template instanceof TRelationshipTemplate) { + relationshipTemplates.add((TRelationshipTemplate) template); + } else { + TNodeTemplate nodeTemplate = (TNodeTemplate) template; + + // Get saved position + // x and y are stored as attributes of other namespaces + String left = ModelUtilities.getLeft(nodeTemplate); + String top = ModelUtilities.getTop(nodeTemplate); + %> + <nt:nodeTemplateRenderer client="<%=client%>" relationshipTypes="<%=relationshipTypes%>" repositoryURL="<%=repositoryURL%>" nodeTemplate="<%=nodeTemplate%>" top="<%=top%>" left="<%=left%>"/> + <% + } + } + %> + </div> + </div> + + <script> + var multiDNDmode = false; + var multiDNDdata = {}; + + $(document).on("dragstart", "div.NodeTemplateShape", function(e) { + var nodeTemplateShape = $(this); + hideNodeTemplateShapeChangeBoxes(nodeTemplateShape); + if (nodeTemplateShape.hasClass("selected")) { + var allSelectedShapes = $("div.NodeTemplateShape.selected"); + if (allSelectedShapes.length > 1) { + // console.log("start: multiDNDmode"); + multiDNDdata.x = e.clientX; + multiDNDdata.y = e.clientY; + multiDNDdata.shapes = $("div.NodeTemplateShape.selected").not("#" + e.currentTarget.id); + multiDNDmode = true; + } + } else { + // "mousedown" event handling already took care about + // deselect everything else + // select shape + } + }); +</script> +<script> + $(document).on("drag", "div.NodeTemplateShape", function(e) { + if (multiDNDmode) { + // TODO possibly, this has to be put in a queue to avoid racing events? + var dx = e.clientX - multiDNDdata.x; + var dy = e.clientY - multiDNDdata.y; + multiDNDdata.x = e.clientX; + multiDNDdata.y = e.clientY; + multiDNDdata.shapes.each(function(i, n) { + n = $(n); + var offset = n.offset(); + offset.left += dx; + offset.top += dy; + n.offset(offset); + }); + jsPlumb.repaintEverything(); + } + }); + +</script> +<script> + + function doLayout() { + var editor = $("#editorArea"); + var nodeTemplates = editor.find(".NodeTemplateShape"); + require(["winery-sugiyamaLayouter"], function(layouter) { + layouter.layout(nodeTemplates); + }); + } + +</script> +<script> + + function horizontalAlignment() { + + var counter = 0; + var aggregatedLeft = 0; + + $("div.NodeTemplateShape.selected").each(function() { + aggregatedLeft = aggregatedLeft + $(this).position().left; + counter = counter + 1; + }); + + var newLeft = aggregatedLeft / counter; + + $("div.NodeTemplateShape.selected").each(function() { + jsPlumb.animate($(this).attr("id"), { + left : newLeft + }, { + duration : 500, + easing : 'easeOutBack' + }); + }); + + } + +</script> +<script> + + function verticalAlignment() { + + var counter = 0; + var aggregatedTop = 0; + + $("div.NodeTemplateShape.selected").each(function() { + aggregatedTop = aggregatedTop + $(this).position().top; + counter = counter + 1; + }); + + var newTop = aggregatedTop / counter; + + $("div.NodeTemplateShape.selected").each(function() { + jsPlumb.animate($(this).attr("id"), { + top : newTop + }, { + duration : 500, + easing : 'easeOutBack' + }); + }); + + } + +</script> +<script> +require(["winery-topologymodeler-AMD"], function(wt) { + winery.events.register(winery.events.name.command.SAVE, wt.save); + wt.setTopologyTemplateURL("<%=topologyTemplateURL%>"); +}); +</script> +<script> + + // "mousedown" instead of "click" enables a more Visio-like behavior + $(document).on("mousedown", "div.NodeTemplateShape", function(e) { + var target = $(e.target); + + // no special handling if x-editable popover is clicked + if (target.parents().hasClass("popover")) { + return false; + } + + // no special handling if connectors are clicked + if (target.hasClass("connectorEndpoint") || target.hasClass("connectorBox") || target.hasClass("connectorLabel")) { + return false; + } + + if (target.is("a") && !target.hasClass("editable")) { + // Link clicked + // Open in new tab + // Delay opening for 300ms to disalbe a dragstart + window.setTimeout(function() { + var href = target.attr("href"); + window.open(href); + }, 300); + return false; + } + + // if the deployment artifact "buttons" are clicked, handle that functionality + // class addOrLinkDA is also present + if (target.hasClass("addDA")) { + var nodeTemplate = $(this); + hideNodeTemplateShapeChangeBoxes(nodeTemplate); + var id = nodeTemplate.attr('id'); + + // adding DAs only works for existing resources + // Reason: the POST is directed to the "deploymentartifacts" sub resource, + // which does all the artifact template autocreation magic + $.ajax({ + type: "HEAD", + async: false, + url: "<%=topologyTemplateURL%>nodetemplates/" + encodeID(id) + "/", + error: function(jqXHR, textStatus, errorThrown) { + vShowError("Node template does not exist on the server. Please save the topology before adding deployment artifacts"); + }, + success: function(resData, textStatus, jqXHR) { + // setting this global variable is required for getURLForDeploymanetArtifactGeneration(), with which the dialog has been initalized. + currentlySelectedNodeTemplate = id; + openAddDeploymentArtifactDiag(); + } + }); + + return false; + } + + if (target.is("button")) { + // "Edit XML" or "Add deployment artifact" clicked + return false; + } + + // if the custom KV properties are clicked, handle them + if (target.hasClass("KVPropertyValue")) { + return false; + } + // OK or Cancel clicked at editable + if ((target.hasClass("icon-ok")) || (target.hasClass("icon-remove"))) { + return false; + } + + if (target.hasClass("reqorcap")) { + var reqOrCapId = undefined; // set to undefined to avoid compiler warnings + // check if req or cap should be edited + var parentReqOrCapDiv = undefined; // used to determine whether a req or cap is edited, set to undefined to avoid compiler warnings + if (target.is("div")) { + reqOrCapId = target.parent().attr("id"); + parentReqOrCapDiv = target.parent(); + } else { + vShowError("Wrong branch. UI is not consistent with code"); + } + var isReq = parentReqOrCapDiv.hasClass("requirements"); + if (isReq) { + showAddOrUpdateDiagForReq(undefined, reqOrCapId); + } else { + //console.log(parentReqOrCapDiv.hasClass("capabilities")); + showAddOrUpdateDiagForCap(undefined, reqOrCapId); + } + return false; + } + + if (target.hasClass("policy")) { + // click is always on the seen policy content (name, template, ...) + // the complete element is the parent element + var policy = $(target).parent(); + showUpdateDiagForPolicy(policy); + return false; + } + + if ( (e.shiftKey) || (e.ctrlKey) ) { + // SHIFT or CTRL indicates multi select + // toggle containment in the multi select + $(this).toggleClass("selected"); + } else { + // no explicit multi select + var numSelected = $("div.NodeTemplateShape.selected").length; + if ($(this).hasClass("selected")) { + // selection if already exists + + // Below, we raise the selection change even in that case to provoke an update of properties etc. + // When dragging and dropping a single node, the menu of the node is not shown any more + // a click on the (still selected) node should reveal the menu entries. + } else { + // curent shape not selected + + if (numSelected > 0) { + // other shapes are selected + // the clicked shape is clicked + // that means, all other shapes should be unselected + $("div.NodeTemplateShape.selected").removeClass("selected"); + } + + // no multi select trigger + // shape is unselected + // finally, select the shape + $(this).addClass("selected"); + } + } + + winery.events.fire(winery.events.name.SELECTION_CHANGED); + return false; + }); + +</script> +<script> + + // we cannot use "$("#editorArea").on("click") as this is *always* triggered before $(document).on("click", ...) + $(document).on("mousedown", "#editorArea", function(e) { + hidePalette(); + + winery.events.fire(winery.events.name.command.UNSELECT_ALL_NODETEMPLATES); + + hideRTViewOnTheRight(); + unselectAllConnections(); + + // true because jsPlumb COULD treat this event, currently unclear + return true; + }); + + /** marquee tool **/ + + var selectionBoxMode = false; + var selectionBox = {}; + + /** + * This function is called when selectionBoxMode = true and the mouse gets moved + */ + var selectionBoxModeMouseMoveFunction = function(e) { + selectionBox.endX = e.pageX; + selectionBox.endY = e.pageY; + + // fix selectionbox coordinates if they are out of the window + if (selectionBox.endX < selectionBox.minx) selectionBox.endX = selectionBox.minx; + if (selectionBox.endX > selectionBox.maxx) selectionBox.endX = selectionBox.maxx; + if (selectionBox.endY < selectionBox.miny) selectionBox.endY = selectionBox.miny; + if (selectionBox.endY > selectionBox.maxy) selectionBox.endY = selectionBox.maxy; + + // we cannot show the selection box at mousedown as this conflicts somehow with jsPlumb + // if the .offset of the selectionbox is set, jsPlumb events are not fired any more + $("#selectionbox").show(); + // setSelectionBoxCoordinates() only works if selectionbox is shown + setSelectionBoxCoordinates(); + } + + function setSelectionBoxCoordinates() { + var x; + var y; + var height; + var width; + + // adjust parameters for html, where top/left have to be smaller than lower right + if (selectionBox.startX < selectionBox.endX) { + x = selectionBox.startX; + width = selectionBox.endX - selectionBox.startX; + } else { + x = selectionBox.endX; + width = selectionBox.startX - selectionBox.endX; + } + if (selectionBox.startY < selectionBox.endY) { + y = selectionBox.startY; + height = selectionBox.endY - selectionBox.startY; + } else { + y = selectionBox.endY; + height = selectionBox.startY - selectionBox.endY; + } + + $("#selectionbox").offset({ + left : x, + top : y + }); + $("#selectionbox").width(width); + $("#selectionbox").height(height); + + // console.log("realx: " + $("#selectionbox").offset().left); + // console.log("realy: " + $("#selectionbox").offset().top); + + selectionBox.x = x; + selectionBox.y = y; + selectionBox.height = height; + selectionBox.width = width; + + var area = {}; + if (lastSelectionBox == undefined) { + // nothing selected at last, check whole new box + area = selectionBox; + } else { + // TODO + // calculate area to check + } + + // console.log("sel: " + x + "/" + y + " --X dim: " + width + "/" + height); + + // quick hack: we just go through all node templates and check them for selection + $("div.NodeTemplateShape:not('.hidden')").each(function(index, nodeTemplate) { + nodeTemplate = $(nodeTemplate); + var nx = nodeTemplate.offset().left; + var ny = nodeTemplate.offset().top; + var nw = nodeTemplate.width(); + var nh = nodeTemplate.height(); + /* console.log(nx + "/" + ny + " --> dim: " + nw + "/" + nh); */ + if (nx >= x && + ny >= y && + nx + nw <= x + width && + ny + nh <= y + height) { + nodeTemplate.addClass("selected"); + } else { + nodeTemplate.removeClass("selected"); + } + }); + + lastSelectionBox = selectionBox; + } + + // register selection box handling events + $(document).on("mousedown", "#editorArea", function(e) { + selectionBoxMode = true; + selectionBox.startX = e.pageX; + selectionBox.startY = e.pageY; + selectionBox.endX = selectionBox.startX; + selectionBox.endY = selectionBox.startY; + // console.log("Start: " + selectionBox.startX + "/" + selectionBox.startY) + selectionBox.minx = document.body.scrollLeft; + selectionBox.miny = document.body.scrollTop; + selectionBox.maxx = selectionBox.minx + $(window).width(); + selectionBox.maxy = selectionBox.miny + $(window).height(); + lastSelectionBox = undefined; + $(document).on("mousemove", selectionBoxModeMouseMoveFunction); + return true; + }); + $(document).on("mouseup", function(e) { + // TODO: possibly, dragend could be used. With the recent libraries, it also works in Chrome + if (selectionBoxMode) { + $(document).off("mousemove", selectionBoxModeMouseMoveFunction); + selectionBoxMode = false; + $("#selectionbox").hide(); + } else if (multiDNDmode) { + multiDNDmode = false; + // console.log("end: multiDNDmode"); + } + }); + +</script> +<script> + + /** + * register events / event registering / eventing + */ + $(function() { + winery.events.register( + winery.events.name.SELECTION_CHANGED, + function() { + var numSelected = $("div.NodeTemplateShape.selected").length; + + if (numSelected == 1) { + + var selectedNodeTemplate = $("div.NodeTemplateShape.selected"); + if (isShownNodeTemplateShapeChangeBoxes(selectedNodeTemplate)) { + // shape change boxes are already shown. Hide them + hideNodeTemplateShapeChangeBoxes($("div.NodeTemplateShape")); + } else { + // fired if + // * a single node template is selected, + // * no menu is shown + + // bring that shape to the front + $("div.NodeTemplateShape").css("z-index", "20"); + selectedNodeTemplate.css("z-index", "21"); + + // we show the change boxes + showNodeTemplateShapeChangeBoxes(selectedNodeTemplate); + hideNodeTemplateShapeChangeBoxes($("div.NodeTemplateShape:not(.selected)")); + } + } else { + // hide everywhere + hideNodeTemplateShapeChangeBoxes($("div.NodeTemplateShape")); + } + + updateVisibilityToggleButtons(); + } + ); + winery.events.register( + winery.events.name.command.SELECT_ALL_NODETEMPLATES, + function () { + $("div.NodeTemplateShape").addClass("selected"); + winery.events.fire(winery.events.name.SELECTION_CHANGED); + } + ); + winery.events.register( + winery.events.name.command.UNSELECT_ALL_NODETEMPLATES, + function () { + $("div.NodeTemplateShape").removeClass("selected"); + winery.events.fire(winery.events.name.SELECTION_CHANGED); + } + ); + + winery.events.register( + winery.events.name.command.MOVE_UP, + function () { + wineryMoveSelectedNodeTemplateShapes(0, -10); + return false; + } + ); + winery.events.register( + winery.events.name.command.MOVE_DOWN, + function () { + wineryMoveSelectedNodeTemplateShapes(0, 10); + return false; + } + ); + winery.events.register( + winery.events.name.command.MOVE_LEFT, + function () { + wineryMoveSelectedNodeTemplateShapes(-10, 0); + return false; + } + ); + winery.events.register( + winery.events.name.command.MOVE_RIGHT, + function () { + wineryMoveSelectedNodeTemplateShapes(10, 0); + return false; + } + ); + + winery.events.register(winery.events.name.command.DELETE_SELECTION, function() { + if ($(":focus").length == 0) { + // only delete something if no input field is focused + // otherwise, a deletion of a character leads to a deletion of the selected node + var nodesToDelete = $("div.NodeTemplateShape.selected"); + if (nodesToDelete.size() > 0) { + nodesToDelete.each(function(idx, n) { + var outEdges = jsPlumb.select({source:n.id}); + outEdges.detach(); + var inEdges = jsPlumb.select({target:n.id}); + inEdges.detach(); + }); + nodesToDelete.remove(); + } else { + jsPlumb.select().each(function(connection) { + if (connection.hasType("selected")) { + jsPlumb.detach(connection); + // handleConnectionRemoved is fired by detach, + // this handles the proper data model updates + } + }); + } + }; + }); + }); + +</script> +<script> + + /** + * Initialization code + */ + $(function() { + // We need this variable to avoid adding drop targets multiple times + // The dragenter event is triggered if the current trag leaves a sub element, too + var dragEnterCount = 0; + var firstDrop = true; + + // hack for firefox 19.0.2 publishing the dragenter event twice in some cases (when firebug is not active) + var lastElement = ""; + + var divDemo = $("html"); + divDemo.on("dragenter", function(event) { + if (firstDrop) { + $(".addnewartifacttemplate").show(); + firstDrop = false; + } + if (lastElement != event.target) { + dragEnterCount++; + lastElement = event.target; + } + }); + divDemo.on("dragleave", function(event) { + dragEnterCount--; + lastElement = ""; + if (dragEnterCount==0) { + $(".addnewartifacttemplate").hide(); + lastElement = ""; + firstDrop = true; + } + }); + + // disable dragover to enable drag'n'drop of files + // see https://github.com/blueimp/jQuery-File-Upload/wiki/Multiple-File-Upload-Widgets-on-the-same-page + $(document).on("drop dragover", function(e) { + e.preventDefault(); + e.stopPropagation(); + }); + + $(document).on("drop", function(e) { + if (e.originalEvent.dataTransfer && e.originalEvent.dataTransfer.files) { + e.preventDefault(); + e.stopPropagation(); + } + }); + + // A call is not necessary - the button should have been intialized correctly at the loading by having the right class (active) where appropriate + // updateVisibilityToggleButtons(); + }); +</script> +<script> + // fire KeyboardJS initialization in parallel to loading + require(["keyboardjs"], function(KeyboardJS) { + KeyboardJS.on('del', function(event, keys, keyComboStr) { + if (!keyComboAllowed()) { + return true; + } else { + winery.events.fire(winery.events.name.command.DELETE_SELECTION); + } + }); + + KeyboardJS.on('ctrl + s', function(event, keys, keyComboStr) { + winery.events.fire(winery.events.name.command.SAVE); + + // disable triggering saving by browser + return false; + }); + + KeyboardJS.on('ctrl + a', function(event, keys, keyComboStr) { + if (!keyComboAllowed()) { + // CTRL+a on an input element should trigger selecting all text + return true; + } else { + // otherwise, we select all node templates + winery.events.fire(winery.events.name.command.SELECT_ALL_NODETEMPLATES); + return false; + } + }); + + KeyboardJS.on('up', function(event, keys, keyComboStr) { + if (!keyComboAllowedAndNodeTemplatesSelected()) { + return true; + } else { + winery.events.fire(winery.events.name.command.MOVE_UP); + return false; + } + }); + KeyboardJS.on('down', function(event, keys, keyComboStr) { + if (!keyComboAllowedAndNodeTemplatesSelected()) { + // down on an input, when a dialog is shown or when no nodeTemplate is selected, should trigger the default action + return true; + } else { + // otherwise, we move the selected node templates down + winery.events.fire(winery.events.name.command.MOVE_DOWN); + return false; + } + }); + KeyboardJS.on('left', function(event, keys, keyComboStr) { + if (!keyComboAllowedAndNodeTemplatesSelected()) { + return true; + } else { + winery.events.fire(winery.events.name.command.MOVE_LEFT); + return false; + } + }); + KeyboardJS.on('right', function(event, keys, keyComboStr) { + if (!keyComboAllowedAndNodeTemplatesSelected()) { + return true; + } else { + winery.events.fire(winery.events.name.command.MOVE_RIGHT); + return false; + } + }); + }); +</script> +<script> + + function updateVisibilityToggleButtons() { + + if ($("div.NodeTemplateShape.selected").size() == 0) { + + // show buttons active if all parts are visible + // show buttons inactive if any part is not visible + if ($("div.NodeTemplateShape:visible .deploymentArtifactsContainer:visible").size() == $("div.NodeTemplateShape:visible .deploymentArtifactsContainer").size()) { + $('#toggleDeploymentArtifactsVisibility').addClass('active'); + } else { + $('#toggleDeploymentArtifactsVisibility').removeClass('active'); + } + if ($("div.NodeTemplateShape:visible .propertiesContainer:visible").size() == $("div.NodeTemplateShape:visible .propertiesContainer").size()) { + $('#togglePropertiesVisibility').addClass('active'); + } else { + $('#togglePropertiesVisibility').removeClass('active'); + } + if ($("div.NodeTemplateShape:visible div.type.nodetemplate:visible").size() == $("div.NodeTemplateShape:visible div.type.nodetemplate").size()) { + $('#toggleTypeVisibility').addClass('active'); + } else { + $('#toggleTypeVisibility').removeClass('active'); + } + if ($("div.NodeTemplateShape:visible div.id.nodetemplate:visible").size() == $("div.NodeTemplateShape:visible div.id.nodetemplate").size()) { + $('#toggleIdVisibility').addClass('active'); + } else { + $('#toggleIdVisibility').removeClass('active'); + } + + } else { + if ($("div.NodeTemplateShape.selected .deploymentArtifactsContainer:visible").size() > 0) { + $('#toggleDeploymentArtifactsVisibility').addClass('active'); + } else { + $('#toggleDeploymentArtifactsVisibility').removeClass('active'); + } + if ($("div.NodeTemplateShape.selected .propertiesContainer:visible").size() > 0) { + $('#togglePropertiesVisibility').addClass('active'); + } else { + $('#togglePropertiesVisibility').removeClass('active'); + } + if ($("div.NodeTemplateShape.selected div.type.nodetemplate:visible").size() > 0) { + $('#toggleTypeVisibility').addClass('active'); + } else { + $('#toggleTypeVisibility').removeClass('active'); + } + if ($("div.toggleIdVisibility.selected div.id.nodetemplate:visible").size() > 0) { + $('#toggleTypeVisibility').addClass('active'); + } else { + $('#toggleIdVisibility').removeClass('active'); + } + } + } + +</script> + +<script> + + function handleConnectionRemoved(data) { + var id = data.connection.id; + + // QUICK HACK: trigger rerouting of arrows + // jsPlumb should do it automatically, but in the winery setup, it does not + window.setTimeout(function() { + jsPlumb.repaint($("#" + data.targetId)); + }, 300); + + + delete winery.connections[id]; + } + + jsPlumb.bind("ready", function() { + jsPlumb.importDefaults({ + DragOptions : { cursor: "pointer", zIndex:2000 }, + HoverClass:"connector-hover" + }); + + jsPlumb.bind("connectionDrag", function(conn) { + isInConnectionMode = true; + winery.events.fire(winery.events.name.command.UNSELECT_ALL_NODETEMPLATES); + return true; + }); + + jsPlumb.bind("beforeDrop", function(sourceId, targetId, scope, connection, dropEndpoint) { + isInConnectionMode = false; + return true; + }); + + jsPlumb.bind("connectionDetached", function(connection) { + handleConnectionRemoved(connection); + }); + + jsPlumb.bind("click", function(conn, originalEvent) { + if (!conn.hasType("selected")) { + unselectAllConnections(); + conn.addType("selected"); + showRTViewOnTheRight(conn); + } else { + conn.removeType("selected"); + // we have to go through all connections by ourselves to find out the number of selected ones + var selectedConn = undefined; + var count = 0; + jsPlumb.select().each(function(connection) { + if (connection.hasType("selected")) { + count++; + selectedConn = connection; + } + }); + if (count == 1) { + showRTViewOnTheRight(selectedConn); + } else { + hideRTViewOnTheRight(); + } + } + }); + // jsPlumb.ready + }); + </script> + + +<%-- ===== BEGIN: enable editing properties of requirements and capabilities ===== --%> +<div class="hidden" id="skelettonContainerForRequirements"> + <%-- create property value holders for each requirement type; used for NEWLY created requirements --%> + <c:forEach items="<%=client.getAllTypes(TRequirementType.class)%>" var="type"> + <div class="skelettonPropertyEditorForReq"> + <span class="typeQName">{${type.targetNamespace}}${type.name}</span> + <tmpl:properties + propertiesDefinition="${type.propertiesDefinition}" + wpd="${wc:winerysPropertiesDefinition(type)}" + template="<%=null%>" + pathToImages="images/"> + </tmpl:properties> + </div> + </c:forEach> +</div> +<div class="hidden" id="skelettonContainerForCapabilities"> + <%-- create property value holders for each capability type; used for NEWLY created capability --%> + <c:forEach items="<%=client.getAllTypes(TCapabilityType.class)%>" var="type"> + <div class="skelettonPropertyEditorForCap"> + <span class="typeQName">{${type.targetNamespace}}${type.name}</span> + <tmpl:properties + propertiesDefinition="${type.propertiesDefinition}" + wpd="${wc:winerysPropertiesDefinition(type)}" + template="<%=null%>" + pathToImages="images/"> + </tmpl:properties> + </div> + </c:forEach> +</div> + +<script> +// Initialize skeletton editor does NOT work with the current clone thing, we have to initialize the editor after the clone add addreqorcap.tag +</script> +<%-- ===== END: enable editing properties of requirements and capabilities ===== --%> + + +<%-- ===== BEGIN: enable editing properties of relationship types ===== --%> +<%-- idea: + * create editor in skelettonContainerForRelationshipTemplates, + * move it to the properties for editing, + * and move it back to skelettonContainerForRelationshipTemplates after editing +--%> + +<div class="hidden" id="skelettonContainerForRelationshipTemplates"> + <%-- create property value holders for each relationship type; used for NEWLY created relationship templates --%> + <c:forEach items="<%=relationshipTypes%>" var="relationshipType"> + <div class="skelettonPropertyEditorForRelationshipTemplate"> + <span class="typeQName">{${relationshipType.targetNamespace}}${relationshipType.name}</span> + <tmpl:properties + propertiesDefinition="${relationshipType.propertiesDefinition}" + wpd="${wc:winerysPropertiesDefinition(relationshipType)}" + template="<%=null%>" + pathToImages="images/"> + </tmpl:properties> + </div> + </c:forEach> + + <%-- create property value holders for each existing relationship template; used for existing relationship templates--%> + <c:forEach items="<%=relationshipTemplates%>" var="relationshipTemplate"> + <%-- data-id stores the id of the relationship template --%> + <div class="propertyEditorForRelationshipTemplate" data-id="${relationshipTemplate.id}"> + <c:set var="typeQName" value="${relationshipTemplate.type}" /> + <c:set var="relationshipType" value="<%=client.getType((javax.xml.namespace.QName) pageContext.getAttribute(\"typeQName\"), TRelationshipType.class)%>" /> + <tmpl:properties + propertiesDefinition="${relationshipType.propertiesDefinition}" + wpd="${wc:winerysPropertiesDefinition(relationshipType)}" + template="${relationshipTemplate}" + pathToImages="images/"> + </tmpl:properties> + </div> + </c:forEach> +</div> + +<script> +// Initialize skeletton editor +// A clone also clones the editing functionality +$(".skelettonPropertyEditorForRelationshipTemplate").find(".KVPropertyValue").editable(); +</script> + +<script> +var tmpRelationshipTemplateProperties = {}; + +function onDoneRegisterConnectionTypesAndConnectNodeTemplates() { + // as soon as all connection types are registered, + // winery.connections[] is filled + + // winery.connections is a hashmap from jsPlumb ids to a datastructure containing the winery id + // the jsPlumb id is NOT equal to the winery id + // therefore, we have to create a map between winery id and jsplumb id + var mapTOSCAIdToJSPlumbId = {}; + $.each(winery.connections, function(i, e) { + mapTOSCAIdToJSPlumbId[e.id] = i; + }); + + // we have to move PropertyEditorForRelationshipTemplate->*ID* to winery.connections[*ID*].propertiesHTML + // we also init x-editable + $(".propertyEditorForRelationshipTemplate").each(function(i,e) { + var id = $(e).data("id"); + var propertiesContainer = $(e).children("div.propertiesContainer"); + if (propertiesContainer.length != 0) { + // properties exist + // move the properties container + id = mapTOSCAIdToJSPlumbId[id]; + winery.connections[id].propertiesContainer = propertiesContainer; + propertiesContainer.find(".KVPropertyValue").editable(); + } + }); + + // we have to bind here and not in propertiesOfOneRelationshipTemplate.tag as we only want to listen to *usercreated* connections, + // not to existing ones + jsPlumb.bind("connection", function(data) { + // similar to winery-common-topologyrendering -> handleConnectionCreated + var conn; + if (data.connection) { + conn = data.connection; + } else { + conn = data; + } + + var id = conn.id; + var type = conn.getType()[0]; + var propertiesContainer= $(".skelettonPropertyEditorForRelationshipTemplate > span:contains('" + type + "')").parent().children("div"); + winery.connections[id].propertiesContainer = propertiesContainer; + }); + + // finally, we have finished loading + $('#loading').fadeOut(); +} +</script> +<%-- ===== END: enable editing properties of relationship types ===== --%> + +<tmpl:registerConnectionTypesAndConnectNodeTemplates relationshipTemplates="<%=relationshipTemplates%>" relationshipTypes="<%=relationshipTypes %>" ondone="onDoneRegisterConnectionTypesAndConnectNodeTemplates();" repositoryURL="<%=repositoryURL%>"/> + +<!-- The template to display files available for upload --> +<script id="template-upload" type="text/x-tmpl"> +{% for (var i=0, file; file=o.files[i]; i++) { %} + <tr class="template-upload fade"> + <td> + <span class="preview"></span> + </td> + <td> + <p class="name">{%=file.name%}</p> + {% if (file.error) { %} + <div><span class="label label-important">Error</span> {%=file.error%}</div> + {% } %} + </td> + <td> + <p class="size">{%=o.formatFileSize(file.size)%}</p> + {% if (!o.files.error) { %} + <div class="progress progress-success progress-striped active" role="progressbar" aria-valuemin="0" aria-valuemax="100" aria-valuenow="0"><div class="bar" style="width:0%;"></div></div> + {% } %} + </td> + <td> + {% if (!o.files.error && !i && !o.options.autoUpload) { %} + <button class="btn btn-primary start"> + <i class="icon-upload icon-white"></i> + <span>Start</span> + </button> + {% } %} + {% if (!i) { %} + <button class="btn btn-warning cancel"> + <i class="icon-ban-circle icon-white"></i> + <span>Cancel</span> + </button> + {% } %} + </td> + </tr> +{% } %} +</script> +<!-- The template to display files available for download --> +<script id="template-download" type="text/x-tmpl"> +{% for (var i=0, file; file=o.files[i]; i++) { %} + <tr class="template-download fade"> + <td> + <span class="preview"> + {% if (file.thumbnailUrl) { %} + <a href="{%=file.url%}" title="{%=file.name%}" download="{%=file.name%}" data-gallery><img src="{%=file.thumbnailUrl%}"></a> + {% } %} + </span> + </td> + <td> + <p class="name"> + <a href="{%=file.url%}" title="{%=file.name%}" download="{%=file.name%}" {%=file.thumbnailUrl?'data-gallery':''%}>{%=file.name%}</a> + </p> + {% if (file.error) { %} + <div><span class="label label-important">Error</span> {%=file.error%}</div> + {% } %} + </td> + <td> + <span class="size">{%=o.formatFileSize(file.size)%}</span> + </td> + <td> + <button class="btn btn-danger delete" data-type="{%=file.deleteType%}" data-url="{%=file.deleteUrl%}"{% if (file.deleteWithCredentials) { %} data-xhr-fields='{"withCredentials":true}'{% } %}> + <i class="icon-trash icon-white"></i> + <span>Delete</span> + </button> + </td> + </tr> +{% } %} +</script> + +</div> + +<script type="text/x-tmpl" id="tmpl-deploymentArtifact"> + <div class="deploymentArtifact row" onclick="showDeploymentArtifactInformation('{%=o.nodeTemplateId%}', '{%=o.name%}');"> + <textarea class="hidden">{%=o.xml%}</textarea> + <div class="col-xs-4 overflowhidden deploymentArtifact name">{%=o.name%}</div> + <div class="col-xs-4 overflowhidden artifactTemplate">{% if (o.artifactTemplateName) { %}{%=o.artifactTemplateName%}{% } %}</div> + <div class="col-xs-4 overflowhidden artifactType">{%=o.artifactTypeName%}</div> + </div> +</script> + +<script type="text/x-tmpl" id="tmpl-deploymentArtifactXML"> + <tosca:DeploymentArtifact + name="{%=o.name%}" + xmlns:ns1="{%=o.artifactTypeNSAndId.namespace%}" + artifactType="ns1:{%=o.artifactTypeNSAndId.localname%}" + {% if (o.artifactTemplateNSAndId) { %} + xmlns:ns2="{%=o.artifactTemplateNSAndId.namespace%}" + artifactRef="ns2:{%=o.artifactTemplateNSAndId.localname%}" + {% } %} + xmlns:tosca="<%=org.eclipse.winery.common.constants.Namespaces.TOSCA_NAMESPACE%>" /> +</script> + +<%-- param: value, selected (optional), text --%> +<script type="text/x-tmpl" id="tmpl-option"> +<option value="{%=o.value%}"{% if (o.selected) { %} selected="selected"{% } %}>{%=o.text%}</option> +</script> + + </body> +</html> |