FELIX-1988 Apply 12.bundles_plugin.patch by Valentin Valchev (thanks)

git-svn-id: https://svn.apache.org/repos/asf/felix/trunk@911439 13f79535-47bb-0310-9956-ffa450edef68
diff --git a/webconsole/src/main/resources/res/ui/bundles.css b/webconsole/src/main/resources/res/ui/bundles.css
new file mode 100644
index 0000000..5824bd6
--- /dev/null
+++ b/webconsole/src/main/resources/res/ui/bundles.css
@@ -0,0 +1,28 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#optionalData {
+	margin: 0;
+	padding: 0;
+}
+
+ul.icons {margin: 0; padding: 0;}
+ul.icons li {margin: 1px; position: relative; padding: 1px 0; cursor: pointer; float: left;  list-style: none;}
+ul.icons span.ui-icon {float: left; margin: 0 1px;}
+
+.col_Status   { width: 50px;  }
+.col_Actions { width: 121px; }
diff --git a/webconsole/src/main/resources/res/ui/bundles.js b/webconsole/src/main/resources/res/ui/bundles.js
index cef5de4..2660b74 100644
--- a/webconsole/src/main/resources/res/ui/bundles.js
+++ b/webconsole/src/main/resources/res/ui/bundles.js
@@ -14,72 +14,57 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-function renderStatusLine() {
-	$("#plugin_content").append( "<div class='fullwidth'><div class='statusline'/></div>" );
-}
-
-function renderView( /* Array of String */ columns, /* String */ buttons ) {
-    renderStatusLine();
-    renderButtons(buttons);
-    var txt = "<div class='table'><table id='plugin_table' class='tablelayout'><thead><tr>";
-    for ( var name in columns ) {
-    	txt = txt + "<th class='col_" + columns[name] + "'>" + columns[name] + "</th>";
-    }
-    txt = txt + "</tr></thead><tbody></tbody></table></div>";
-    $("#plugin_content").append( txt );
-    renderButtons(buttons);
-    renderStatusLine();	
-}
-
-function renderButtons( buttons ) {
-	$("#plugin_content").append( "<form method='post' enctype='multipart/form-data'><div class='fullwidth'><div class='buttons'>" +
-	                             buttons + "</div></div></form>" );
-}
 
 function renderData( eventData )  {
-	$(".statusline").empty().append(eventData.status);
-	$("#plugin_table > tbody > tr").remove();
+	var s = eventData.s;
+    $(".statline").html(i18n.statline.msgFormat(s[0], s[1], s[2], s[3], s[4]));
+    $("#plugin_table > tbody > tr").remove();
     for ( var idx in eventData.data ) {
-    	if ( currentBundle == null || !drawDetails || currentBundle == eventData.data[idx].id) {
+        if ( currentBundle == null || !drawDetails || currentBundle == eventData.data[idx].id) {
             entry( eventData.data[idx] );
-    	}
+        }
     }
-    $("#plugin_table").trigger("update");
     if ( drawDetails && eventData.data.length == 1 ) {
-	    renderDetails(eventData.data[0]);    
+        renderDetails(eventData.data[0]);    
     } else if ( currentBundle != null ) {
-    	var id = currentBundle;
-    	hideDetails(id);
-    	showDetails(id);
+        var id = currentBundle;
+        hideDetails(id);
+        showDetails(id);
     }
+    initStaticWidgets();
 }
 
 function entry( /* Object */ dataEntry ) {
     var trElement = tr( null, { id: "entry" + dataEntry.id } );
     entryInternal( trElement,  dataEntry );
-	$("#plugin_table > tbody").append(trElement);	
+    $("#plugin_table > tbody").append(trElement);   
 }
 
 function actionButton( /* Element */ parent, /* string */ id, /* Obj */ action ) {
-	if ( !action.enabled ) {
-		return;
-	}
-	var enabled = action.enabled;
-	var op = action.link;
-	var opLabel = action.name;
-	var img = action.image;
-	
-	var input = createElement( "input", null, {
-            type: 'image',
-            style: {"margin-left": "10px"},
-            title: opLabel,
-            alt: opLabel,
-            src: imgRoot + '/bundle_' + img + '.png'
-        });
-	$(input).click(function() {changeDataEntryState(id, op)});
-		
+    if ( !action.enabled ) {
+        return;
+    }
+    var enabled = action.enabled;
+    var op = action.link;
+    var opLabel = action.name;
+    var img = action.image;
+    // fixup JQuery UI icons
+    if(img == "start" ) img = "play";
+    if(img == "update") img = "transferthick-e-w";
+    if(img == "delete") img = "trash";
+
+	// apply i18n
+	opLabel = i18n[opLabel] ? i18n[opLabel] : opLabel;
+    
+    var input = createElement('li', 'dynhover', {
+        title: opLabel
+    });
+    $(input)
+        .html('<span class="ui-icon ui-icon-'+img+'"></span>')
+        .click(function() {changeDataEntryState(id, op)});
+
     if (!enabled) {
-    	$(input).attr("disabled", true);
+        $(input).attr("disabled", true).addClass("ui-state-disabled");
     }
     parent.appendChild( input );
 }
