1 /*******************************************************************************
2 * Copyright (c) 2012-2014 University of Stuttgart.
3 * All rights reserved. This program and the accompanying materials
4 * are made available under the terms of the Eclipse Public License v1.0
5 * and the Apache License 2.0 which both accompany this distribution,
6 * and are available at http://www.eclipse.org/legal/epl-v10.html
7 * and http://www.apache.org/licenses/LICENSE-2.0
10 * Oliver Kopp - initial API and implementation and/or initial documentation
11 *******************************************************************************/
14 * Functions copied from winery-common.js to replace it in the long term
16 * Shared between topology modeler and repository
18 define([], function() {
19 var xmlParser = new DOMParser();
20 var VALUE_OF_NONE_CHOOSEN = "(none)"; // constant to indicate that nothing is chosen in a select2
24 getNamespaceAndLocalNameFromQName: getNamespaceAndLocalNameFromQName,
25 replaceDialogShownHookForOrionUpdate: replaceDialogShownHookForOrionUpdate,
26 writeCollectionDefinedByATextArea: writeCollectionDefinedByATextArea,
27 getDocument: getDocument,
29 getURLFragmentOutOfFullQName: getURLFragmentOutOfFullQName,
30 makeArtifactTypeURLFromQName: makeArtifactTypeURLFromQName,
31 makeNodeTypeURLFromQName: makeNodeTypeURLFromQName,
32 makeRelationshipTypeURLFromQName: makeRelationshipTypeURLFromQName,
33 makeRelationshipTypeURLFromNSAndLocalName: makeRelationshipTypeURLFromNSAndLocalName,
35 qname2href: qname2href,
37 fetchSelect2DataAndInitSelect2: fetchSelect2DataAndInitSelect2,
38 removeItemFromSelect2Field: removeItemFromSelect2Field,
40 checkXMLValidityAndShowErrorIfInvalid: checkXMLValidityAndShowErrorIfInvalid,
41 synchronizeNameAndType: synchronizeNameAndType,
43 VALUE_OF_NONE_CHOOSEN: VALUE_OF_NONE_CHOOSEN
47 * OriginalName: encodeID
49 function encodeId(id) {
50 // the URL sent to the server should be the encoded id
51 id = encodeURIComponent(id);
52 // therefore, we have to encode it twice
53 id = encodeURIComponent(id);
58 * @param qname a QName in the form {namespace}localname
59 * @return { namespace: namespace, localname: localname }
61 function getNamespaceAndLocalNameFromQName(qname) {
62 var i = qname.indexOf("}");
64 namespace : qname.substr(1,i-1),
65 localname : qname.substr(i+1)
71 * Orion does not update content if field not fully shown
72 * therefore, we hook in into the "shown" event
74 function replaceDialogShownHookForOrionUpdate(diag, orionAreaId, content) {
75 diag.off("shown.bs.modal");
76 diag.on("shown.bs.modal", function() {
77 var area = window.winery.orionareas[orionAreaId];
78 area.editor.setText(content);
79 area.fixEditorHeight();
83 function getURLFragmentOutOfNSAndLocalName(nsAndLocalName) {
85 res = encodeID(nsAndLocalName.namespace);
87 res = res + encodeID(nsAndLocalName.localname);
92 * Extracts an URL fragment of the form <encoded namespace>/<encoded id> out of a full QName
94 * @param qname a QName in the form {namespace}localname
96 function getURLFragmentOutOfFullQName(qname) {
97 var d = getNamespaceAndLocalNameFromQName(qname);
98 return getURLFragmentOutOfNSAndLocalName(d);
102 * @param w the XMLwriter
103 * @param elementSet the set of HTML elements to write
104 * @param elementName the name of the wrapper element (e.g., "Requirements", "Policies")
106 function writeCollectionDefinedByATextArea(w, elementSet, elementName) {
107 if (elementSet.length !== 0) {
108 w.writeStartElement(elementName);
109 elementSet.each(function(i, element) {
110 // XML contains element completely
111 // we do not have to parse reqorcap.children("div.id").children("span.id").text() or the span.name
112 var text = $(element).children("textarea").val();
119 function makeArtifactTypeURLFromQName(repoURL, qname) {
120 return repoURL + "/artifacttypes/" + getURLFragmentOutOfFullQName(qname) + "/";
123 function makeNodeTypeURLFromQName(repoURL, qname) {
124 return repoURL + "/nodetypes/" + getURLFragmentOutOfFullQName(qname) + "/";
127 function makeRelationshipTypeURLFromQName(repoURL, qname) {
128 return repoURL + "/relationshiptypes/" + getURLFragmentOutOfFullQName(qname) + "/";
131 function makeRelationshipTypeURLFromNSAndLocalName(repoURL, nsAndLocalName) {
132 return repoURL + "/relationshiptypes/" + getURLFragmentOutOfNSAndLocalName(nsAndLocalName) + "/";
136 * functionality similar to org.eclipse.winery.common.Util.qname2href(String, Class<? extends TExtensibleElements>, QName)
138 function qname2href(repositoryUrl, componentPathFragment, qname) {
139 var nsAndId = getNamespaceAndLocalNameFromQName(qname);
140 var absoluteURL = repositoryUrl + "/" + componentPathFragment + "/" + getURLFragmentOutOfNSAndLocalName(nsAndId);
141 var res = "<a target=\"_blank\" data-qname=\"" + qname + "\" href=\"" + absoluteURL + "\">" + nsAndId.localname + "</a>";
148 * @param field is the jquery field
149 * @param id_to_remove the id to remove
151 function removeItemFromSelect2Field(field, id_to_remove) {
152 // nothing can be done currently
153 // see https://github.com/ivaynberg/select2/issues/535#issuecomment-30210641 for a disucssion
154 vShowNotification("The select field shows stale data. Refresh the page to get rid of that.")
158 * Fetches select2 data from the given URL and initializes the field provided by the fieldId
160 * Calls vShowError if something went wrong
162 * @param onSuccess (optional)
163 * @param allowAdditions (optional) if set to true, select2 is initalized with the functionality to allow additions during the search
165 function fetchSelect2DataAndInitSelect2(fieldId, url, onSuccess, allowAdditions) {
169 }).done(function (result) {
170 var params = {"data": result};
171 if (typeof allowAdditions === "boolean") {
172 params.createSearchChoice = function(term) {
173 // enables creation of new namespaces
174 return {id:term, text:term};
178 // init select2 and select first item
179 $("#" + fieldId).select2(params);
180 if (result.length === 0) {
181 $("#" + fieldId).select2("val", null);
183 $("#" + fieldId).select2("val", result[0].id);
186 if (typeof onSuccess === "function") {
189 }).fail(function(jqXHR, textStatus, errorThrown) {
190 vShowAJAXError("Could not fetch select2 data from " + url, jqXHR, errorThrown);
196 function getDocument(xmlString) {
197 var xmlDoc = xmlParser.parseFromString(xmlString, "text/xml");
202 * Checks given XML string for validity. If it's invalid, an error message is shown
203 * Relies on the current browser's XML handling returning a HTML document if something went wrong during parsing
205 * @return XMLdocument if XML is valid, false otherwise
207 function checkXMLValidityAndShowErrorIfInvalid(xmlString) {
208 var doc = getDocument(xmlString);
210 if (doc.firstChild.localName == "html") {
211 errorMsg = new XMLSerializer().serializeToString(doc);
213 // at Chrome, the error may be nested in the XML
215 // quick hack, only "xhtml" is quered
216 function nsResolover(x) {
217 return "http://www.w3.org/1999/xhtml";
220 var element = doc.evaluate( '//x:parsererror', doc, nsResolover, XPathResult.FIRST_ORDERED_NODE_TYPE, null).singleNodeValue;
221 if (element !== null) {
222 errorMsg = new XMLSerializer().serializeToString(element);
226 if (errorMsg !== "") {
227 vShowError(errorMsg);
235 * Updates the XML in the orion editor based on the values given in the input fields.
236 * Shows error if XML is invalid
238 * Works only with SELECT2 fields
240 * @param idPrefix: (new|edit)${shortName}, derived names: [idPrefix]Name, [idPrefix]Id, Orion[idPrefix]XML
241 * @param hasIdField: whether the Id should be read and written
242 * @param selectFields: array of {attribute, fieldSuffix}, where attribute is a name of an attribute having a QName.
243 * Each select box is determined by #[idPrefix][fieldSuffix].
244 * The select box content is converted to a QName and the result is written to the attribute [name]
245 * Default: {attribute: "type", fieldSuffix: "Type"}
247 * @return false if XML is invalid, true: an object if id/name/attribute1/attribute2/... (qname + attribute1FullQName: qname object)/xml (to be used in tmpl-${cssClassPrefix})
248 * {id:id, name:name, type: "ns5:type", typeFullQName: "{http://www.example.org}type"}
250 function synchronizeNameAndType(idPrefix, hasIdField, selectFields) {
251 if (typeof hasIdField === undefined) {
254 if (typeof selectFields === undefined) {
255 selectFields = [{attribute: "type", fieldSuffix: "Type"}];
259 var val = window.winery.orionareas["Orion" + idPrefix + "XML"].editor.getText();
260 var xmlDoc = checkXMLValidityAndShowErrorIfInvalid(val);
263 var name = $("#" + idPrefix + "Name").val();
264 // initialize result object
268 xmlDoc.firstChild.setAttribute("name", name);
270 // write id and name to XML
272 var id = $("#" + idPrefix + "Id").val();
274 // TODO a checking should be done if the id exists
275 // probably not here, but at caller's side
278 xmlDoc.firstChild.setAttribute("id", id);
282 // write each selectField to xml
283 // for that, we have to determine the QName
284 $(selectFields).each(function(i, m) {
285 var content = $("#" + idPrefix + m.fieldSuffix).select2("val");
287 if (content == VALUE_OF_NONE_CHOOSEN) {
288 // if nothing is chosen do not put it into the result
292 // determine qname of type
293 //getQNameOutOfFullQName(type, xmlDoc.firstChild) does not always work as xmlDoc.firstChild does not have ALL *available* namespace prefixes
294 var typeNSAndId = getNamespaceAndLocalNameFromQName(content);
295 var prefix = xmlDoc.firstChild.lookupPrefix(typeNSAndId.namespace);
297 // we have to ask the repo for a prefix
301 "url": winery.repositoryURL + "/admin/namespaces/" + encodeID(typeNSAndId.namespace),
303 error: function(jqXHR, textStatus, errorThrown) {
304 vShowAJAXError("Could not determine prefix", jqXHR, errorThrown);
306 success: function(resData, textStatus, jqXHR) {
310 // new prefix fetched, xmlns attribute has to be written
311 xmlDoc.firstChild.setAttribute("xmlns:" + prefix, typeNSAndId.namespace);
313 var qname = prefix + ":" + typeNSAndId.localname;
314 res[m.attribute] = qname;
315 res[m.attribute + "FullQName"] = typeNSAndId;
316 xmlDoc.firstChild.setAttribute(m.attribute, qname);
319 var xml = new XMLSerializer().serializeToString(xmlDoc);