blob: 3b2c9fc40f849ce3fbfeb03a28f7b01d1e9d7048 [file] [log] [blame]
Felix Meschbergerf15dc7a2010-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 Meschberger98f1be02010-03-03 12:48:20 +000023var ifStatusOK = false;
Felix Meschbergerf15dc7a2010-02-21 16:45:55 +000024
Guillaume Nodete00edeb2010-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
Felix Meschbergerf15dc7a2010-02-21 16:45:55 +000048/* displays a date in the user's local timezone */
49function localTm(time) {
50 return (time ? new Date(time) : new Date()).toLocaleString();
51}
52
53function doRepoAction(action, url) {
54 if ( !url ) {
55 Xalert('Invalid URI: ' + url, 'Error');
56 } else {
57 $.post(pluginRoot, {
58 'action' : action,
59 'url' : url
60 }, renderData, 'json');
61 }
62}
63
Guillaume Nodete00edeb2010-03-04 20:53:59 +000064function showDetails( symbolicname, version ) {
65 window.location.href = window.location.pathname + '?details&symbolicname=' + symbolicname + '&version=' + version;
66}
67
68function showVersions( symbolicname ) {
69 var _id = symbolicname.replace(/\./g, '_');
70 $("#block" + _id).append("<div id='pluginInlineVersions" + _id + "' style='margin-left: 4em'><ul/></div>");
71 $("#img" + _id).each(function() {
72 $(this).
73 removeClass('ui-icon-triangle-1-e').//right
74 addClass('ui-icon-triangle-1-s');//down
75 });
76 $("#entry" + _id).each(function() {
77 $(this).
78 unbind('click').
79 click(function() {hideVersions(symbolicname)}).
80 attr("title", "Hide Versions");
81 });
82 var versions = [];
83 for (var i in obrData.resources ) {
84 if (obrData.resources[i].symbolicname == symbolicname) {
85 versions.push(obrData.resources[i].version);
86 }
87 }
88 versions.sort();
89 for (var i in versions) {
90 var txt = "<li><a href='javascript: showDetails(\"" + symbolicname + "\",\"" + versions[i] + "\")'>" + versions[i] + "</a></li>";
91 $("#pluginInlineVersions" + _id + " > ul").append(txt);
92 }
93}
94
95function hideVersions( symbolicname ) {
96 var _id = symbolicname.replace(/\./g, '_');
97 $("#img" + _id).each(function() {
98 $(this).
99 removeClass('ui-icon-triangle-1-s').//down
100 addClass('ui-icon-triangle-1-e');//right
101 });
102 $("#pluginInlineVersions" + _id).each(function() {
103 $(this).
104 remove();
105 });
106 $("#entry" + _id).each(function() {
107 $(this).
108 unbind('click').
109 click(function() {showVersions(symbolicname)}).
110 attr("title", "Show Versions");
111 });
112}
113
Felix Meschbergerf15dc7a2010-02-21 16:45:55 +0000114function renderResource(res) {
Felix Meschbergerf15dc7a2010-02-21 16:45:55 +0000115 // proceed with resource
116 var _id = res.symbolicname.replace(/\./g, '_');
Guillaume Nodete00edeb2010-03-04 20:53:59 +0000117 var _tr = resTable.find('#row' + _id);
Felix Meschbergerf15dc7a2010-02-21 16:45:55 +0000118
119 if (_tr.length == 0) { // not created yet, create it
Guillaume Nodete00edeb2010-03-04 20:53:59 +0000120 var blockElement = createElement('span', '', {
121 id: 'block' + _id
122 });
123 var titleElement = createElement('span', '', {
124 id: 'entry' + _id,
125 title: "Show Versions"
126 });
127 var inputElement = createElement('span', 'ui-icon ui-icon-triangle-1-e', {
128 id: 'img' + _id,
129 style: {display: "inline-block"}
130 });
131 blockElement.appendChild(titleElement);
132 titleElement.appendChild(inputElement);
133 titleElement.appendChild(text(" "));
134 titleElement.appendChild(text(res.presentationname ? res.presentationname : res.symbolicname));
135 $(titleElement).click(function() {showVersions(res.symbolicname)});
136
137 _tr = tr( null, { 'id' : 'row' + _id } , [
138 td( null, null, [ blockElement ] ),
Felix Meschbergerf15dc7a2010-02-21 16:45:55 +0000139 td( null, null, [ text(res.installed ? res.version : '') ] )
140 ]);
141 resTable.append( _tr );
Felix Meschbergerf15dc7a2010-02-21 16:45:55 +0000142 }
143}
144
Guillaume Nodete00edeb2010-03-04 20:53:59 +0000145function getCapabilitiesByName(res, name) {
146 var caps = [];
147 for (var v in res.capabilities) {
148 if (res.capabilities[v].name == name) {
149 caps.push(res.capabilities[v]);
150 }
151 }
152 return caps;
153}
154
155function getRequirementsByName(res, name) {
156 var caps = [];
157 for (var v in res.requirements) {
158 if (res.requirements[v].name == name) {
159 caps.push(res.requirements[v]);
160 }
161 }
162 return caps;
163}
164
165function createDetailedTable(enclosing, name, headers, rows, callback) {
166 if (rows && rows.length > 0) {
167 var uuid = jQuery.uuid();
168 var title = createElement('span', null, null, [
169 createElement('span', 'ui-icon ui-icon-triangle-1-e', { id: "img"+uuid, style: {display: "inline-block"} }),
170 text(" "),
171 text(name)
172 ]);
173 enclosing.append(tr(null, null, [
174 td(null, null, [ title ]),
175 td(null, null, [ createElement('table', 'nicetable ui-widget ui-helper-hidden', { id: "alt1"+uuid }, [
176 createElement('thead', null, null, [
177 tr(null, null, headers.map(function(x) {
178 return th('ui-widget-header', null, [text(x)]);
179 }))
180 ]),
181 createElement('tbody', null, null,
182 rows.map(function(x) {
183 var values = callback(x);
184 var tds = values.map(function(x) {
185 return td(null, null, [x]);
186 });
187 return tr(null, null, tds);
188 })
189 )
190 ]),
191 createElement('span', null, { id: "alt2"+uuid }, [
192 text(rows.length)
193 ])
194 ])
195 ]));
196 $(title).
197 unbind('click').
198 click(function(event) {
199 event.preventDefault();
200 $("#img"+uuid).toggleClass('ui-icon-triangle-1-s').//down
201 toggleClass('ui-icon-triangle-1-e');//right
202 $("#alt1"+uuid).toggle();
203 $("#alt2"+uuid).toggle();
204 });
205 }
206}
207
208function trim(stringToTrim) {
209 return stringToTrim.replace(/^\s+|\s+$/g,"");
210}
211
212function parseSimpleFilter(filter) {
213 filter = filter.substring(1, filter.length-1);
214 var start = 0;
215 var pos = 0;
216 var c = filter.charAt(pos);
217 while (c != '~' && c != '<' && c != '>' && c != '=' && c != '(' && c != ')') {
218 if (c == '<' && filterChars[pos+1] == '*') {
219 break;
220 }
221 if (c == '*' && filterChars[pos+1] == '>') {
222 break;
223 }
224 pos++;
225 c = filter.charAt(pos);
226 }
227 if (pos == start) {
228 throw ("Missing attr: " + filter.substring(pos));
229 }
230
231 var attr = trim(filter.substring(start, pos));
232 var oper = filter.substring(pos, pos+2);
233 var value;
234 if (oper == '*>' || oper == '~=' || oper == '>=' || oper == '<=' || oper == '<*') {
235 value = trim(filter.substring(pos+2));
236 if (value == '') {
237 throw ("Missing value: " + filter.substring(pos));
238 }
239
240 return { operator: oper, operands: [ attr, value ]};
241 } else {
242 if (c != '=') {
243 throw ("Invalid operator: " + filter.substring(pos));
244 }
245 oper = '=';
246 value = filter.substring(pos+1);
247 if (value == '*' ) {
248 return { operator: '=*', operands: [ attr ]};
249 }
250 return { operator: '=', operands: [ attr, value ]};
251 }
252}
253
254function parseFilter(filter) {
255 if (filter.charAt(0) != "(" || filter.charAt(filter.length-1) != ")") {
256 throw "Wrong parenthesis: " + filter;
257 }
258 if (filter.charAt(1) == "!") {
259 return { operator: filter.charAt(1), operands: [ parseFilter(filter.substring(2, filter.length-1)) ] };
260 }
261 if (filter.charAt(1) == "|" || filter.charAt(1) == "&") {
262 var inner = filter.substring(2, filter.length-1);
263 var flts = inner.match(/\([^\(\)]*(\([^\(\)]*(\([^\(\)]*(\([^\(\)]*\))*[^\(\)]*\))*[^\(\)]*\))*[^\(\)]*\)/g);
264 return { operator: filter.charAt(1), operands: flts.map(function(x) { return parseFilter(x); }) };
265 }
266 return parseSimpleFilter(filter);
267}
268
269function simplify(filter) {
270 if (filter.operator == '&' || filter.operator == '|') {
271 filter.operands = filter.operands.map(function(x) { return simplify(x); });
272 } else if (filter.operator == '!') {
273 if (filter.operands[0].operator == '<=') {
274 filter.operator = '>';
275 filter.operands = filter.operands[0].operands;
276 } else if (filter.operands[0].operator == '>=') {
277 filter.operator = '<';
278 filter.operands = filter.operands[0].operands;
279 }
280 }
281 return filter;
282}
283
284function addRow(tbody, key, value) {
285 if (value) {
286 tbody.append( tr(null, null, [
287 td(null, null, [ text(key) ]),
288 td(null, null, [ text(value) ])
289 ]));
290 }
291}
292
293function renderDetailedResource(res) {
294 var tbody = $('#detailsTableBody');
295
296 tbody.append( tr(null, null, [
297 th('ui-widget-header', null, [
298 text("Resource")
299 ]),
300 th('ui-widget-header', null, [
301 createElement('form', 'button-group', { method: "post"}, [
302 createElement('input', null, { type: "hidden", name: "bundle", value: res.id}),
303 createElement('input', 'ui-state-default ui-corner-all', { type: "submit", name: "deploy", value: "Deploy" }, [ text("dummy")]),
304 createElement('input', 'ui-state-default ui-corner-all', { type: "submit", name: "deploystart", value: "Start" }, [ text("dummy")]),
305 text(" "),
306 createElement('input', 'ui-state-default ui-corner-all', { id: "optional", type: "checkbox", name: "optional" }),
307 text(" "),
308 createElement('label', 'ui-widget', { 'for': "optional" }, [ text("optional") ])
309 ])
310 ])
311 ]));
312
313 addRow(tbody, "Name", res.presentationname);
314 addRow(tbody, "Description", res.description);
315 addRow(tbody, "Symbolic name", res.symbolicname);
316 addRow(tbody, "Version", res.version);
317 addRow(tbody, "URI", res.uri);
318 addRow(tbody, "Documentation", res.documentation);
319 addRow(tbody, "Javadoc", res.javadoc);
320 addRow(tbody, "Source", res.source);
321 addRow(tbody, "License", res.license);
322 addRow(tbody, "Copyright", res.copyright);
323 addRow(tbody, "Size", res.size);
324
325 // Exported packages
326 createDetailedTable(tbody, "Exported packages", ["Package", "Version"],
327 getCapabilitiesByName(res, "package").sort(function(a,b) {
328 var pa = a.properties['package'], pb = b.properties['package']; return pa == pb ? 0 : pa < pb ? -1 : +1;
329 }),
330 function(p) {
331 return [ text(p.properties['package']), text(p.properties['version']) ];
332 });
333 // Exported services
334 createDetailedTable(tbody, "Exported services", ["Service"], getCapabilitiesByName(res, "service"), function(p) {
335 return [ text(p.properties['service']) ];
336 });
337 // Imported packages
338 createDetailedTable(tbody, "Imported packages", ["Package", "Version", "Optional"], getRequirementsByName(res, "package"), function(p) {
339 var f = parseFilter(p.filter);
340 simplify(f);
341 var n, vmin = "[0.0.0", vmax = "infinity)";
342 if (f.operator == '&') {
343 for (var i in f.operands) {
344 var fi = f.operands[i];
345 if (fi.operands[0] == 'package' && fi.operator == '=') {
346 n = fi.operands[1];
347 }
348 if (fi.operands[0] == 'version') {
349 if (fi.operator == '>=') {
350 vmin = '[' + fi.operands[1];
351 }
352 if (fi.operator == '>') {
353 vmin = '(' + fi.operands[1];
354 }
355 if (fi.operator == '<=') {
356 vmax = fi.operands[1] + "]";
357 }
358 if (fi.operator == '<') {
359 vmax = fi.operands[1] + ")";
360 }
361 }
362 }
363 }
364 return [ text(n ? n : p.filter), text(vmin + ", " + vmax), text(p.optional) ];
365 });
366 // Imported bundles
367 createDetailedTable(tbody, "Imported bundles", ["Bundle", "Version", "Optional"], getRequirementsByName(res, "bundle"), function(p) {
368 return [ text(p.filter), text(""), text(p.optional) ];
369 });
370 // Imported services
371 createDetailedTable(tbody, "Imported bundles", ["Service", "Optional"], getRequirementsByName(res, "service"), function(p) {
372 return [ text(p.filter), text(p.optional) ];
373 });
374 // Required dependencies
375 createDetailedTable(tbody, "Dependencies", ["Name", "Version"], res.required, function(p) {
376 var a = createElement('a', null, { href: (window.location.pathname + '?details&symbolicname=' + p.symbolicname + '&version=' + p.version) });
377 a.appendChild(text(p.presentationname ? p.presentationname : p.symbolicname));
378 return [ a, text(p.version) ];
379 });
380 // Optional dependencies
381 createDetailedTable(tbody, "Optional Dependencies", ["Name", "Version"], res.optional, function(p) {
382 var a = createElement('a', null, { href: (window.location.pathname + '?details&symbolicname=' + p.symbolicname + '&version=' + p.version) });
383 a.appendChild(text(p.presentationname ? p.presentationname : p.symbolicname));
384 return [ a, text(p.version) ];
385 });
386 // Unsatisfied requirements
387 createDetailedTable(tbody, "Unsatisfied Requirements", ["Requirement", "Optional"], res.unsatisfied, function(p) {
388 return [ text(p.filter), text(p.optional) ];
389 });
390
391// $('#detailsTableBody').append( tr(null, null, [ th('ui-widget-header', { colspan: 2 }, [ text("Resource") ]) ]) );
392// $('#detailsTableBody').append( tbody );
393}
394
Felix Meschbergerf15dc7a2010-02-21 16:45:55 +0000395function renderRepository(repo) {
396 var _tr = repoTableTemplate.clone();
397 _tr.find('td:eq(0)').text( repo.name );
398 _tr.find('td:eq(1)').text( repo.url );
399 _tr.find('td:eq(2)').text( localTm(repo.lastModified) );
400 _tr.find('li:eq(0)').click(function() {
401 doRepoAction('refresh', repo.url);
402 });
403 _tr.find('li:eq(1)').click(function() {
404 doRepoAction('delete', repo.url);
405 });
406 repoTable.append(_tr);
Felix Meschbergerf15dc7a2010-02-21 16:45:55 +0000407}
408
Guillaume Nodete00edeb2010-03-04 20:53:59 +0000409function renderData() {
Felix Meschbergerf15dc7a2010-02-21 16:45:55 +0000410 repoTable.empty();
411 resTable.empty();
Guillaume Nodete00edeb2010-03-04 20:53:59 +0000412 if ( obrData.status ) {
Felix Meschbergerf15dc7a2010-02-21 16:45:55 +0000413 $('.statline').html(i18n.status_ok);
Felix Meschberger98f1be02010-03-03 12:48:20 +0000414 ifStatusOK.removeClass('ui-helper-hidden');
Guillaume Nodete00edeb2010-03-04 20:53:59 +0000415 for (var i in obrData.repositories ) {
416 renderRepository( obrData.repositories[i] );
417 }
418 if ($.getUrlVar('details')) {
419 $('#resTable').addClass('ui-helper-hidden');
420 $('#detailsTable').removeClass('ui-helper-hidden');
421 for (var i in obrData.resources ) {
422 renderDetailedResource( obrData.resources[i] );
423 }
424 } else {
425 for (var i in obrData.resources ) {
426 renderResource( obrData.resources[i] );
427 }
Felix Meschbergerf15dc7a2010-02-21 16:45:55 +0000428 }
429 } else {
430 $('.statline').html(i18n.status_no);
Felix Meschberger98f1be02010-03-03 12:48:20 +0000431 ifStatusOK.addClass('ui-helper-hidden');
Felix Meschbergerf15dc7a2010-02-21 16:45:55 +0000432 }
433}
434
Guillaume Nodete00edeb2010-03-04 20:53:59 +0000435
436$.extend({
437 getUrlVars: function(){
438 var vars = [], hash;
439 var hashes = window.location.href.slice(window.location.href.indexOf('?') + 1).split('&');
440 for(var i = 0; i < hashes.length; i++)
441 {
442 var j = hashes[i].indexOf('=');
443 if (j > 0) {
444 var k = hashes[i].slice(0, j);
445 var v = hashes[i].slice(j + 1);
446 vars.push(k);
447 vars[k] = v;
448 } else {
449 vars.push(hashes[i]);
450 vars[hashes[i]] = true;
451 }
452 }
453 return vars;
454 },
455 getUrlVar: function(name){
456 return $.getUrlVars()[name];
457 }
458});
459
Felix Meschbergerf15dc7a2010-02-21 16:45:55 +0000460$(document).ready( function() {
461 repoTable = $('#repoTable tbody');
462 repoTableTemplate = repoTable.find('tr').clone();
463 addRepoUri = $('#addRepoUri');
464 resTable = $('#resTable tbody').empty();
465 searchField = $('#searchField');
Felix Meschberger98f1be02010-03-03 12:48:20 +0000466 ifStatusOK = $('#ifStatusOK');
Guillaume Nodete00edeb2010-03-04 20:53:59 +0000467 searchField.val($.getUrlVar('query'));
Felix Meschbergerf15dc7a2010-02-21 16:45:55 +0000468
Guillaume Nodete00edeb2010-03-04 20:53:59 +0000469 $('#addRepoBtn').click(function(event) {
470 event.preventDefault();
Felix Meschbergerf15dc7a2010-02-21 16:45:55 +0000471 doRepoAction('add', addRepoUri.val());
472 });
Guillaume Nodete00edeb2010-03-04 20:53:59 +0000473 $('#searchBtn').click(function(event) {
474 event.preventDefault();
475 window.location.href = window.location.pathname + '?query=' + searchField.val();
476 });
477 searchField.keypress(function(event) {
478 if (event.keyCode == 13) {
479 event.preventDefault();
480 $('#searchBtn').click();
481 }
Felix Meschbergerf15dc7a2010-02-21 16:45:55 +0000482 });
483
Guillaume Nodete00edeb2010-03-04 20:53:59 +0000484 renderData();
485 initStaticWidgets();
486});
487