@@ -88,23 +73,20 @@
     var id = dataEntry.id;
     var name = dataEntry.name;
     var state = dataEntry.state;
-    
-    var inputElement = createElement("img", "rightButton", {
-    	src: appRoot + "/res/imgs/arrow_right.png",
-    	style: {border: "none"},
-    	id: 'img' + id,
-    	title: "Details",
-    	alt: "Details",
-    	width: 14,
-    	height: 14
+
+    // right arrow
+    var inputElement = createElement('span', 'ui-icon ui-icon-triangle-1-e', {
+        title: "Details",
+        id: 'img' + id,
+        style: {display: "inline-block"}
     });
     $(inputElement).click(function() {showDetails(id)});
     var titleElement;
     if ( drawDetails ) {
-    	titleElement = text(name);
+        titleElement = text(name);
     } else {
         titleElement = createElement ("a", null, {
-    	    href: window.location.pathname + "/" + id
+            href: window.location.pathname + "/" + id
         });
         titleElement.appendChild(text(name));
     }
@@ -115,147 +97,126 @@
     parent.appendChild( td( null, null, [ text( dataEntry.symbolicName ) ] ) );
     parent.appendChild( td( null, null, [ text( state ) ] ) );
     var actionsTd = td( null, null );
-    var div = createElement("div", null, {
-    	style: { "text-align" : "left"}
-    });
+    var div = createElement('ul', 'icons ui-widget');
     actionsTd.appendChild(div);
     
     for ( var a in dataEntry.actions ) {
-    	actionButton( div, id, dataEntry.actions[a] );
+        actionButton( div, id, dataEntry.actions[a] );
     }
     parent.appendChild( actionsTd );
 }
 
 function loadData() {
-	$.get(pluginRoot + "/.json", null, function(data) {
-	    renderData(data);
-	}, "json");	
+    $.get(pluginRoot + "/.json", null, function(data) {
+        renderData(data);
+    }, "json"); 
 }
 
 function changeDataEntryState(/* long */ id, /* String */ action) {
-	$.post(pluginRoot + "/" + id, {"action":action}, function(data) {
-	    renderData(data);
-	}, "json");	
+    $.post(pluginRoot + "/" + id, {"action":action}, function(data) {
+        renderData(data);
+    }, "json"); 
 }
 
 function refreshPackages() {
-	$.post(window.location.pathname, {"action": "refreshPackages"}, function(data) {
-	    renderData(data);
-	}, "json");	
+    $.post(window.location.pathname, {"action": "refreshPackages"}, function(data) {
+        renderData(data);
+    }, "json"); 
 }
 
 function showDetails( id ) {
-	currentBundle = id;
+    currentBundle = id;
     $.get(pluginRoot + "/" + id + ".json", null, function(data) {
-    	renderDetails(data.data[0]);
+        renderDetails(data.data[0]);
     }, "json");
 }
 
 function hideDetails( id ) {
-	currentBundle = null;
-	$("#img" + id).each(function() {
-		$("#pluginInlineDetails" + id).remove();
-		$(this).attr("src", appRoot + "/res/imgs/arrow_right.png");
-		$(this).attr("title", "Details");
-		$(this).attr("alt", "Details");
-		$(this).unbind('click').click(function() {showDetails(id)});
-	});
+    currentBundle = null;
+    $("#img" + id).each(function() {
+        $("#pluginInlineDetails" + id).remove();
+        $(this).
+            removeClass('ui-icon-triangle-1-w').//left
+            removeClass('ui-icon-triangle-1-s').//down
+            addClass('ui-icon-triangle-1-e').//right
+            attr("title", "Details").
+            unbind('click').click(function() {showDetails(id)});
+    });
 }
 
 function renderDetails( data ) {
-	$("#entry" + data.id + " > td").eq(1).append("<div id='pluginInlineDetails"  + data.id + "'/>");
-	$("#img" + data.id).each(function() {
-		if ( drawDetails ) {
-			$(this).attr("src", appRoot + "/res/imgs/arrow_left.png");
-			$(this).attr("title", "Back");
-			$(this).attr("alt", "Back");
-    	    var ref = window.location.pathname;
-    	    ref = ref.substring(0, ref.lastIndexOf('/'));
-			$(this).unbind('click').click(function() {window.location = ref;});
-		} else {
-			$(this).attr("src", appRoot + "/res/imgs/arrow_down.png");
-			$(this).attr("title", "Hide Details");
-			$(this).attr("alt", "Hide Details");
-			$(this).unbind('click').click(function() {hideDetails(data.id)});
-		}
-	});
-	$("#pluginInlineDetails" + data.id).append("<table border='0'><tbody></tbody></table>");
+    $("#entry" + data.id + " > td").eq(1).append("<div id='pluginInlineDetails"  + data.id + "'/>");
+    $("#img" + data.id).each(function() {
+        if ( drawDetails ) {
+            var ref = window.location.pathname;
+            ref = ref.substring(0, ref.lastIndexOf('/'));
+            $(this).
+                removeClass('ui-icon-triangle-1-e').//right
+                removeClass('ui-icon-triangle-1-s').//down
+                addClass('ui-icon-triangle-1-w').//left
+                attr("title", "Back").
+                unbind('click').click(function() {window.location = ref});
+        } else {
+            $(this).
+                removeClass('ui-icon-triangle-1-w').//left
+                removeClass('ui-icon-triangle-1-e').//right
+                addClass('ui-icon-triangle-1-s').//down
+                attr("title", "Hide Details").
+                unbind('click').click(function() {hideDetails(data.id)});
+        }
+    });
+    $("#pluginInlineDetails" + data.id).append("<table border='0'><tbody></tbody></table>");
     var details = data.props;
     for (var idx in details) {
         var prop = details[idx];
-        
-        var txt = "<tr><td class='aligntop' noWrap='true' style='border:0px none'>" + prop.key + "</td><td class='aligntop' style='border:0px none'>";	        
+		var key = i18n[prop.key] ? i18n[prop.key] : prop.key;
+
+        var txt = "<tr><td class='aligntop' noWrap='true' style='border:0px none'>" + key + "</td><td class='aligntop' style='border:0px none'>";          
         if (prop.value) {
-        	if ( prop.key == 'Bundle Documentation' )  {
-        		txt = txt + "<a href='" + prop.value + "' target='_blank'>" + prop.value + "</a>";
-        	} else  {
-        		if ( $.isArray(prop.value) ) {
-	        		var i = 0;
-	        		for(var pi in prop.value) {
-	        			var value = prop.value[pi];
-		                if (i > 0) { txt = txt + "<br/>"; }
-		                var span;
-		                if (value.substring(0, 6) == "INFO: ") {
-		                	txt = txt + "<span style='color: grey;'>!!" + value.substring(5) + "</span>";
-		                } else if (value.substring(0, 7) == "ERROR: ") {
-		                	txt = txt + "<span style='color: red;'>!!" + value.substring(6) + "</span>";
-		                } else {
-		                	txt = txt + value;
-		                }
-		                i++;
-	        		}
-        		} else {
-        			txt = txt + prop.value;
-        		}
-        	}
+            if ( prop.key == 'Bundle Documentation' )  {
+                txt = txt + "<a href='" + prop.value + "' target='_blank'>" + prop.value + "</a>";
+            } else  {
+                if ( $.isArray(prop.value) ) {
+                    var i = 0;
+                    for(var pi in prop.value) {
+                        var value = prop.value[pi];
+                        if (i > 0) { txt = txt + "<br/>"; }
+                        txt = txt + value;
+                        i++;
+                    }
+                } else {
+                    txt = txt + prop.value;
+                }
+            }
         } else {
-        	txt = txt + "\u00a0";
+            txt = txt + "\u00a0";
         }
         txt = txt + "</td></tr>";
         $("#pluginInlineDetails" + data.id + " > table > tbody").append(txt);
-	}
+    }
 }
 
