SLING-461 Move Sling Console to Apache Felix/FELIX-562 Move OSGi Console to Apache Felix

git-svn-id: https://svn.apache.org/repos/asf/felix/trunk@657024 13f79535-47bb-0310-9956-ffa450edef68
diff --git a/webconsole/src/main/resources/OSGI-INF/metatype/metatype.properties b/webconsole/src/main/resources/OSGI-INF/metatype/metatype.properties
new file mode 100644
index 0000000..be38663
--- /dev/null
+++ b/webconsole/src/main/resources/OSGI-INF/metatype/metatype.properties
@@ -0,0 +1,44 @@
+#
+#  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.
+#
+
+#
+# This file contains localization strings for configuration labels and
+# descriptions as used in the metatype.xml descriptor generated by the
+# the Sling SCR plugin
+
+manager.name = Sling Management Console
+manager.description = Configuration of the Sling Management Console.
+
+manager.root.name = Root URI
+manager.root.description = The root path to the Sling Management Console.
+
+realm.name = Realm
+realm.description = The name of the HTTP Authentication Realm.
+
+username.name = User Name
+username.description = The name of the user allowed to access the Sling \
+ Management Console. To disable authentication clear this value.
+
+password.name = Password
+password.description = The password for the user allowed to access the Sling \
+ Management Console.
+ 
+default.render.name = Default Page
+default.render.name.description = The name of the default configuration page \
+ when invoking the Sling Management console.
\ No newline at end of file
diff --git a/webconsole/src/main/resources/res/imgs/Sling.png b/webconsole/src/main/resources/res/imgs/Sling.png
new file mode 100644
index 0000000..e29d72b
--- /dev/null
+++ b/webconsole/src/main/resources/res/imgs/Sling.png
Binary files differ
diff --git a/webconsole/src/main/resources/res/imgs/element_add.png b/webconsole/src/main/resources/res/imgs/element_add.png
new file mode 100644
index 0000000..badd904
--- /dev/null
+++ b/webconsole/src/main/resources/res/imgs/element_add.png
Binary files differ
diff --git a/webconsole/src/main/resources/res/imgs/element_delete.png b/webconsole/src/main/resources/res/imgs/element_delete.png
new file mode 100644
index 0000000..2e41916
--- /dev/null
+++ b/webconsole/src/main/resources/res/imgs/element_delete.png
Binary files differ
diff --git a/webconsole/src/main/resources/res/imgs/element_run.png b/webconsole/src/main/resources/res/imgs/element_run.png
new file mode 100644
index 0000000..6dcd23b
--- /dev/null
+++ b/webconsole/src/main/resources/res/imgs/element_run.png
Binary files differ
diff --git a/webconsole/src/main/resources/res/imgs/element_stop.png b/webconsole/src/main/resources/res/imgs/element_stop.png
new file mode 100644
index 0000000..a89013d
--- /dev/null
+++ b/webconsole/src/main/resources/res/imgs/element_stop.png
Binary files differ
diff --git a/webconsole/src/main/resources/res/imgs/favicon.ico b/webconsole/src/main/resources/res/imgs/favicon.ico
new file mode 100644
index 0000000..a36e242
--- /dev/null
+++ b/webconsole/src/main/resources/res/imgs/favicon.ico
Binary files differ
diff --git a/webconsole/src/main/resources/res/ui/admin.css b/webconsole/src/main/resources/res/ui/admin.css
new file mode 100644
index 0000000..984d9a0
--- /dev/null
+++ b/webconsole/src/main/resources/res/ui/admin.css
@@ -0,0 +1,546 @@
+/*
+ * 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.
+ */ /* CSS Document */
+#main {
+    font-family: Verdana, Arial, Helvetica, sans-serif;
+    font-size: 10px;
+    color: black;
+    background-color: white;
+    border-collapse: collapse;
+    padding: 0px;
+    margin: 30px 0 30px 30px;
+    width: 957px;
+    position: absolute;
+    text-align: left;
+    border-color: black;
+}
+
+#lead {
+    color: #00678C;
+    /* color: #ffffff; */
+    margin: 0px 0px 26px 0px;
+    padding: 0px;
+    width: 957px;
+    height: 100px;
+}
+
+#lead h1 { /*
+    background-image: url(../imgs/banner_left.jpg);
+    background-repeat: no-repeat;
+    */
+    margin: 0px;
+    padding: 5px 0 0 8px;
+    font-size: 400%;
+    font-weight: bold;
+    line-height: 120%;
+    height: 95px;
+    /* account for 5px top marging to get a total of 100px */
+    float: left;
+}
+
+#lead br {
+    line-height: 20px;
+}
+
+#lead p { /*
+    background-image: url(../imgs/banner_right.jpg);
+    background-repeat: no-repeat;
+    border-left: 1px solid;
+        */
+    margin: 0px;
+    padding: 0px;
+    height: 100px;
+    float: right;
+}
+
+#technav {
+    border-bottom: 1px solid #6181A9;
+    border-top: 1px solid #6181A9;
+    color: black;
+    font-size: 10px;
+    font-weight: bold;
+    /*
+    border-top: 1px solid black;
+    */
+    height: 21px;
+    padding: 0;
+    margin: 0;
+}
+
+#technav a {
+    display: block;
+    float: left;
+    text-decoration: none;
+    padding: 3px 10px 3px 10px;
+    color: #6181A9;
+    text-decoration: none;
+}
+
+#technav a:hover {
+    background-color: black;
+}
+
+#technav .technavat {
+    display: block;
+    float: left;
+    text-decoration: none;
+    padding: 3px 10px 3px 10px;
+    background-color: #B6CAE4;
+    color: black;
+}
+
+#claim {
+    color: white;
+    background-color: black;
+    padding: 2px 10px 2px 10px;
+}
+
+#claim p {
+    margin: 0;
+    padding: 0;
+}
+
+#claim a {
+    color: #C5E2EE;
+    text-decoration: none;
+}
+
+/*
+.claimcell A:link {
+	color: #C5E2EE;
+	text-decoration: none;
+}
+
+.claimcell A:visited {
+	color: #C5E2EE;
+	text-decoration: none;
+}
+*/
+#claim a:hover {
+    color: #99FF33;
+    border-bottom: 1px solid;
+}
+
+#claim a:active {
+    color: #FFFFFF;
+}
+
+/* old styles */
+table {
+    text-align: left;
+}
+
+table.content {
+    clear: both;
+    font-size: 10px;
+    line-height: 13px;
+    border: 0px solid #66dd44;
+    border-top: 1px solid #cccccc;
+    padding: 0px;
+    margin: 0px;
+    margin-top: 26px;
+    margin-bottom: 26px;
+    /* width: 718px; */
+    text-align: left;
+}
+
+tr {
+    border-left: 1px solid #cccccc;  
+    border-right: 1px solid #cccccc;  
+}
+
+td.content {
+    color: #333333;
+    border: 0px solid #66dd44;
+    border-bottom: 1px solid #cccccc;
+    vertical-align: middle;
+    padding: 5px;
+}
+
+td.disabled {
+    color: #999999;
+}
+
+th.content {
+    color: #333333;
+    border: 0px solid #66dd44;
+    border-bottom: 1px solid #cccccc;
+    text-align: left;
+    padding: 5px;
+    padding-left: 10px;
+}
+
+.right {
+    text-align: right;
+}
+.center {
+    text-align: center;
+}
+
+th.container {
+    color: #6181A9;
+    background-color: #f0f0f0;
+}
+
+th.important {
+    color: #B81833;
+}
+
+.important {
+    color: #B81833;
+}
+
+#maintable { /* postion: absolute; */
+    font-size: 10px;
+    line-height: 13px;
+    border: 1px solid #000000;
+    padding: 0px;
+    margin: 0px;
+    width: 960px;
+}
+
+.toolcell {
+    font-size: 10px;
+    color: #999999;
+    line-height: 10px;
+    background-color: #000000;
+    height: 18px;
+    /* width: 960px; */
+    padding: 0px;
+    padding-bottom: 1px;
+    text-align: left;
+}
+
+.toolcell A:link {
+    color: #C5E2EE;
+    text-decoration: none;
+}
+
+.toolcell A:visited {
+    color: #C5E2EE;
+    text-decoration: none;
+}
+
+.toolcell A:hover {
+    color: #99FF33;
+    text-decoration: none;
+    border-bottom: 1px solid;
+}
+
+.toolcell A:active {
+    color: #FFFFFF;
+    text-decoration: none;
+}
+
+.leadcell {
+    margin: 0px;
+    padding: 0px;
+    border: 0px solid #000000;
+    width: 718px;
+    height: 100px;
+    background-image: url(../imgs/banner_left.jpg);
+    vertical-align: top;
+}
+
+.leadcelltext {
+    position: absolute;
+    border: 0px solid #000000;
+    font-size: 26px;
+    line-height: 32px;
+    margin-top: 5px;
+    margin-left: 8px;
+    color: #ffffff;
+    vertical-align: top;
+}
+
+.logocell {
+    border-left: 1px solid #000000;
+    width: 239px;
+    background-image: url(../imgs/banner_right.jpg);
+}
+
+#technavcell {
+    font-size: 10px;
+    font-weight: bold;
+    border: 0px solid #000000;
+    border-top: 1px solid #000000;
+    height: 21px;
+    background-color: #6181A9;
+}
+
+/*
+#technav A:link {
+	float: left;
+	display: block;
+	color: #ffffff;
+	border: 0px solid #000000;
+	border-right: 1px solid #000000;
+	height: 21px;
+	text-decoration: none;
+	padding: 0px 10px 0px 10px;
+	background-color: #6181A9;
+}
+
+#technav A:visited {
+	float: left;
+	display: block;
+	color: #ffffff;
+	border-right: 1px solid #000000;
+	height: 21px;
+	text-decoration: none;
+	padding: 0px 10px 0px 10px;
+	background-color: #6181A9;
+}
+
+#technav A:hover {
+	float: left;
+	display: block;
+	color: #ffffff;
+	border-right: 1px solid #000000;
+	height: 21px;
+	text-decoration: none;
+	padding: 0px 10px 0px 10px;
+	background-color: #000000;
+}
+
+#technav A:active {
+	float: left;
+	display: block;
+	color: #ffffff;
+	border-right: 1px solid #000000;
+	height: 21px;
+	text-decoration: none;
+	padding: 0px 10px 0px 10px;
+	background-color: #6181A9;
+}
+*/
+.techcontentcell { /* width: 718px; */
+    border: 0px solid #000000;
+    border-top: 1px solid #000000;
+}
+
+.relatedcell {
+    border-left: 1px solid #000000;
+    border-top: 1px solid #000000;
+    width: 239px;
+    background-color: #EBF0F6;
+}
+
+/*
+.claimcell {
+	width: 715px;
+	font-size: 10px;
+	color: #ffffff;
+	line-height: 10px;
+	background-color: #000000;
+	height: 18px;
+	padding: 0px;
+	padding-bottom: 1px;
+}
+
+.claimcell A:link {
+	color: #C5E2EE;
+	text-decoration: none;
+}
+
+.claimcell A:visited {
+	color: #C5E2EE;
+	text-decoration: none;
+}
+
+.claimcell A:hover {
+	color: #99FF33;
+	text-decoration: none;
+	border-bottom: 1px solid;
+}
+
+.claimcell A:active {
+	color: #FFFFFF;
+	text-decoration: none;
+}
+*/ /* CENTRAL CONTENT AREA STYLING */
+.content {
+    position: relative;
+    margin: 25px;
+    font-size: 11px;
+    line-height: 16px;
+    color: #000000;
+}
+
+.content A:link {
+    color: #336600;
+    text-decoration: underline;
+}
+
+.content A:visited {
+    color: #666666;
+    text-decoration: underline;
+}
+
+.content A:hover {
+    color: #ffffff;
+    background-color: #336600;
+    text-decoration: none;
+}
+
+.content A:active {
+    color: #ffffff;
+    background-color: #000000;
+    text-decoration: none;
+}
+
+body {
+	background-color: white;
+}
+
+/* TEXT STYLING */ /*
+h1, h2, h3, h4, h5, h6, p
+
+	{
+	margin: 0px;
+	margin-bottom: 8px;
+	font-size: 11px;
+	line-height: 16px;
+	font-weight:bold;
+	}
+
+*/ /*
+h1
+	{
+	color: #000000;
+	margin-top: 32px;
+	clear: left;
+	}
+
+
+h2
+	{
+	color: #336699;
+	}
+
+
+h3
+	{
+	color: #336699;
+	}
+*/ /*
+p
+	{
+	font-size: 11px;
+	line-height: 16px;
+	font-weight: normal;
+	color: #000000;
+	}
+*/ /* FORMS */
+form {
+    font-size: 9px;
+    border-top: 0px solid #000000;
+    border-bottom: 0px solid #000000;
+    border-left: 0px solid #000000;
+    border-right: 0px solid #000000;
+    margin: 0;
+    padding: 0;
+    clear: left;
+}
+
+select,textarea {
+    font-family: Verdana, Arial, Helvetica, san-serif;
+    font-size: 9px;
+    font-weight: normal;
+    display: block;
+    float: left;
+    padding-top: 3px;
+    margin-bottom: 10px;
+}
+
+.input {
+    font-family: Verdana, Arial, Helvetica, san-serif;
+    font-size: 9px;
+    font-weight: normal;
+    color: #184054;
+    background-color: #f0f0f0;
+    border: 1px solid #999999;
+    border-bottom: 1px solid #cccccc;
+    border-right: 1px solid #cccccc;
+}
+
+.submit {
+    cursor: default;
+    width: 60px;
+    font-family: Verdana, Arial, Helvetica, san-serif;
+    font-size: 10px;
+    font-weight: bold;
+    background-color: #f0f0f0;
+    height: 20px;
+    padding: 0px;
+    padding-bottom: 1px;
+    margin: 0px;
+    border: 1px solid #cccccc;
+    border-bottom: 1px solid #666666;
+    border-right: 1px solid #666666;
+}
+
+input.important {
+    background-color: #B81833;
+    color: #ffffff;
+}
+
+select {
+    color: #184054;
+    background-color: #f0f0f0;
+    border: 0px solid #999999;
+}
+
+textarea {
+    color: #184054;
+    background-color: #f0f0f0;
+    width: 234px;
+    height: 100px;
+    border: 1px solid #999999;
+    border-bottom: 1px solid #cccccc;
+    border-right: 1px solid #cccccc;
+}
+
+.clearleft {
+    clear: left;
+}
+
+.clearboth {
+    clear: both;
+}
+
+.checkradio {
+    background-color: #ffffff;
+    width: 20px;
+    padding: 0px;
+    padding-bottom: 10px;
+    margin: 0px;
+    margin-top: 2px;
+    border: 0px solid #999999;
+}
+
+.checkradiotext {
+    font-size: 9px;
+    font-weight: normal;
+    line-height: 11px;
+    width: 100px;
+    color: #000000;
+    padding: 0px;
+    padding-bottom: 10px;
+    margin: 0px;
+    margin-top: 4px;
+    border: 0px solid #999999;
+}
\ No newline at end of file
diff --git a/webconsole/src/main/resources/res/ui/admin.js b/webconsole/src/main/resources/res/ui/admin.js
new file mode 100644
index 0000000..3fe3697
--- /dev/null
+++ b/webconsole/src/main/resources/res/ui/admin.js
@@ -0,0 +1,152 @@
+/*
+ * 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.
+ */
+
+
+/* shuts down server after [num] seconds */
+function shutdown(num, formname, elemid) {
+	var elem;
+	var canCount = document.getElementById;
+	if (canCount) {
+	    elem = document.getElementById(elemid);
+	    canCount = (typeof(elem) != "undefined" && typeof(elem.innerHTML) != "undefined");
+	}
+	var secs=" second";
+	var ellipsis="...";
+	if (num > 0) {
+		if (num != 1) {
+			secs+="s";
+		}
+		if (canCount) {
+		    elem.innerHTML=num+secs+ellipsis;
+		}
+		setTimeout('shutdown('+(--num)+', "'+formname+'", "'+elemid+'")',1000);
+	} else {
+	    document[formname].submit();
+	}
+}
+
+/* aborts server shutdown and redirects to [target] */
+function abort(target) {
+    top.location.href=target;
+}
+
+/* checks if values of [pass1] and [pass2] match */
+function checkPasswd(form, pass0, pass1, pass2) {
+    var check = false;
+    check = (form[pass0].value != form[pass1].value);
+    if (!check) {
+        alert("Old and new password must be different.");
+        form[pass1].value="";
+        form[pass2].value="";
+        form[pass1].focus();
+    }
+    check = (form[pass1].value == form[pass2].value);
+    if (!check) {
+        alert("Passwords did not match. Please type again.");
+        form[pass1].value="";
+        form[pass2].value="";
+        form[pass1].focus();
+    }
+    return check;
+}
+
+/* displays a date in the user's local timezone */
+function localDate(time) {
+    var date = time ? new Date(time) : new Date();
+    document.write(date.toLocaleString());
+}
+
+/* shows the about screen  */
+function showAbout() {
+// Temporarily disabled, as thee is no about.html page (fmeschbe, 20070330)
+//    var arguments = ABOUT_VERSION+";"+ABOUT_JVERSION+";"+ABOUT_MEM+";"+ABOUT_USED+";"+ABOUT_FREE;
+//    if (window.showModalDialog) {
+//        window.showModalDialog("about.html", arguments, "help: no; status: no; resizable: no; center: yes; scroll: no");
+//    } else {
+//        aboutWin = window.open("about.html?a="+arguments, "about", "width=500,height=420,modal,status=no,toolbar=no,menubar=no,personalbar=no");
+//    }
+}
+
+//-----------------------------------------------------------------------------
+// Ajax Support
+
+// request object, do not access directly, use getXmlHttp instead
+var xmlhttp = null;
+function getXmlHttp() {
+	if (xmlhttp) {
+		return xmlhttp;
+	}
+	
+	if (window.XMLHttpRequest) {
+		xmlhttp = new XMLHttpRequest();
+	} else if (window.ActiveXObject) {
+		try {
+			xmlhttp = new ActiveXObject("Msxml2.XMLHTTP");
+		} catch (ex) {
+			try {
+				xmlhttp = new ActiveXObject("Microsoft.XMLHTTP");
+			} catch (ex) {
+			}
+		}
+	}
+	
+	return xmlhttp;
+}
+
+function sendRequest(/* String */ method, /* url */ url, /* function */ callback) {
+    var xmlhttp = getXmlHttp();
+    if (!xmlhttp) {
+        return;
+    }
+    
+    if (xmlhttp.readyState < 4) {
+    	xmlhttp.abort();
+  	}
+  	
+  	if (!method) {
+  		method = 'GET';
+  	}
+  	
+  	if (!url) {
+  		url = document.location;
+  	} else if (url.charAt(0) == '?') {
+  		url = document.location + url;
+  	}
+  	
+    xmlhttp.open(method, url);
+    xmlhttp.onreadystatechange = handleResult;
+    xmlhttp.priv_callback = callback;
+    xmlhttp.send(null);
+  	
+}
+
+function handleResult() {
+    var xmlhttp = getXmlHttp();
+    if (!xmlhttp || xmlhttp.readyState != 4) {
+        return;
+    }
+    
+    var result = xmlhttp.responseText;
+    if (!result) {
+        return;
+    }
+
+	if (xmlhttp.priv_callback) {
+	    var obj = eval('(' + result + ')');
+	    xmlhttp.priv_callback(obj);
+	}
+}
diff --git a/webconsole/src/main/resources/res/ui/configmanager.js b/webconsole/src/main/resources/res/ui/configmanager.js
new file mode 100644
index 0000000..d15aa17
--- /dev/null
+++ b/webconsole/src/main/resources/res/ui/configmanager.js
@@ -0,0 +1,229 @@
+/*
+ * 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.
+ */
+
+
+function configure() {
+    var span = document.getElementById('configField');
+    if (!span) {
+        return;
+    }
+    var select = document.configSelection.pid;
+    var pid = select.options[select.selectedIndex].value;
+    var parm = '?action=ajaxConfigManager&' + pid;
+    sendRequest('GET', parm, displayConfigForm);
+}
+
+function displayConfigForm(obj) {
+    var span = document.getElementById('configField');
+    if (!span) {
+        return;
+    }
+    var innerHtml = '<tr class="content" id="configField">' + span.innerHTML + '</tr>';
+    innerHtml += '<tr class="content">';
+    innerHtml += '<th colspan="2" class="content" >' + obj.title + '</th></tr>';
+    innerHtml += '<tr class="content">';
+    innerHtml += '<td class="content">&nbsp;</td>';
+    innerHtml += '<td class="content">';
+    innerHtml += '<form method="post">';
+    innerHtml += '<input type="hidden" name="apply" value="true" />';
+    innerHtml += '<input type="hidden" name="pid" value="' + obj.pid + '" />';
+    innerHtml += '<input type="hidden" name="action" value="ajaxConfigManager" />';
+    innerHtml += '<table border="0" width="100%">';
+    if (obj.description) {
+        innerHtml += '<tr class="content">';
+        innerHtml += '<td class="content" colspan="2">' + obj.description + '</td></tr>';
+    }
+    if (obj.propertylist == 'properties') {
+        innerHtml += printTextArea(obj.properties);
+    } else {
+        innerHtml += printForm(obj);
+    }
+    innerHtml += '<tr class="content">';
+    innerHtml += '<td class="content">&nbsp;</td>';
+    innerHtml += '<td class="content">';
+    innerHtml += '<input type="submit" class="submit" name="submit" value="Save" />';
+    innerHtml += '&nbsp;&nbsp;&nbsp;';
+    innerHtml += '<input type="reset" class="submit" name="reset" value="Reset" />';
+    innerHtml += '&nbsp;&nbsp;&nbsp;';
+    innerHtml += '<input type="submit" class="submit" name="delete" value="Delete" onClick="return confirmDelete();"/>';
+    if (obj.isFactory) {
+        innerHtml += '&nbsp;&nbsp;&nbsp;';
+        innerHtml += '<input type="submit" class="submit" name="create" value="Create Configuration" onClick="return promptContext(this);" />';
+        innerHtml += '<input type="hidden" name="sling.context" value="" />';
+    }
+    innerHtml += '</td></tr>';
+    innerHtml += '</table>';
+    innerHtml += '</form>';
+    innerHtml += '</td></tr>';
+    innerHtml += printConfigurationInfo(obj);
+    span.parentNode.innerHTML = innerHtml;
+}
+
+function printTextArea(props) {
+    var innerHtml = '<tr class="content">';
+    innerHtml += '<td class="content" style="vertical-align: top">Properties</td>';
+    innerHtml += '<td class="content" style="width: 99%">';
+    innerHtml += '<textarea name="properties" style="height: 50%; width: 99%">';
+    for (var key in props) {
+        innerHtml += key + ' =  ' + props[key] + '\r\n';
+    }
+    innerHtml += '</textarea>';
+    innerHtml += 'Enter Name-Value pairs of configuration properties.</td>';
+    return innerHtml;
+}
+
+function printForm(obj) {
+    var innerHtml = '';
+    var propList;
+    for (var idx in obj.propertylist) {
+        var prop = obj.propertylist[idx];
+        var attr = obj[prop];
+        innerHtml += '<tr class="content">';
+        innerHtml += '<td class="content" style="vertical-align: top">' + attr.name + '</td>';
+        innerHtml += '<td class="content" style="width: 99%">';
+        if (attr.value != undefined) { // check is required to also handle empty strings, 0 and false
+            innerHtml += createInput(prop, attr.value, attr.type, '99%');
+            innerHtml += '<br />';
+        } else if (typeof(attr.type) == 'object') {
+        	// assume attr.values and multiselect
+        	innerHtml += createMultiSelect(prop, attr.values, attr.type, '99%');
+            innerHtml += '<br />';
+        } else {
+            for (var vidx in attr.values) {
+                var spanElement = createSpan(prop, attr.values[vidx], attr.type);
+                innerHtml += '<span id="' + spanElement.id + '">';
+                innerHtml += spanElement.innerHTML;
+                innerHtml += '</span>';
+            }
+        }
+        if (attr.description) {
+            innerHtml += attr.description;
+        }
+        innerHtml += '</td>';
+        if (propList) {
+            propList += ',' + prop;
+        } else {
+            propList = prop;
+        }
+    }
+    innerHtml += '<input type="hidden" name="propertylist" value="' + propList + '"/>';
+    return innerHtml;
+}
+
+function printConfigurationInfo(obj) {
+    var innerHtml = '<tr class="content">';
+    innerHtml += '<th colspan="2" class="content" >Configuration Information</th></tr>';
+    innerHtml += '<tr class="content">';
+    innerHtml += '<td class="content">Persistent Identity (PID)</td>';
+    innerHtml += '<td class="content">' + obj.pid + '</td></tr>';
+    if (obj.factoryPID) {
+        innerHtml += '<tr class="content">';
+        innerHtml += '<td class="content">Factory Peristent Identifier (Factory PID)</td>';
+        innerHtml += '<td class="content">' + obj.factoryPID + '</td></tr>';
+    }
+    innerHtml += '<tr class="content">';
+    innerHtml += '<td class="content">Configuration Binding</td>';
+    innerHtml += '<td class="content">' + obj.bundleLocation + '</td></tr>';
+    return innerHtml;
+}
+
+function addValue(prop, vidx) {
+    var span = document.getElementById(vidx);
+    if (!span) {
+        return;
+    }
+    var newSpan = createSpan(prop, '');
+    span.parentNode.insertBefore(newSpan, span.nextSibling);
+}
+
+var spanCounter = 0;
+function createSpan(prop, value, type) {
+    spanCounter++;
+    var newId = prop + spanCounter;
+    var innerHtml = createInput(prop, value, type, '89%');
+    innerHtml += '<input class="input" type="button" value="+" onClick="addValue(\'' + prop + '\',\'' + newId + '\');" style="width: 5%" />';
+    innerHtml += '<input class="input" type="button" value="-" onClick="removeValue(\'' + newId + '\');" style="width: 5%" />';
+    innerHtml += '<br />';
+    var newSpan = document.createElement('span');
+    newSpan.id = newId;
+    newSpan.innerHTML = innerHtml;
+    return newSpan;
+}
+
+function createInput(prop, value, type, width) {
+    if (type == 11) { // AttributeDefinition.BOOLEAN
+        if (value && typeof(value) != "boolean") {
+            value = value.toString().toLowerCase() == "true";
+        }
+        var checked = value ? 'checked' : '';
+        return '<input class="input" type="checkbox" name="' + prop + '" value="true" ' + checked + '/>';
+    } else if (typeof(type) == "object") { // predefined values
+    	var labels = type.labels;
+    	var values = type.values;
+    	var innerHtml = '<select class="select" name="' + prop + '" style="width: ' + width + '">';
+    	for (var idx in labels) {
+    		var selected = (value == values[idx]) ? ' selected' : '';
+    		innerHtml += '<option value="' + values[idx] + '"' + selected + '>' + labels[idx] + '</option>';
+    	}
+    	innerHtml += '</select>';
+    	return innerHtml;
+    } else { // Simple 
+        return '<input class="input" type="text" name="' + prop + '" value="' + value + '" style="width: ' + width + '"/>';
+    }
+}
+
+function createMultiSelect(prop, values, options, width) {
+    // convert value list into 'set'
+    var valueSet = new Object();
+    for (var idx in values) {
+    	valueSet[ values[idx] ] = true;
+    }
+    
+   	var labels = options.labels;
+   	var values = options.values;
+   	var innerHtml = '';
+   	for (var idx in labels) {
+   		var checked = valueSet[ values[idx] ] ? ' checked' : '';
+   		innerHtml += '<label><input type="checkbox" name="' + prop + '" value="' + values[idx] + '"' + checked + '>' + labels[idx] + '</label>';
+   	}
+   	return innerHtml;
+}
+
+function removeValue(vidx) {
+    var span = document.getElementById(vidx);
+    if (!span) {
+        return;
+    }
+    span.parentNode.removeChild(span);
+}
+
+function confirmDelete() {
+    return confirm("Are you sure to delete this configuration ?");
+}
+
+function promptContext(form) {
+    var result = prompt("Please give a Sling Context for the new configuration");
+    // alert("You entered: [" + result + "] for form [" + form + "/" + form.form + "]");
+    
+    // set the hidden sling.context input field with the value
+    if (result != null) {
+        form.form["sling.context"].value = result;
+        return true;
+    }
+    
+    return false;
+}
\ No newline at end of file