Merge "Inherit from oparent"
[vfc/nfvo/wfengine.git] / winery / org.eclipse.winery.topologymodeler / src / main / webapp / js / winery-common.js
1 /*******************************************************************************
2  * Copyright (c) 2012-2013 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
8  *
9  * Contributors:
10  *    Oliver Kopp - initial API and implementation and/or initial documentation
11  *******************************************************************************/
12
13 /**
14 This .js file is shared between the Winery Repository and the Winery Topology Modeler
15
16 This should be rewritten as AMD module. A start is made in winery-support-common.js.
17
18 vConfirmYesNo is defined in jsp/shared/dialogs.jsp
19 */
20
21 /**
22  * Highlights fields, which are required but not filled out by the user.
23  * The check for required fields is done via the CSS class "required"
24  *
25  * @return true if a required field is not filled with a value
26  */
27 function highlightRequiredFields() {
28         var requiredFieldMissing = false;
29         // includes check input field attribute "required" of HTML5: http://www.w3.org/TR/html-markup/input.radio.html#input.radio.attrs.required
30         $("input.required:visible:enabled, input[required]:visible").each(function(){
31                 if ($(this).val() == '') {
32                         $(this).parent().addClass('has-warning');
33                         requiredFieldMissing = true;
34                 } else {
35                         $(this).parent().removeClass('has-warning');
36                 }
37         });
38         return requiredFieldMissing;
39 }
40
41 function vPnotify(text, title, type) {
42         require(["pnotify"], function() {
43                 var notice = $.pnotify({
44                         title: title,
45                         text: text,
46                         type: type
47                 });
48                 notice.on("click", function(e) {
49                         var target = $(e.target);
50                         if (target.is(".ui-pnotify-closer *, .ui-pnotify-sticker *, a")) {
51                                 // buttons clicked - call their functionality
52                                 return true;
53                         } else {
54                                 // click on text leads to display of a dialog showing the complete content
55
56                                 var textDiv;
57                                 if (target.is("div.ui-pnotify-text")) {
58                                         textDiv = target;
59                                 } else {
60                                         textDiv = target.closest("div.ui-pnotify-container").find("div.ui-pnotify-text");
61                                 }
62
63                                 // put text into dialog and show it
64                                 $("#diagmessagetitle").text("Full notification");
65                                 $("#diagmessagemsg").html(textDiv.html());
66                                 $("#diagmessage").modal("show");
67
68                                 return false;
69                         }
70                 });
71         });
72 }
73
74 /**
75  * @param title optional title
76  */
77 function vShowError(text, title) {
78         vPnotify(text, title, "error");
79 }
80
81 function vShowAJAXError(msg, jqXHR, errorThrown) {
82         vShowError(msg + "<br />" + errorThrown + "<br/>" + jqXHR.responseText);
83 }
84
85 /**
86  * @param title optional title
87  */
88 function vShowNotification(text, title) {
89         vPnotify(text, title, "notification");
90 }
91
92
93 /**
94  * @param title optional title
95  */
96 function vShowSuccess(text, title) {
97         vPnotify(text, title, "success");
98 }
99
100 /**
101  * Deletes the given resource with confirmation.
102  * if deletion fails, an error message is shown
103  *
104  * @param onSuccess: function(data, textStatus, jqXHR) to call if deletion has been successful
105  * @param onError: function(jqXHR, textStatus, errorThrown) called if deletion lead to an error (optional)
106  * @param onStart: function() called if user has agreed to delete resource (optional)
107  * @param withoutConfirmation if given, the resource is deleted without any confirmation
108  */
109 function deleteResource(nameOfResource, url, onSuccess, onError, onStart, withoutConfirmation) {
110         var f = function() {
111                 $.ajax({
112                         url:  url,
113                         type: 'DELETE',
114                         async: true,
115                         error: function(jqXHR, textStatus, errorThrown) {
116                                 vShowAJAXError("Could not delete " + nameOfResource, jqXHR, errorThrown);
117                                 if (onError) onError();
118                         },
119                         success: function(data, textStatus, jqXHR) {
120                                 vShowSuccess("Successfully deleted " + nameOfResource);
121                                 onSuccess(data, textStatus, jqXHR);
122                         }
123                 });
124         };
125         if (withoutConfirmation) {
126                 f();
127         } else {
128                 vConfirmYesNo("Do you really want to delete " + nameOfResource + "?", f);
129         }
130 }
131
132 /**
133  * Function to create a td with two columns: one for a key and one for a value
134  *
135  * Has to be called from a td element: This function uses $(this) to determine the td
136  * It changes the content of the td to an input field. In case the input was updated, it is POSTed to the given URL
137  *
138  * TODO: The editing mode should use x-editable instead of a self-written input handling
139  *
140  * @param url the URL to post the key/value pair to
141  * @param keyName the keyname of the key - used at POST with <keyName>=<newKey>
142  * @param valueName the keyname of the value - used at POST with <valueName>=<newValue>
143  *
144  */
145 function vCreateTdClickFunction(url, keyName, valueName) {
146         var inputId = "thingedit" + Math.floor((Math.random()*100)+1); ;
147         keyName = keyName || "key";
148         valueName = valueName || "value";
149
150         var f = function(e) {
151                 var input = $("#" + inputId);
152                 if (input.length != 0) {
153                         // input field already there
154                         return;
155                 }
156
157                 var td = $(this);
158                 var oldPrefix = td.text();
159                 var html =  "<input id='" + inputId + "' value='" + oldPrefix + "'></input>";
160                 td.html(html);
161
162                 // new field generated, has to be looked up
163                 input = $("#" + inputId);
164
165                 input.keydown(function(e) {
166                         if (e.keyCode == 27) {
167                                 // ESC key pressed
168                                 input.off("blur");
169                                 td.html(oldPrefix);
170                         } else if (e.keyCode == 13) {
171                                 // enter key pressed
172                                 input.trigger("blur");
173                         }
174                 });
175
176                 input.focus();
177
178                 input.on("blur", function() {
179                         var newPrefix = input.val();
180                         if (newPrefix == oldPrefix) {
181                                 td.html(newPrefix);
182                         } else {
183                                 var namespace = td.next().text();
184                                 newPrefixEscaped = escape(newPrefix);
185                                 namespaceEscaped = escape(namespace);
186                                 var data = keyName + "=" + newPrefixEscaped + "&" + valueName + "=" + namespaceEscaped;
187                                 $.ajax({
188                                         url: url,
189                                         type: "POST",
190                                         async: false,
191                                         data: data,
192                                         error: function(jqXHR, textStatus, errorThrown) {
193                                                 vShowAJAXError("Could not update data", jqXHR, errorThrown);
194                                                 input.focus();
195                                         },
196                                         success: function(data, textSTatus, jqXHR) {
197                                                 vShowSuccess("Successfully updated data");
198                                                 td.html(newPrefix);
199                                         }
200                                 });
201                         }
202                 });
203         };
204
205         return f;
206 }
207
208 /**
209  * This function is also availble at winery-support-common.js
210  * This function here is due to legacy reasons and all callers should move to winery-support-common.js
211  *
212  * @param qname a QName in the form {namespace}localname
213  * @return { namespace: namespace, localname: localname }
214  */
215 function getNamespaceAndLocalNameFromQName(qname) {
216         var i = qname.indexOf("}");
217         var res = {
218                 namespace : qname.substr(1,i-1),
219                 localname : qname.substr(i+1)
220         };
221         return res;
222 }
223
224 /**
225  * Converts a QName of the form {namespace}id to the form prefix:id
226  * with a lookup of the prefix in the element
227  *
228  * returns wrong data if prefix wsa not found
229  */
230 function getQNameOutOfFullQName(fullQname, element) {
231         var nsAndId = getNamespaceAndLocalNameFromQName(fullQname);
232         var prefix = element.lookupPrefix(nsAndId.namespace);
233         var qname = prefix + ":" + nsAndId.localname;
234         return qname;
235 }
236
237 /**
238  * Converts a QName of the form prefix:id to the form {namespace}id
239  * with a lookup of the prefix in the element
240  *
241  * Currently not used anywhere
242  */
243 function getFullQNameOutOfQName(qname, element) {
244         var i = qname.indexOf(":");
245         var prefix = qname.substr(0,i-1);
246         var localname = qname.substr(i+1);
247         var namespace = element.lookupPrefix(prefix);
248         return "{" + namespace + "}" + localname;
249 }
250
251 function encodeID(id) {
252         // the URL sent to the server should be the encoded id
253         id = encodeURIComponent(id);
254         // therefore, we have to encode it twice
255         id = encodeURIComponent(id);
256         return id;
257 }
258
259 // URLs from QName are provided by winery-support-common.js
260 function makeArtifactTemplateURL(repoURL, namespace, id) {
261         return repoURL + "/artifacttemplates/" + encodeID(namespace) + "/" + encodeID(id) + "/";
262 }
263
264 if (!window.winery) window.winery = {};
265 window.winery.BOOTSTRAP_ANIMATION_DURATION = 400;