-function renderBundles(data) {
-	$(document).ready(function(){
-    	renderView( ["Id", "Name", "Version", "Symbolic Name", "Status", "Actions"],
-        		"<input type='hidden' name='action' value='install'/>" +
-        		"<input type='hidden' name='bundlestart' value='start'/>" +
-        		"<input type='hidden' name='bundlestartlevel' value='" + startLevel + "'/>" +
-                "<input class='fileinput' type='file' name='bundlefile' style='margin-left:10px'/>" +
-         		"<input type='submit' value='Install or Update' style='margin-left:10px'/>" +
-         		"<button class='reloadButton' type='button' name='reload' style='margin-left:60px'>Reload</button>" +
-         		"<button class='installButton' type='button' name='install'>Install/Update...</button>" +
-         		"<button class='refreshPackages' type='button' name='refresh'>Refresh Packages</button>"
-        		 );
-        $(".refreshPackages").click(refreshPackages);
-	    $(".reloadButton").click(loadData);
-	    $(".installButton").click(function() {
-	    	document.location = pluginRoot + "/upload";
-	    });
-        renderData(data);
-        
-        var extractMethod = function(node) {
-        	var link = node.getElementsByTagName("a");
-            if ( link && link.length == 1 ) {
-            	return link[0].innerHTML;
-            }
-            return node.innerHTML;
-        };
-        // check for cookie
-        var cv = $.cookies.get("webconsolebundlelist");
-        var lo = (cv ? cv.split(",") : [1,0]);
-        $("#plugin_table").tablesorter({
-            headers: {
-        	    0: { sorter:"digit"},
-                5: { sorter: false }
-            },
-            sortList: [lo],
-            textExtraction:extractMethod 
-        });
-        $("#plugin_table").bind("sortEnd", function() {
-        	var table = $("#plugin_table").eq(0).attr("config");
-        	$.cookies.set("webconsolebundlelist", table.sortList.toString());
-        });
-    });
-}
+$(document).ready(function(){
+	$(".refreshPackages").click(refreshPackages);
+	$(".reloadButton").click(loadData);
+	$(".installButton").click(function() {
+		document.location = pluginRoot + "/upload";
+	});
+	renderData(__bundles__);
+
+	// check for cookie
+	var cv = $.cookies.get("webconsolebundlelist");
+	var lo = (cv ? cv.split(",") : [1,0]);
+	$("#plugin_table").tablesorter({
+		headers: {
+			0: { sorter:"digit" },
+			5: { sorter: false }
+		},
+		textExtraction:mixedLinksExtraction,
+		sortList: cv ? [lo] : false
+	}).bind("sortEnd", function() {
+		var table = $("#plugin_table").eq(0).attr("config");
+		$.cookies.set("webconsolebundlelist", table.sortList.toString());
+	});
+});
+