blob: 7c40daa03b54d9bdb1c96acc45992acf098be28f [file] [log] [blame]
Felix Meschberger26444e22010-02-21 16:45:55 +00001/*
2 * Licensed to the Apache Software Foundation (ASF) under one or more
3 * contributor license agreements. See the NOTICE file distributed with
4 * this work for additional information regarding copyright ownership.
5 * The ASF licenses this file to You under the Apache License, Version 2.0
6 * (the "License"); you may not use this file except in compliance with
7 * the License. You may obtain a copy of the License at
8 *
9 * http://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
16 */
17
18var repoTable = false;
19var repoTableTemplate = false;
20var addRepoUri = false;
21var resTable = false;
22var searchField = false;
Felix Meschberger80943442010-03-03 12:48:20 +000023var ifStatusOK = false;
Felix Meschberger26444e22010-02-21 16:45:55 +000024
Guillaume Nodet65c01e92010-03-04 20:53:59 +000025//This prototype is provided by the Mozilla foundation and
26//is distributed under the MIT license.
27//http://www.ibiblio.org/pub/Linux/LICENSES/mit.license
28if (!Array.prototype.map)
29{
30 Array.prototype.map = function(fun /*, thisp*/)
31 {
32 var len = this.length;
33 if (typeof fun != "function")
34 throw new TypeError();
35
36 var res = new Array(len);
37 var thisp = arguments[1];
38 for (var i = 0; i < len; i++)
39 {
40 if (i in this)
41 res[i] = fun.call(thisp, this[i], i, this);
42 }
43
44 return res;
45 };
46}
47
Guillaume Nodet6ec586e2010-03-10 17:37:43 +000048var uid = 0;
49function guid() {
50 uid = uid + 1;
51 return (0x10000 + uid).toString(16).substring(1) + (((1+Math.random())*0x10000)|0).toString(16).substring(1);
52}
53
Felix Meschberger26444e22010-02-21 16:45:55 +000054/* displays a date in the user's local timezone */
55function localTm(time) {
Felix Meschbergerf952a772010-08-11 06:53:08 +000056 return (time ? new Date(time) : new Date()).toLocaleString();
Felix Meschberger26444e22010-02-21 16:45:55 +000057}
58
59function doRepoAction(action, url) {
Felix Meschbergerf952a772010-08-11 06:53:08 +000060 if ( !url ) {
61 Xalert('Invalid URI: ' + url, 'Error');
62 } else {
63 $.post(pluginRoot, {
64 'action' : action,
65 'url' : url
66 }, renderData, 'json');
67 }
Felix Meschberger26444e22010-02-21 16:45:55 +000068}
69
Guillaume Nodet65c01e92010-03-04 20:53:59 +000070function showDetails( symbolicname, version ) {
Felix Meschbergerc7581ac2010-03-23 13:50:55 +000071 window.location.href = pluginRoot + '/' + symbolicname + '/' + version;
Guillaume Nodet65c01e92010-03-04 20:53:59 +000072}
73
74function showVersions( symbolicname ) {
Felix Meschbergerf952a772010-08-11 06:53:08 +000075 var _id = symbolicname.replace(/\./g, '_');
Guillaume Nodet65c01e92010-03-04 20:53:59 +000076 $("#block" + _id).append("<div id='pluginInlineVersions" + _id + "' style='margin-left: 4em'><ul/></div>");
77 $("#img" + _id).each(function() {
78 $(this).
79 removeClass('ui-icon-triangle-1-e').//right
80 addClass('ui-icon-triangle-1-s');//down
81 });
82 $("#entry" + _id).each(function() {
83 $(this).
84 unbind('click').
85 click(function() {hideVersions(symbolicname)}).
86 attr("title", "Hide Versions");
87 });
88 var versions = [];
89 for (var i in obrData.resources ) {
90 if (obrData.resources[i].symbolicname == symbolicname) {
91 versions.push(obrData.resources[i].version);
92 }
93 }
94 versions.sort();
95 for (var i in versions) {
96 var txt = "<li><a href='javascript: showDetails(\"" + symbolicname + "\",\"" + versions[i] + "\")'>" + versions[i] + "</a></li>";
97 $("#pluginInlineVersions" + _id + " > ul").append(txt);
98 }
99}
100
101function hideVersions( symbolicname ) {
Felix Meschbergerf952a772010-08-11 06:53:08 +0000102 var _id = symbolicname.replace(/\./g, '_');
Guillaume Nodet65c01e92010-03-04 20:53:59 +0000103 $("#img" + _id).each(function() {
104 $(this).
105 removeClass('ui-icon-triangle-1-s').//down
106 addClass('ui-icon-triangle-1-e');//right
107 });
108 $("#pluginInlineVersions" + _id).each(function() {
109 $(this).
110 remove();
111 });
112 $("#entry" + _id).each(function() {
113 $(this).
114 unbind('click').
115 click(function() {showVersions(symbolicname)}).
116 attr("title", "Show Versions");
117 });
118}
119
Felix Meschberger26444e22010-02-21 16:45:55 +0000120function renderResource(res) {
Felix Meschbergerf952a772010-08-11 06:53:08 +0000121 // proceed with resource
122 var _id = res.symbolicname.replace(/\./g, '_');
123 var _tr = resTable.find('#row' + _id);
Felix Meschberger26444e22010-02-21 16:45:55 +0000124
Felix Meschbergerf952a772010-08-11 06:53:08 +0000125 if (_tr.length == 0) { // not created yet, create it
126 var blockElement = createElement('span', '', {
Guillaume Nodet65c01e92010-03-04 20:53:59 +0000127 id: 'block' + _id
Felix Meschbergerf952a772010-08-11 06:53:08 +0000128 });
Guillaume Nodet65c01e92010-03-04 20:53:59 +0000129 var titleElement = createElement('span', '', {
130 id: 'entry' + _id,
131 title: "Show Versions"
132 });
133 var inputElement = createElement('span', 'ui-icon ui-icon-triangle-1-e', {
134 id: 'img' + _id,
135 style: {display: "inline-block"}
136 });
137 blockElement.appendChild(titleElement);
138 titleElement.appendChild(inputElement);
139 titleElement.appendChild(text(" "));
140 titleElement.appendChild(text(res.presentationname ? res.presentationname : res.symbolicname));
141 $(titleElement).click(function() {showVersions(res.symbolicname)});
142
Felix Meschbergerf952a772010-08-11 06:53:08 +0000143 _tr = tr( null, { 'id' : 'row' + _id } , [
144 td( null, null, [ blockElement ] ),
145 td( null, null, [ text(res.installed ? res.version : '') ] )
146 ]);
147 resTable.append( _tr );
148 }
Felix Meschberger26444e22010-02-21 16:45:55 +0000149}
150
Guillaume Nodet65c01e92010-03-04 20:53:59 +0000151function getCapabilitiesByName(res, name) {
152 var caps = [];
153 for (var v in res.capabilities) {
154 if (res.capabilities[v].name == name) {
155 caps.push(res.capabilities[v]);
156 }
157 }
158 return caps;
159}
160
161function getRequirementsByName(res, name) {
162 var caps = [];
163 for (var v in res.requirements) {
164 if (res.requirements[v].name == name) {
165 caps.push(res.requirements[v]);
166 }
167 }
168 return caps;
169}
170
171function createDetailedTable(enclosing, name, headers, rows, callback) {
172 if (rows && rows.length > 0) {
Guillaume Nodet6ec586e2010-03-10 17:37:43 +0000173 var uuid = guid();
Guillaume Nodet65c01e92010-03-04 20:53:59 +0000174 var title = createElement('span', null, null, [
175 createElement('span', 'ui-icon ui-icon-triangle-1-e', { id: "img"+uuid, style: {display: "inline-block"} }),
176 text(" "),
177 text(name)
178 ]);
179 enclosing.append(tr(null, null, [
180 td(null, null, [ title ]),
181 td(null, null, [ createElement('table', 'nicetable ui-widget ui-helper-hidden', { id: "alt1"+uuid }, [
182 createElement('thead', null, null, [
183 tr(null, null, headers.map(function(x) {
184 return th('ui-widget-header', null, [text(x)]);
185 }))
186 ]),
187 createElement('tbody', null, null,
188 rows.map(function(x) {
189 var values = callback(x);
190 var tds = values.map(function(x) {
191 return td(null, null, [x]);
192 });
193 return tr(null, null, tds);
194 })
195 )
196 ]),
197 createElement('span', null, { id: "alt2"+uuid }, [
198 text(rows.length)
199 ])
200 ])
201 ]));
202 $(title).
203 unbind('click').
204 click(function(event) {
205 event.preventDefault();
206 $("#img"+uuid).toggleClass('ui-icon-triangle-1-s').//down
207 toggleClass('ui-icon-triangle-1-e');//right
208 $("#alt1"+uuid).toggle();
209 $("#alt2"+uuid).toggle();
210 });
211 }
212}
213
214function trim(stringToTrim) {
Felix Meschbergerf952a772010-08-11 06:53:08 +0000215 return stringToTrim.replace(/^\s+|\s+$/g,"");
Guillaume Nodet65c01e92010-03-04 20:53:59 +0000216}
217
218function parseSimpleFilter(filter) {
219 filter = filter.substring(1, filter.length-1);
220 var start = 0;
221 var pos = 0;
222 var c = filter.charAt(pos);
223 while (c != '~' && c != '<' && c != '>' && c != '=' && c != '(' && c != ')') {
224 if (c == '<' && filterChars[pos+1] == '*') {
225 break;
226 }
227 if (c == '*' && filterChars[pos+1] == '>') {
228 break;
229 }
230 pos++;
231 c = filter.charAt(pos);
232 }
233 if (pos == start) {
234 throw ("Missing attr: " + filter.substring(pos));
235 }
236
237 var attr = trim(filter.substring(start, pos));
238 var oper = filter.substring(pos, pos+2);
239 var value;
240 if (oper == '*>' || oper == '~=' || oper == '>=' || oper == '<=' || oper == '<*') {
241 value = trim(filter.substring(pos+2));
242 if (value == '') {
243 throw ("Missing value: " + filter.substring(pos));
244 }
245
246 return { operator: oper, operands: [ attr, value ]};
247 } else {
248 if (c != '=') {
249 throw ("Invalid operator: " + filter.substring(pos));
250 }
251 oper = '=';
252 value = filter.substring(pos+1);
253 if (value == '*' ) {
254 return { operator: '=*', operands: [ attr ]};
255 }
256 return { operator: '=', operands: [ attr, value ]};
257 }
258}
259
260function parseFilter(filter) {
261 if (filter.charAt(0) != "(" || filter.charAt(filter.length-1) != ")") {
262 throw "Wrong parenthesis: " + filter;
263 }
264 if (filter.charAt(1) == "!") {
265 return { operator: filter.charAt(1), operands: [ parseFilter(filter.substring(2, filter.length-1)) ] };
266 }
267 if (filter.charAt(1) == "|" || filter.charAt(1) == "&") {
268 var inner = filter.substring(2, filter.length-1);
269 var flts = inner.match(/\([^\(\)]*(\([^\(\)]*(\([^\(\)]*(\([^\(\)]*\))*[^\(\)]*\))*[^\(\)]*\))*[^\(\)]*\)/g);
270 return { operator: filter.charAt(1), operands: flts.map(function(x) { return parseFilter(x); }) };
271 }
272 return parseSimpleFilter(filter);
273}
274
275function simplify(filter) {
276 if (filter.operator == '&' || filter.operator == '|') {
277 filter.operands = filter.operands.map(function(x) { return simplify(x); });
278 } else if (filter.operator == '!') {
279 if (filter.operands[0].operator == '<=') {
280 filter.operator = '>';
281 filter.operands = filter.operands[0].operands;
282 } else if (filter.operands[0].operator == '>=') {
283 filter.operator = '<';
284 filter.operands = filter.operands[0].operands;
285 }
286 }
287 return filter;
288}
289
290function addRow(tbody, key, value) {
291 if (value) {
292 tbody.append( tr(null, null, [
293 td(null, null, [ text(key) ]),
294 td(null, null, [ text(value) ])
295 ]));
296 }
297}
298
299function renderDetailedResource(res) {
300 var tbody = $('#detailsTableBody');
301
302 tbody.append( tr(null, null, [
303 th('ui-widget-header', null, [
304 text("Resource")
305 ]),
306 th('ui-widget-header', null, [
307 createElement('form', 'button-group', { method: "post"}, [
308 createElement('input', null, { type: "hidden", name: "bundle", value: res.id}),
309 createElement('input', 'ui-state-default ui-corner-all', { type: "submit", name: "deploy", value: "Deploy" }, [ text("dummy")]),
Guillaume Nodet6ec586e2010-03-10 17:37:43 +0000310 createElement('input', 'ui-state-default ui-corner-all', { type: "submit", name: "deploystart", value: "Deploy and Start" }, [ text("dummy")]),
Guillaume Nodet65c01e92010-03-04 20:53:59 +0000311 text(" "),
312 createElement('input', 'ui-state-default ui-corner-all', { id: "optional", type: "checkbox", name: "optional" }),
313 text(" "),
Guillaume Nodet6ec586e2010-03-10 17:37:43 +0000314 createElement('label', 'ui-widget', { 'for': "optional" }, [ text("deploy optional dependencies") ])
Guillaume Nodet65c01e92010-03-04 20:53:59 +0000315 ])
316 ])
317 ]));
318
319 addRow(tbody, "Name", res.presentationname);
320 addRow(tbody, "Description", res.description);
321 addRow(tbody, "Symbolic name", res.symbolicname);
322 addRow(tbody, "Version", res.version);
323 addRow(tbody, "URI", res.uri);
324 addRow(tbody, "Documentation", res.documentation);
325 addRow(tbody, "Javadoc", res.javadoc);
326 addRow(tbody, "Source", res.source);
327 addRow(tbody, "License", res.license);
328 addRow(tbody, "Copyright", res.copyright);
329 addRow(tbody, "Size", res.size);
330
331 // Exported packages
332 createDetailedTable(tbody, "Exported packages", ["Package", "Version"],
333 getCapabilitiesByName(res, "package").sort(function(a,b) {
334 var pa = a.properties['package'], pb = b.properties['package']; return pa == pb ? 0 : pa < pb ? -1 : +1;
335 }),
336 function(p) {
337 return [ text(p.properties['package']), text(p.properties['version']) ];
338 });
339 // Exported services
340 createDetailedTable(tbody, "Exported services", ["Service"], getCapabilitiesByName(res, "service"), function(p) {
341 return [ text(p.properties['service']) ];
342 });
343 // Imported packages
344 createDetailedTable(tbody, "Imported packages", ["Package", "Version", "Optional"], getRequirementsByName(res, "package"), function(p) {
345 var f = parseFilter(p.filter);
346 simplify(f);
347 var n, vmin = "[0.0.0", vmax = "infinity)";
348 if (f.operator == '&') {
349 for (var i in f.operands) {
350 var fi = f.operands[i];
351 if (fi.operands[0] == 'package' && fi.operator == '=') {
352 n = fi.operands[1];
353 }
354 if (fi.operands[0] == 'version') {
355 if (fi.operator == '>=') {
356 vmin = '[' + fi.operands[1];
357 }
358 if (fi.operator == '>') {
359 vmin = '(' + fi.operands[1];
360 }
361 if (fi.operator == '<=') {
362 vmax = fi.operands[1] + "]";
363 }
364 if (fi.operator == '<') {
365 vmax = fi.operands[1] + ")";
366 }
367 }
368 }
369 }
370 return [ text(n ? n : p.filter), text(vmin + ", " + vmax), text(p.optional) ];
371 });
372 // Imported bundles
373 createDetailedTable(tbody, "Imported bundles", ["Bundle", "Version", "Optional"], getRequirementsByName(res, "bundle"), function(p) {
374 return [ text(p.filter), text(""), text(p.optional) ];
375 });
376 // Imported services
Guillaume Nodet6ec586e2010-03-10 17:37:43 +0000377 createDetailedTable(tbody, "Imported services", ["Service", "Optional"], getRequirementsByName(res, "service"), function(p) {
Guillaume Nodet65c01e92010-03-04 20:53:59 +0000378 return [ text(p.filter), text(p.optional) ];
379 });
380 // Required dependencies
381 createDetailedTable(tbody, "Dependencies", ["Name", "Version"], res.required, function(p) {
Felix Meschbergerc7581ac2010-03-23 13:50:55 +0000382 var a = createElement('a', null, { href: (pluginRoot + '/' + p.symbolicname + '/' + p.version) });
Guillaume Nodet65c01e92010-03-04 20:53:59 +0000383 a.appendChild(text(p.presentationname ? p.presentationname : p.symbolicname));
384 return [ a, text(p.version) ];
385 });
386 // Optional dependencies
387 createDetailedTable(tbody, "Optional Dependencies", ["Name", "Version"], res.optional, function(p) {
Felix Meschbergerc7581ac2010-03-23 13:50:55 +0000388 var a = createElement('a', null, { href: (pluginRoot + '/' + p.symbolicname + '/' + p.version) });
Guillaume Nodet65c01e92010-03-04 20:53:59 +0000389 a.appendChild(text(p.presentationname ? p.presentationname : p.symbolicname));
390 return [ a, text(p.version) ];
391 });
392 // Unsatisfied requirements
393 createDetailedTable(tbody, "Unsatisfied Requirements", ["Requirement", "Optional"], res.unsatisfied, function(p) {
394 return [ text(p.filter), text(p.optional) ];
395 });
396
397// $('#detailsTableBody').append( tr(null, null, [ th('ui-widget-header', { colspan: 2 }, [ text("Resource") ]) ]) );
398// $('#detailsTableBody').append( tbody );
399}
400
Felix Meschberger26444e22010-02-21 16:45:55 +0000401function renderRepository(repo) {
Felix Meschbergerf952a772010-08-11 06:53:08 +0000402 var _tr = repoTableTemplate.clone();
403 _tr.find('td:eq(0)').text( repo.name );
404 _tr.find('td:eq(1)').text( repo.url );
405 _tr.find('td:eq(2)').text( localTm(repo.lastModified) );
406 _tr.find('li:eq(0)').click(function() {
407 doRepoAction('refresh', repo.url);
408 });
409 _tr.find('li:eq(1)').click(function() {
410 doRepoAction('delete', repo.url);
411 });
412 repoTable.append(_tr);
Felix Meschberger26444e22010-02-21 16:45:55 +0000413}
414
Guillaume Nodet65c01e92010-03-04 20:53:59 +0000415function renderData() {
Felix Meschbergerf952a772010-08-11 06:53:08 +0000416 repoTable.empty();
417 resTable.empty();
418 if ( obrData.status ) {
419 $('.statline').html(i18n.status_ok);
420 ifStatusOK.removeClass('ui-helper-hidden');
421 for (var i in obrData.repositories ) {
422 renderRepository( obrData.repositories[i] );
423 }
424 if (obrData.details) {
425 $('#resTable').addClass('ui-helper-hidden');
426 $('#detailsTable').removeClass('ui-helper-hidden');
427 for (var i in obrData.resources ) {
428 renderDetailedResource( obrData.resources[i] );
429 }
430 } else {
431 for (var i in obrData.resources ) {
432 renderResource( obrData.resources[i] );
433 }
434 }
435 } else {
436 $('.statline').html(i18n.status_no);
437 ifStatusOK.addClass('ui-helper-hidden');
438 }
Felix Meschberger26444e22010-02-21 16:45:55 +0000439}
440
Guillaume Nodet65c01e92010-03-04 20:53:59 +0000441
442$.extend({
443 getUrlVars: function(){
444 var vars = [], hash;
445 var hashes = window.location.href.slice(window.location.href.indexOf('?') + 1).split('&');
446 for(var i = 0; i < hashes.length; i++)
447 {
448 var j = hashes[i].indexOf('=');
449 if (j > 0) {
450 var k = hashes[i].slice(0, j);
451 var v = hashes[i].slice(j + 1);
452 vars.push(k);
453 vars[k] = v;
454 } else {
455 vars.push(hashes[i]);
456 vars[hashes[i]] = true;
457 }
458 }
459 return vars;
460 },
461 getUrlVar: function(name){
462 return $.getUrlVars()[name];
463 }
464});
465
Felix Meschberger26444e22010-02-21 16:45:55 +0000466$(document).ready( function() {
Felix Meschbergerf952a772010-08-11 06:53:08 +0000467 repoTable = $('#repoTable tbody');
468 repoTableTemplate = repoTable.find('tr').clone();
469 addRepoUri = $('#addRepoUri');
470 resTable = $('#resTable tbody').empty();
471 searchField = $('#searchField');
472 ifStatusOK = $('#ifStatusOK');
473
474 var query = $.getUrlVar('query');
475 if (query) {
Felix Meschbergerc7581ac2010-03-23 13:50:55 +0000476 searchField.val(decodeURIComponent(query));
477 }
Felix Meschberger26444e22010-02-21 16:45:55 +0000478
Felix Meschbergerf952a772010-08-11 06:53:08 +0000479 $('#addRepoBtn').click(function(event) {
Guillaume Nodet65c01e92010-03-04 20:53:59 +0000480 event.preventDefault();
Felix Meschbergerf952a772010-08-11 06:53:08 +0000481 doRepoAction('add', addRepoUri.val());
482 });
483 $('#searchBtn').click(function(event) {
Guillaume Nodet65c01e92010-03-04 20:53:59 +0000484 event.preventDefault();
Felix Meschbergerc7581ac2010-03-23 13:50:55 +0000485 window.location.href = pluginRoot + '?query=' + encodeURIComponent(searchField.val());
Felix Meschbergerf952a772010-08-11 06:53:08 +0000486 });
487 searchField.keypress(function(event) {
Guillaume Nodet65c01e92010-03-04 20:53:59 +0000488 if (event.keyCode == 13) {
489 event.preventDefault();
490 $('#searchBtn').click();
491 }
Felix Meschbergerf952a772010-08-11 06:53:08 +0000492 });
Felix Meschberger26444e22010-02-21 16:45:55 +0000493
Felix Meschbergerf952a772010-08-11 06:53:08 +0000494 renderData();
Guillaume Nodet65c01e92010-03-04 20:53:59 +0000495 initStaticWidgets();
496});
497