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/OSGI-INF/l10n/bundle.properties b/webconsole/src/main/resources/OSGI-INF/l10n/bundle.properties
index b89c29f..20de138 100644
--- a/webconsole/src/main/resources/OSGI-INF/l10n/bundle.properties
+++ b/webconsole/src/main/resources/OSGI-INF/l10n/bundle.properties
@@ -35,7 +35,11 @@
 bundle=Bundle
 version=Version
 help=Help
-
+start=Start
+stop=Stop
+save=Save
+reset=Reset
+delete=Delete
 
 # VMStat plugin
 vmstat.stopped=Framework has been stopped.
@@ -91,4 +95,73 @@
 
 # Shell plugin
 shell.clear=Clear
-shell.status=Use the command prompt to execute shell commands.
\ No newline at end of file
+shell.status=Use the command prompt to execute shell commands.
+
+# Bundles plugin
+bundles.statline=Bundle information: {0} bundles in total, {1} bundles active, {2} active fragments, {3} bundles resolved, {4} bundles installed.
+bundles.install_or_update=Install or Update
+bundles.install_update=Install/Update...
+bundles.refreshPkg=Refresh Packages
+bundles.name=Name
+bundles.name.symb=Symbolic Name
+bundles.status=Status
+bundles.actions=Actions
+# bundle details
+bundles.location=Bundle Location
+bundles.lastMod=Last Modification
+bundles.doc=Bundle Documentation
+bundles.vendor=Vendor
+bundles.copyright=Copyright
+bundles.description=Description
+bundles.startlevel=Start Level
+bundles.classpath=Bundle Classpath
+bundles.pkg.exported=Exported Packages
+bundles.pkg.imported=Imported Packages
+bundles.pkg.importingBundles=Importing Bundles
+bundles.manifest.headers=Manifest Headers
+bundles.hosts=Host Bundles
+bundles.framents=Fragments Attached
+# actions
+bundles.update=Update
+bundles.uninstall=Uninstall
+bundles.refreshImports=Refresh Package Imports
+# upload form
+bundles.upload.caption=Upload / Install Bundles
+bundles.upload.start=Start Bundle
+bundles.upload.level=Start Level
+
+
+# Components plugin
+scr.status.no_service=Apache Felix Declarative Service required for this function!
+scr.status.no_components=No components installed currently!
+scr.status.ok=Number of installed components: {0}
+scr.action.enable=Enable
+scr.action.disable=Disable
+scr.action.configure=Configure
+scr.prop.bundle=Bundle
+scr.prop.defstate=Default State
+scr.prop.activation=Activation
+scr.prop.properties=Properties
+scr.serv.type=Service Type
+scr.serv=Services
+scr.title.actions=Actions
+scr.title.status=Status
+scr.title.name=Name
+
+
+# Configuration plugin
+config.status.ok=Configuration Admin Service is running.
+config.status.missing=Configuration Admin Service is not installed/running.
+config.properties=Properties
+config.properties.enter=Enter Name-Value pairs of configuration properties
+config.info.title=Configuration Information
+config.info.pid=Persistent Identity (PID)
+config.info.fpid=Factory Persistent Identifier (Factory PID)
+config.info.binding=Configuration Binding
+config.info.unbound=Unbound or new configuration 
+config.unbind.btn=Unbind
+config.unbind.tip=Unbind Configuration from Bundle
+config.del.ask=Are you sure to delete this configuration ?
+config.del.config=Configuration: 
+config.del.bundle=Bundle: 
+config.unbind.ask=Are you sure to unbind this configuration ?
diff --git a/webconsole/src/main/resources/res/lib/support.js b/webconsole/src/main/resources/res/lib/support.js
index 86e7620..427d0db 100644
--- a/webconsole/src/main/resources/res/lib/support.js
+++ b/webconsole/src/main/resources/res/lib/support.js
@@ -81,12 +81,8 @@
 });
 
 /* A helper function, used together with tablesorter, when the cells contains mixed text and links. As example:
-
 	elem.tablesorter({
-		headers: {
-			0: {textExtraction: mixedLinksExtraction},
-			2: {sorter: false}
-		}
+		textExtraction: mixedLinksExtraction
 	});
 */
 function mixedLinksExtraction(node) {
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());
+	});
+});
+
diff --git a/webconsole/src/main/resources/templates/bundles.html b/webconsole/src/main/resources/templates/bundles.html
new file mode 100644
index 0000000..4221f30
--- /dev/null
+++ b/webconsole/src/main/resources/templates/bundles.html
@@ -0,0 +1,86 @@
+<script type="text/javascript" src="${appRoot}/res/ui/bundles.js"></script>
+<script type="text/javascript">
+// <![CDATA[
+var startLevel = ${startLevel};
+var drawDetails = ${drawDetails};
+var currentBundle = ${currentBundle};
+var __bundles__ = ${__bundles__};
+var i18n = {
+	'Symbolic Name'       : '${bundles.name.symb}',
+	'Version'             : '${version}',
+	'Bundle Location'     : '${bundles.location}',
+	'Last Modification'   : '${bundles.lastMod}',
+	'Bundle Documentation': '${bundles.doc}',
+	'Vendor'              : '${bundles.vendor}',
+	'Copyright'           : '${bundles.copyright}',
+	'Description'         : '${bundles.description}',
+	'Start Level'         : '${bundles.startlevel}',
+	'Bundle Classpath'    : '${bundles.classpath}',
+	'Exported Packages'   : '${bundles.pkg.exported}',
+	'Imported Packages'   : '${bundles.pkg.imported}',
+	'Importing Bundles'   : '${bundles.pkg.importingBundles}',
+	'Manifest Headers'    : '${bundles.manifest.headers}',
+	'Host Bundles'        : '${bundles.hosts}',
+	'Fragments Attached'  : '${bundles.framents}',
+	'Vendor'              : '${bundles.vendor}',
+	// actions
+	'Start'               : '${start}',
+	'Stop'                : '${stop}',
+	'Update'              : '${bundles.update}',
+	'Uninstall'           : '${bundles.uninstall}',
+	'Refresh Package Imports' : '${bundles.refreshImports}',
+	//
+	statline              : '${bundles.statline}'
+}
+// ]]>
+</script>
+
+<!-- status line -->
+<p class="statline">&nbsp;</p>
+
+<!-- top header -->
+<form method="post" enctype="multipart/form-data" action="">
+	<div class="ui-widget-header ui-corner-top buttonGroup">
+		<input name="action" value="install" type="hidden" />
+		<input name="bundlestart" value="start" type="hidden" />
+		<input name="bundlestartlevel" value="5" type="hidden" />
+		<input name="bundlefile" style="margin-left: 10px;" type="file" />
+		<input value="${bundles.install_or_update}" style="margin-left: 10px;" type="submit" />
+		<button class="reloadButton" type="button" name="reload" style="margin-left: 60px;">${reload}</button>
+		<button class="installButton" type="button" name="install">${bundles.install_update}</button>
+		<button class="refreshPackages" type="button" name="refresh">${bundles.refreshPkg}</button>
+	</div>
+</form>
+
+<table id="plugin_table" class="tablesorter nicetable noauto">
+	<thead>
+		<tr>
+			<th class="col_Id">${id}</th>
+			<th class="col_Name">${bundles.name}</th>
+			<th class="col_Version">${version}</th>
+			<th class="col_Symbolic_Name">${bundles.name.symb}</th>
+			<th class="col_Status">${bundles.status}</th>
+			<th class="col_Actions">${bundles.actions}</th>
+		</tr>
+	</thead>
+	<tbody>
+		<tr><td colspan="6">&nbsp;</td></tr>
+	</tbody>
+</table>
+
+<!-- bottom header -->
+<form method="post" enctype="multipart/form-data" action="">
+	<div class="ui-widget-header ui-corner-bottom buttonGroup">
+		<input name="action" value="install" type="hidden" />
+		<input name="bundlestart" value="start" type="hidden" />
+		<input name="bundlestartlevel" value="5" type="hidden" />
+		<input name="bundlefile" style="margin-left: 10px;" type="file" />
+		<input value="${bundles.install_or_update}" style="margin-left: 10px;" type="submit" />
+		<button class="reloadButton" type="button" name="reload" style="margin-left: 60px;">${reload}</button>
+		<button class="installButton" type="button" name="install">${bundles.install_update}</button>
+		<button class="refreshPackages" type="button" name="refresh">${bundles.refreshPkg}</button>
+	</div>
+</form>
+
+<!-- status line -->
+<p class="statline">&nbsp;</p>
diff --git a/webconsole/src/main/resources/templates/bundles_upload.html b/webconsole/src/main/resources/templates/bundles_upload.html
new file mode 100644
index 0000000..18f9b52
--- /dev/null
+++ b/webconsole/src/main/resources/templates/bundles_upload.html
@@ -0,0 +1,33 @@
+<!--<script type="text/javascript" src="res/ui/bundles.js"></script>-->
+<script type="text/javascript" src="res/lib/jquery.multifile-1.4.6.js"></script>
+
+<form method="post" enctype="multipart/form-data" action="../" style="width:50%">
+
+	<!-- top heading -->
+	<div class="ui-widget-header ui-corner-top buttonGroup">
+		<input type="hidden" name="action" value="install"/>
+		${bundles.upload.caption}
+	</div>
+
+	<table class="nicetable">
+		<tr>
+			<td style="text-align:right">${bundles.upload.start}</td>
+			<td><input type="checkbox" name="bundlestart" value="start"/></td>
+		</tr>
+		<tr>
+			<td style="text-align:right">${bundles.upload.level}</td>
+			<td><input class="input" type="text" name="bundlestartlevel" id="bundlestartlevel" value="${startLevel}" size="4"/></td>
+		</tr>
+		<tr>
+			<td>&nbsp;</td>
+			<td>
+				<input class="multi" accept="jar" type="file" name="bundlefile"/>
+			</td>
+		</tr>
+		<tr>
+			<td colspan="2" style="text-align:center">
+				<input type="submit" value="${bundles.install_or_update}"/>
+			</td>
+		</tr>
+	</table>
+</form>