This is an automated email from the ASF dual-hosted git repository.

rombert pushed a commit to branch master
in repository 
https://gitbox.apache.org/repos/asf/sling-org-apache-sling-resource-editor.git

commit d8866ccf02638031c37d4cc4b7295223cc8925de
Author: Sandro Boehme <[email protected]>
AuthorDate: Fri Jun 26 10:58:10 2015 +0000

    SLING-4736 Resource Editor :: properties page :: add CRUD for String and 
Path and prepare for other types:
    o Added crud for String and Path properties
    o Added path-editor, path-viewer and string-editor tag files
    o Added e2e tests for the new crud
    o Added shortcuts and a cheat sheet for properties to explain them
    o Added bootstrap-notify to notify after saving and deleting properties
    o Added Glyphicons-halflings icon font for property icons
    o Manually tested on IE9
    o Styles adapted for IE9
    o Added toolbar with dropdown for the properties page
    o Replaced some css colors by variables in less files
    o Added vertical scrolling to the properties page
    
    git-svn-id: https://svn.apache.org/repos/asf/sling/trunk@1687749 
13f79535-47bb-0310-9956-ffa450edef68
---
 frontend/Gruntfile.js                              |  58 ++-
 frontend/package.json                              |   3 +-
 pom.xml                                            |   8 +-
 src/main/img/save-bigger_white.xcf                 | Bin 0 -> 1467 bytes
 src/main/less/forms.less                           |   5 +
 src/main/less/glyphicons.less                      |  15 +
 src/main/less/navs.less                            |  22 +
 src/main/less/reseditor.less                       |  64 ++-
 src/main/less/scaffolding.less                     |   4 +
 src/main/less/variables.less                       |   2 +
 src/main/resources/META-INF/resource-editor.tld    |  17 +
 src/main/resources/META-INF/tags/path-editor.tag   |  13 +
 src/main/resources/META-INF/tags/path-viewer.tag   |  24 +
 src/main/resources/META-INF/tags/string-editor.tag |  17 +
 .../resource-editor-static-content/css/ie.css}     |  17 +-
 .../js/properties/PropertyController.js            | 196 +++++++++
 .../js/tree/AddNodeController.js                   |   6 +-
 .../SLING-INF/libs/sling/resource-editor/html.jsp  |  86 +---
 .../libs/sling/resource-editor/nodes.json.incl.jsp |   4 +-
 .../libs/sling/resource-editor/nodes.json.jsp      |   2 +-
 .../libs/sling/resource-editor/properties.jsp      | 180 ++++++++
 .../libs/sling/resource-editor/rootnodes.json.jsp  |   2 +-
 src/test/javascript/e2e/spec/e2e_spec.js           | 485 +++++++++++++--------
 23 files changed, 923 insertions(+), 307 deletions(-)

diff --git a/frontend/Gruntfile.js b/frontend/Gruntfile.js
index 49559d1..e5c1718 100644
--- a/frontend/Gruntfile.js
+++ b/frontend/Gruntfile.js
@@ -71,33 +71,49 @@ module.exports = function(grunt) {
                                  'jquery/dist/jquery.min.js',
                                  'jquery/dist/jquery.min.map',
                                  'bootbox/bootbox.min.js',
-                                 'jstree/dist/jstree.min.js'
+                                 'jstree/dist/jstree.min.js',
+                                 
'bootstrap-notify/dist/bootstrap-notify.min.js'
                                 ], // Actual pattern(s) to match.
                            dest: 
staticContentFolder+'/generated/3rd_party/js',   // Destination path prefix.
                            flatten: true
                          },
                        ],
                      },
-       css_dependencies: {
-               files: [
-                 {
-                   expand: true,     // Enable dynamic expansion.
-                   cwd: 'node_modules/',      // Src matches are relative to 
this path.
-                   src: [
-                         'select2/select2.css',
-                         'select2/select2.png',
-                         'select2/select2-spinner.gif',
-                         'animate.css/animate.min.css',
-                         'jstree/dist/themes/default/style.min.css',
-                         'jstree/dist/themes/default/32px.png',
-                         'jstree/dist/themes/default/40px.png',
-                         'jstree/dist/themes/default/throbber.gif',
-                        ], // Actual pattern(s) to match.
-                   dest: staticContentFolder+'/generated/3rd_party/css',   // 
Destination path prefix.
-                   flatten: true
-                 },
-               ],
-             }
+               css_dependencies: {
+                       files: [
+                         {
+                           expand: true,     // Enable dynamic expansion.
+                           cwd: 'node_modules/',      // Src matches are 
relative to this path.
+                           src: [
+                                 'select2/select2.css',
+                                 'select2/select2.png',
+                                 'select2/select2-spinner.gif',
+                                 'animate.css/animate.min.css',
+                                 'jstree/dist/themes/default/style.min.css',
+                                 'jstree/dist/themes/default/32px.png',
+                                 'jstree/dist/themes/default/40px.png',
+                                 'jstree/dist/themes/default/throbber.gif',
+                                ], // Actual pattern(s) to match.
+                           dest: 
staticContentFolder+'/generated/3rd_party/css',   // Destination path prefix.
+                           flatten: true
+                         },
+                       ],
+                     },
+                   font_dependencies: {
+                       files: [
+                         {
+                           expand: true,     // Enable dynamic expansion.
+                           cwd: 'node_modules/',      // Src matches are 
relative to this path.
+                           src: [
+                                 
'bootstrap/fonts/glyphicons-halflings-regular.ttf',
+                                 
'bootstrap/fonts/glyphicons-halflings-regular.woff2',
+                                 
'bootstrap/fonts/glyphicons-halflings-regular.woff'
+                                ], // Actual pattern(s) to match.
+                           dest: 
staticContentFolder+'/generated/3rd_party/fonts',   // Destination path prefix.
+                           flatten: true
+                         },
+                       ],
+                     }
            },
            karma: {
                options: {
diff --git a/frontend/package.json b/frontend/package.json
index 7fe4321..6966d1e 100644
--- a/frontend/package.json
+++ b/frontend/package.json
@@ -11,7 +11,8 @@
        "select2": "3.5.2-browserify",
        "jstree": "3.0.9",
        "animate.css": "3.1.1",
-       "jquery-scrollto": "1.4.4"
+       "jquery-scrollto": "1.4.4",
+       "bootstrap-notify": "3.0.0"
   },
   "devDependencies": {
     "grunt": "0.4.5",
diff --git a/pom.xml b/pom.xml
index 08ad5fa..e75dd64 100644
--- a/pom.xml
+++ b/pom.xml
@@ -58,7 +58,11 @@
                                <extensions>true</extensions>
                                <configuration>
                                        <instructions>
-                                               
<Sling-Initial-Content>SLING-INF/libs/sling/resource-editor-static-content;overwrite:=true;path:=/libs/sling/resource-editor-static-content,SLING-INF/libs/sling/resource-editor;overwrite:=true;path:=/libs/sling/resource-editor</Sling-Initial-Content>
+                                               <Sling-Initial-Content>
+                                                       
META-INF/tags;overwrite:=true;path:=/libs/sling/resource-editor-tags/property-editor,
+                                                       
SLING-INF/libs/sling/resource-editor-static-content;overwrite:=true;path:=/libs/sling/resource-editor-static-content,
+                                                       
SLING-INF/libs/sling/resource-editor;overwrite:=true;path:=/libs/sling/resource-editor
+                                               </Sling-Initial-Content>
                                                
<Import-Package>!org.slf4j.impl,*,
                                                        
org.apache.sling.commons.js.nodetypes.javascript,
                                                        javax.el,
@@ -80,6 +84,8 @@
                                                        org.xml.sax.helpers
                                                </Import-Package>
                                                
<Export-Package>!org.apache.sling.reseditor</Export-Package>
+                                   
<Include-Resource>META-INF/resource-editor.tld=${project.build.outputDirectory}/META-INF/resource-editor.tld,{maven-resources}</Include-Resource>
+                                   
<Sling-Bundle-Resources>/META-INF/tags</Sling-Bundle-Resources>
                                        </instructions>
                                        
<remoteOBR>www.jcrbrowser.org</remoteOBR>
                                </configuration>
diff --git a/src/main/img/save-bigger_white.xcf 
b/src/main/img/save-bigger_white.xcf
new file mode 100644
index 0000000..bf58185
Binary files /dev/null and b/src/main/img/save-bigger_white.xcf differ
diff --git a/src/main/less/forms.less b/src/main/less/forms.less
index ea3ae31..3b6aa85 100644
--- a/src/main/less/forms.less
+++ b/src/main/less/forms.less
@@ -53,4 +53,9 @@
 // vertical-form is a custom class
 .modal-body.vertical-form label {
        display: block;
+}
+
+
+#properties fieldset {
+       margin-bottom: 5px;
 }
\ No newline at end of file
diff --git a/src/main/less/glyphicons.less b/src/main/less/glyphicons.less
new file mode 100644
index 0000000..4650880
--- /dev/null
+++ b/src/main/less/glyphicons.less
@@ -0,0 +1,15 @@
+//
+// Glyphicons for Bootstrap
+//
+// Since icons are fonts, they can be placed anywhere text is placed and are
+// thus automatically sized to match the surrounding child. To use, create an
+// inline element with the appropriate classes, like so:
+//
+// <a href="#"><span class="glyphicon glyphicon-star"></span> Star</a>
+
+
+#properties .glyphicon {
+       font-size: 16px;
+       color: @textColor;
+}
+
diff --git a/src/main/less/navs.less b/src/main/less/navs.less
index ca7862c..0d880a8 100644
--- a/src/main/less/navs.less
+++ b/src/main/less/navs.less
@@ -79,3 +79,25 @@
   padding: 5px 10px 5px 10px;
   
 }
+
+.nav {
+       > li > a {
+             &:hover,
+             &:focus {
+               background-color: @selectedBackground;
+               border: 1px solid black;
+             }
+           border: 1px solid transparent;
+               color: @textColor;
+       }
+  // Open dropdowns
+  .open {
+       text-shadow: none;
+  }
+  .dropdown-menu > li > a {
+             &:hover,
+             &:focus {
+               background-color: @textColor;
+             }
+   }
+}
diff --git a/src/main/less/reseditor.less b/src/main/less/reseditor.less
index bf16646..18942d4 100755
--- a/src/main/less/reseditor.less
+++ b/src/main/less/reseditor.less
@@ -31,6 +31,7 @@
 @import "forms.less";
 @import "buttons.less";
 @import "modals.less";
+@import "glyphicons.less";
  
 
 /* ################################################################# */
@@ -120,7 +121,7 @@ body
        font-family: 'Michroma', sans-serif;
        font-weight: bold;
        font-size: 24px;
-       color: #2D373D;
+       color: @brand-primary;
        text-shadow: 0 2px 2px #dddddd;
        display: inline;
        margin: 10px;
@@ -134,16 +135,18 @@ body
        margin-left: 4px;
 }
 
-.logout a {
+#login .logout a {
        .rounded;
-       border: 1px solid #2D373D;
-       color: #2D373D;
+       border: 1px solid @brand-primary;
+       color: @brand-primary;
        text-shadow: 0 1px 1px #EEE;
        font-size: 15px;
        margin: 10px 10px 0 0;
-       padding: 0 10px;
        box-shadow: inset 0px 0px 1px black, 1px 1px 0px white;
 }
+#login .logout a:hover {
+       background-color: @textColor;
+}
 
 #login_error {
        width: 200px;
@@ -171,28 +174,12 @@ body
     padding: 5px;
 }
 
-
-fieldset
-{
-       border: none;
-       margin-top: 5px;
-       padding: 0;
-}
 .proplabel
 {
-       width: 25%;
-       float: left;
-       display: inline;
        line-height: 24px;
-       color: #C0C0C0;
+       color: @textColor;
        font-weight: normal;
 }
-.propinput
-{
-       float: left;
-       display: inline;
-       width: 65%;
-}
 .propinputmultival
 {
        float: left;
@@ -202,7 +189,6 @@ fieldset
 .propmultival_fieldset
 {
        float: left;
-       width: 65%;
        margin: 0 5px 0 0
 }
 
@@ -247,6 +233,23 @@ fieldset
        background-image: url(../../img/remove.png);
 }
 
+.property-icon {
+       margin-top: 5px;
+}
+
+.icon {
+       cursor: pointer;
+       border: 1px solid transparent; 
+       padding: 3px;
+       -moz-border-radius: 3px;
+    border-radius: 3px;
+}
+
+.property-icon:hover {
+       border: 1px solid black;
+       background-color: @selectedBackground;
+}
+
 .jstree-default .jstree-icon.add-icon{
        background-image: url(../../img/add.png);
     margin-right: 3px;
@@ -282,7 +285,7 @@ fieldset
 
 #tree .jstree-clicked 
 {
-       background:#303030; 
+       background: @selectedBackground; 
        border:1px solid black; 
        padding:0px 1px;
     -moz-border-radius: 5px;
@@ -349,4 +352,17 @@ input.jstree-rename-input{
 }
 #addNodeDialog .form-group label a{
        font-weight: normal;
+}
+
+.propertyTypeMenu {
+       text-shadow: none;
+}
+
+#properties .ie9filter-plate-div {
+       overflow-y: auto;
+       overflow-x: hidden;
+}
+
+#properties-info-icon {
+       margin-top: -4px;
 }
\ No newline at end of file
diff --git a/src/main/less/scaffolding.less b/src/main/less/scaffolding.less
index 75b563c..1c90e95 100644
--- a/src/main/less/scaffolding.less
+++ b/src/main/less/scaffolding.less
@@ -27,4 +27,8 @@
 
 body {
   .plate-text-shadow;
+}
+
+.property-row a {
+       color: @textColor;
 }
\ No newline at end of file
diff --git a/src/main/less/variables.less b/src/main/less/variables.less
index 9d692a2..25f14f5 100644
--- a/src/main/less/variables.less
+++ b/src/main/less/variables.less
@@ -26,6 +26,7 @@
 // -------------------------
 @bodyBackground:       transparent;
 @textColor: #c0c0c0;
+@selectedBackground: #303030;
 
 // Links
 // -------------------------
@@ -34,3 +35,4 @@
 // Forms
 // -------------------------
 @inputBorderRadius:             3px;
+@icon-font-path:          "../3rd_party/fonts/";
\ No newline at end of file
diff --git a/src/main/resources/META-INF/resource-editor.tld 
b/src/main/resources/META-INF/resource-editor.tld
new file mode 100644
index 0000000..b4a0288
--- /dev/null
+++ b/src/main/resources/META-INF/resource-editor.tld
@@ -0,0 +1,17 @@
+<taglib version="2.1" xmlns="http://java.sun.com/xml/ns/javaee";>
+ <tlib-version>1.0-SNAPSHOT</tlib-version>
+ <short-name>test</short-name>
+ <uri>http://sling.apache.org/resource-editor</uri>
+ <tag-file>
+  <name>string-editor</name>
+  <path>/META-INF/tags/string-editor.tag</path>
+ </tag-file>
+ <tag-file>
+  <name>path-editor</name>
+  <path>/META-INF/tags/path-editor.tag</path>
+ </tag-file>
+ <tag-file>
+  <name>path-viewer</name>
+  <path>/META-INF/tags/path-viewer.tag</path>
+ </tag-file>
+</taglib>
\ No newline at end of file
diff --git a/src/main/resources/META-INF/tags/path-editor.tag 
b/src/main/resources/META-INF/tags/path-editor.tag
new file mode 100644
index 0000000..90df44b
--- /dev/null
+++ b/src/main/resources/META-INF/tags/path-editor.tag
@@ -0,0 +1,13 @@
+<%@ tag body-content="empty" isELIgnored="false" display-name="Path-Editor" %>
+
+<%@ taglib uri="http://java.sun.com/jsp/jstl/core"; prefix="c" %>
+<%@ taglib uri="http://java.sun.com/jsp/jstl/functions"; prefix="fn" %>
+
+<%@attribute name="component_id" %>
+<%@attribute name="value"  %>
+
+<c:if test="${not empty value}" >
+       <c:set var="escapedValue" value="${fn:escapeXml(value)}" />
+</c:if>
+
+<input id="${component_id}" class="propinput form-control property-value 
path-editor" name="new-property-value" value="${escapedValue}"/>
diff --git a/src/main/resources/META-INF/tags/path-viewer.tag 
b/src/main/resources/META-INF/tags/path-viewer.tag
new file mode 100644
index 0000000..6a1fa84
--- /dev/null
+++ b/src/main/resources/META-INF/tags/path-viewer.tag
@@ -0,0 +1,24 @@
+<%@ tag body-content="empty" isELIgnored="false" display-name="Path-Editor" %>
+
+<%@ taglib uri="http://java.sun.com/jsp/jstl/core"; prefix="c" %>
+<%@ taglib uri="http://java.sun.com/jsp/jstl/functions"; prefix="fn" %>
+
+<%@attribute name="component_id" %>
+<%@attribute name="value" %>
+<%@attribute name="editor_component_id" %>
+
+<c:if test="${not empty value}" >
+       <c:set var="escapedValue" value="${fn:escapeXml(value)}" />
+</c:if>
+
+<script type="text/javascript">
+$(document).ready(function() {
+       
+       $('\#${editor_component_id}').on("keyup", function(){
+               $('\#${component_id}').attr('href', 
'/reseditor'+$(this).val()+'.html');
+               $('\#${component_id}').text($(this).val()+'.html');
+       });
+});
+</script>
+
+<a id="${component_id}" class="path-viewer" 
href="/reseditor${value}.html">${escapedValue}.html</a>
\ No newline at end of file
diff --git a/src/main/resources/META-INF/tags/string-editor.tag 
b/src/main/resources/META-INF/tags/string-editor.tag
new file mode 100644
index 0000000..07615de
--- /dev/null
+++ b/src/main/resources/META-INF/tags/string-editor.tag
@@ -0,0 +1,17 @@
+<%@ tag body-content="empty" isELIgnored="false" display-name="String-Editor" 
%>
+
+<%@ taglib uri="http://java.sun.com/jsp/jstl/core"; prefix="c" %>
+<%@ taglib uri="http://java.sun.com/jsp/jstl/functions"; prefix="fn" %>
+
+<%@attribute name="property_name"  %>
+<%@attribute name="value"  %>
+<%@attribute name="rows"  %>
+
+<c:choose>
+  <c:when test="${empty rows}">
+       <textarea data-property-name="${fn:escapeXml(property_name)}" 
name="new-property-value" class="propinput form-control 
property-value">${value}</textarea>
+  </c:when>
+  <c:otherwise>
+       <textarea data-property-name="${fn:escapeXml(property_name)}" 
name="new-property-value" class="propinput form-control property-value" 
rows="${rows}">${value}</textarea>
+  </c:otherwise>
+</c:choose>
diff --git a/src/main/less/scaffolding.less 
b/src/main/resources/SLING-INF/libs/sling/resource-editor-static-content/css/ie.css
similarity index 77%
copy from src/main/less/scaffolding.less
copy to 
src/main/resources/SLING-INF/libs/sling/resource-editor-static-content/css/ie.css
index 75b563c..287decd 100644
--- a/src/main/less/scaffolding.less
+++ 
b/src/main/resources/SLING-INF/libs/sling/resource-editor-static-content/css/ie.css
@@ -17,14 +17,13 @@
  * under the License.
  */
  
-//
-// Scaffolding
-// --------------------------------------------------
+#login .nav-tabs > li > a, #login .tabbable .tab-content {
+       background-color: #202020;
+}
 
-
-// Body reset
-// -------------------------
-
-body {
-  .plate-text-shadow;
+#login_tab_content {
+       border-top-right-radius: 7px;
+       border-top-left-radius: 7px;
+       border-bottom-right-radius: 7px;
+       border-bottom-left-radius: 7px;
 }
\ No newline at end of file
diff --git 
a/src/main/resources/SLING-INF/libs/sling/resource-editor-static-content/js/properties/PropertyController.js
 
b/src/main/resources/SLING-INF/libs/sling/resource-editor-static-content/js/properties/PropertyController.js
new file mode 100644
index 0000000..ebddeab
--- /dev/null
+++ 
b/src/main/resources/SLING-INF/libs/sling/resource-editor-static-content/js/properties/PropertyController.js
@@ -0,0 +1,196 @@
+/*
+ * 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.
+ */
+
+// creating the namespace
+var org = org || {};
+org.apache = org.apache || {};
+org.apache.sling = org.apache.sling || {};
+org.apache.sling.reseditor = org.apache.sling.reseditor || {};
+
+/*
+ * The PropertyController is responsible for the property page functionality.
+ */
+
+//defining the module
+org.apache.sling.reseditor.PropertyController = (function() {
+
+       function PropertyController(settings, mainController){
+               this.mainController = mainController;
+               this.settings = settings;
+               
+               var thisPropertyController = this;
+               
+               $(document).ready(function() {
+                       $.notifyDefaults({
+                               delay: 500,
+                               template: '<div data-notify="container" 
class="col-xs-11 col-sm-3 growl-notify alert alert-{0}" role="alert">' +
+                               '<button type="button" aria-hidden="true" 
class="close" data-notify="dismiss">×</button>' +
+                               '<span data-notify="icon"></span> ' +
+                               '<span data-notify="title">{1}</span> ' +
+                               '<span data-notify="message">{2}</span>' +
+                               '<a href="{3}" target="{4}" 
data-notify="url"></a>' +
+                       '</div>'
+                       });
+
+                       $( "#properties" ).on( "click", 
".dropdown-menu.add-property-menu li a", function() {
+                               var dataType = 
$(this).attr('data-property-type');
+                               
thisPropertyController.openAddPropertyDialog(dataType);
+                       });
+                       $('#addPropertyDialog .submit').click(function(){
+                               thisPropertyController.addProperty();
+                       });
+                       $( "#properties" ).on( "click", 
".property-icon.glyphicon-remove", function() {
+                               var parentRow = $(this).parents(".row:first");
+                               var propertyKey = 
parentRow.find(".proplabel").attr("for");
+                               
thisPropertyController.removeProperty(propertyKey, parentRow);
+                       });
+                       $( "#properties" ).on( "click", 
".property-icon.glyphicon-save", function() {
+                               var parentRow = $(this).parents(".row:first");
+                               var key, value;
+                               if (parentRow.hasClass('new-property')){
+                                       key = $('#newStringPropertyKey').val();
+                               } else {
+                                       key = 
parentRow.find(".proplabel").attr("for");
+                               }
+                               value = parentRow.find(".form-control").val();
+                               
+                               thisPropertyController.saveProperty(key, value);
+                       });
+
+                       $("#properties-info-icon").on("click", function(e, 
data) {
+                               $('#properties 
.info-content-container').slideToggle();
+                       });
+                       $("#properties .info-content-container 
.close").on("click", function(e, data) {
+                               $('#properties 
.info-content-container').slideToggle();
+                       });
+                       $( "#properties" ).on( "keydown", function(event, data) 
{
+                       // see http://www.javascripter.net/faq/keycodes.htm
+                               if (event.ctrlKey || event.metaKey) {
+                                       var pressedKey = 
String.fromCharCode(event.which).toLowerCase();
+                                       var n = 78;
+                                       var s = 83;
+                                       var del = 46;
+                                       switch (event.which){
+                                           case s:
+                                               event.preventDefault();
+                                               var parentRow = $( 
document.activeElement ).parents(".row:first");
+                                               var key = 
parentRow.find(".proplabel").attr("for");
+                                                       var value = 
parentRow.find(".form-control").val();
+                                                       
thisPropertyController.saveProperty(key, value);
+                                               break;
+                                           case del:
+                                               event.preventDefault();
+                                               var parentRow = $( 
document.activeElement ).parents(".row:first");
+                                               var key = 
parentRow.find(".proplabel").attr("for");
+                                                       
thisPropertyController.removeProperty(key, parentRow);
+                                               break;
+                                           case n:
+                                               event.preventDefault();
+                                               $('#properties 
.add-property-menu-item.dropdown-toggle').dropdown('toggle');
+                                               break;
+                                       }
+                               }
+                       });
+               });
+       };
+       
+       PropertyController.prototype.openAddPropertyDialog = function(dataType){
+               $('#addPropertyDialog').modal('show');
+               $('#addPropertyDialog .property-editor').hide();
+               $("#addPropertyDialog 
.property-editor[data-property-type='"+dataType+"']").show();
+       };
+       
+       PropertyController.prototype.removeProperty = function(key, row){
+               var thisPropertyController = this;
+               var confirmationMsg = "You are about to delete the property 
with the key '"+key+"'. Are you sure?";
+               bootbox.confirm(confirmationMsg, function(result) {
+                       if (result){
+                               var data = {};
+                               data[key+"@Delete"] = "";
+                               $.ajax({
+                                 type: 'POST',
+                                 url: location.href,
+                                 dataType: "json",
+                                 data: data
+                               })
+                               .done(function() {
+                                       row.remove();
+                                       $.notify({
+                                               message: 'Property \''+key+'\' 
deleted.' 
+                                       },{
+                                               type: 'success'
+                                       });
+                               })
+                               .fail(function(errorJson) {
+                                       
thisPropertyController.mainController.displayAlert(errorJson);
+                               });
+                       }
+               });
+       };
+       
+       PropertyController.prototype.saveProperty = function(key, value){
+               var thisPropertyController = this;
+               var data = {};
+               data[key] = value;
+               data["_charset_"] = "utf-8";
+               $.ajax({
+                 type: 'POST',
+                 url: location.href,
+                 dataType: "json",
+                 data: data
+               })
+               .done(function() {
+                       $.notify({
+                               message: 'Property \''+key+'\' saved.' 
+                       },{
+                               type: 'success'
+                       });
+               })
+               .fail(function(errorJson) {
+                       
thisPropertyController.mainController.displayAlert(errorJson);
+               });
+       };
+
+       PropertyController.prototype.addProperty = function(){
+               var thisPropertyController = this;
+               var key = $('#new-property-key').val();
+               var value = $("#addPropertyDialog .property-editor:visible 
.property-value").val();
+               var data = {};
+               var propertyType = $("#addPropertyDialog 
.property-editor:visible").attr("data-property-type");
+               data[key] = value;
+               data[key+"@TypeHint"] = propertyType;
+               data["_charset_"] = "utf-8";
+               $.ajax({
+                 type: 'POST',
+                 "_charset_": "utf-8",
+                 url: location.href,
+                 dataType: "json",
+                 data: data
+               })
+               .done(function() {
+                        location.reload();
+               })
+               .fail(function(errorJson) {
+                       $('#addPropertyDialog').modal('hide');
+                       
thisPropertyController.mainController.displayAlert(errorJson);
+               });
+       }
+       
+       return PropertyController;
+}());
diff --git 
a/src/main/resources/SLING-INF/libs/sling/resource-editor-static-content/js/tree/AddNodeController.js
 
b/src/main/resources/SLING-INF/libs/sling/resource-editor-static-content/js/tree/AddNodeController.js
index 3c2571e..e5f0231 100644
--- 
a/src/main/resources/SLING-INF/libs/sling/resource-editor-static-content/js/tree/AddNodeController.js
+++ 
b/src/main/resources/SLING-INF/libs/sling/resource-editor-static-content/js/tree/AddNodeController.js
@@ -244,8 +244,6 @@ org.apache.sling.reseditor.AddNodeController = (function() {
                    }
                });
                
-               $('#addNodeDialog').modal('show');
-               
                var contextPath = this.mainController.getContextPath() == "/" 
&& resourcePath.length>0 && resourcePath.charAt(0)=="/" ? "" : 
this.mainController.getContextPath(); 
                this.lastAddNodeURL = contextPath+resourcePath;
 
@@ -270,8 +268,10 @@ org.apache.sling.reseditor.AddNodeController = (function() 
{
                                        return {id:searchTerm, text:searchTerm};
                                }
                        }).data("select2");
+                       
+                       $('#addNodeDialog').modal('show');
+                       
                        $('#addNodeDialog').addClass('add-node-finished');
-//                     $('#addNodeDialog').append('<div 
id="add-node-finished"></div>');
                });
        }
        
diff --git a/src/main/resources/SLING-INF/libs/sling/resource-editor/html.jsp 
b/src/main/resources/SLING-INF/libs/sling/resource-editor/html.jsp
index 170e0e0..86c0d50 100644
--- a/src/main/resources/SLING-INF/libs/sling/resource-editor/html.jsp
+++ b/src/main/resources/SLING-INF/libs/sling/resource-editor/html.jsp
@@ -22,7 +22,8 @@
 <%@ page import="javax.jcr.*,org.apache.sling.api.resource.Resource, 
org.apache.sling.api.resource.ValueMap"%>
 <%@ page import="java.security.Principal"%>
 <%@ taglib uri="http://java.sun.com/jsp/jstl/core"; prefix="c" %>
-<%@ taglib prefix="sling" uri="http://sling.apache.org/taglibs/sling/1.0"%>
+<%@ taglib uri="http://java.sun.com/jsp/jstl/functions"; prefix="fn" %>
+<%@ taglib prefix="sling" uri="http://sling.apache.org/taglibs/sling"%>
 
 <%@ page language="java" contentType="text/html; charset=UTF-8" 
pageEncoding="UTF-8"%>
 
@@ -36,6 +37,10 @@
 <link href='<%= request.getContextPath() 
%>/libs/sling/resource-editor-static-content/css/font.css' rel='stylesheet' 
type='text/css'>
  <!--[if lt IE 9]>
 <link href='<%= request.getContextPath() 
%>/libs/sling/resource-editor-static-content/css/font_ie.css' rel='stylesheet' 
type='text/css'>
+  <![endif]--> 
+ 
+ <!--[if IE]>
+<link href='<%= request.getContextPath() 
%>/libs/sling/resource-editor-static-content/css/ie.css' rel='stylesheet' 
type='text/css'>
   <![endif]-->
   
 <!-- 
@@ -50,10 +55,12 @@ original
 <script type="text/javascript" src="<%= request.getContextPath() 
%>/libs/sling/resource-editor-static-content/generated/3rd_party/js/bootbox.min.js"></script>
 <script type="text/javascript" src="<%= request.getContextPath() 
%>/libs/sling/resource-editor-static-content/generated/3rd_party/js/jstree.min.js"></script>
 <script type="text/javascript" src="<%= request.getContextPath() 
%>/libs/sling/resource-editor-static-content/generated/3rd_party/js/select2.min.js"></script>
+<script type="text/javascript" src="<%= request.getContextPath() 
%>/libs/sling/resource-editor-static-content/generated/3rd_party/js/bootstrap-notify.min.js"></script>
 
 <script type="text/javascript" src="<%= request.getContextPath() 
%>/libs/sling/resource-editor-static-content/js/tree/JSTreeAdapter.js"></script>
 <script type="text/javascript" src="<%= request.getContextPath() 
%>/libs/sling/resource-editor-static-content/js/tree/TreeController.js"></script>
 <script type="text/javascript" src="<%= request.getContextPath() 
%>/libs/sling/resource-editor-static-content/js/tree/AddNodeController.js"></script>
+<script type="text/javascript" src="<%= request.getContextPath() 
%>/libs/sling/resource-editor-static-content/js/properties/PropertyController.js"></script>
 <script type="text/javascript" src="<%= request.getContextPath() 
%>/libs/sling/resource-editor-static-content/js/LoginController.js"></script>
 <script type="text/javascript" src="<%= request.getContextPath() 
%>/libs/sling/resource-editor-static-content/js/MainController.js"></script>
 
@@ -109,6 +116,8 @@ var jsTreeAdapterSettings = {
 };
 new org.apache.sling.reseditor.JSTreeAdapter(jsTreeAdapterSettings, 
treeController, mainController);
 
+new org.apache.sling.reseditor.PropertyController({}, mainController);
+
 </script>      
 
 </head>
@@ -157,6 +166,7 @@ new 
org.apache.sling.reseditor.JSTreeAdapter(jsTreeAdapterSettings, treeControll
                                                </div>
                                    </div>
                                  </div>
+                                 
                                  <ul class="nav nav-tabs">
                                    <li class="active">
                                        <a id="login_tab" 
href="#login_tab_content" data-toggle="tab">Login</a>
@@ -203,78 +213,8 @@ new 
org.apache.sling.reseditor.JSTreeAdapter(jsTreeAdapterSettings, treeControll
                                        </div>
                                </div>
                        </div>
-                       <div class="col-sm-8">
-                               <div id="outer_content" class="plate">
-                                       <div class="ie9filter-plate-div">
-                                               <div id="inner_content_margin">
-                                                       <form 
action="not_configured_yet.change.properties" method="post">
-                                                               <c:set 
var="resourceIsNode" scope="request" value="<%=resource.adaptTo(Node.class) 
!=null %>"/>
-                                                               <c:choose>
-                                                                    <c:when 
test="${resourceIsNode}" >
-                                                                               
<%--
-                                                                               
For some reason I get the following exception when using the JSTL expression 
'${currentNode.properties}'
-                                                                               
instead of the scriptlet code 'currentNode.getProperties()':
-                                                                               
org.apache.sling.scripting.jsp.jasper.JasperException: Unable to compile class 
for JSP: 
-                                                                               
org.apache.sling.scripting.jsp.jasper.el.JspValueExpression cannot be resolved 
to a type
-                                                                               
see https://issues.apache.org/jira/browse/SLING-2455
-                                                                               
 --%>
-                                                                               
<c:forEach var="property" items="<%=currentNode.getProperties()%>">
-                                                                       <%  
Property property = (Property) pageContext.getAttribute("property");%>
-                                                                               
        <fieldset>
-                                                                               
                <label class="proplabel" 
for='${property.name}'>${property.name} 
[<%=PropertyType.nameFromValue(property.getType())%>${property.multiple ? ' 
multiple' : ''}]</label>
-                                                                               
                <c:choose>
-                                                                               
                     <c:when test="${property.multiple}" >
-                                                                               
                        <fieldset class="propmultival_fieldset">
-                                                                               
                                <div>&nbsp;</div>
-                                                                               
                        <c:forEach var="value" 
items="<%=property.getValues()%>">
-                                                                               
                                <c:choose>
-                                                                               
                                <c:when test="${property.type == 
PropertyType.BINARY}" >
-                                                                               
                                        <p>I'm a binary property</p>
-                                                                               
                                     </c:when>
-                                                                               
                                     <c:otherwise>
-                                                                               
                                        <input class="propinputmultival 
form-control" value="${value.string}"/>
-                                                                               
                                     </c:otherwise>
-                                                                               
                                     </c:choose>
-                                                                               
                        </c:forEach>
-                                                                               
                        </fieldset>
-                                                                               
                     </c:when>
-                                                                               
                     <c:when test="${false}" >
-                                                                               
                     </c:when>
-                                                                               
                     <c:otherwise>
-                                                                               
                             <c:choose>
-                                                                               
                             <c:when test="<%=property.getType() == 
PropertyType.BINARY%>" >
-                                                                               
                                <c:choose>
-                                                                               
                                        <c:when 
test='<%=currentNode.getParent().isNodeType("nt:file") %>'>
-                                                                               
                                                <a class="propinput" href="<%= 
request.getContextPath() %>${resource.parent.path}">Download</a>
-                                                                               
                                        </c:when>
-                                                                               
                                        <c:otherwise>
-                                                                               
                                                <a class="propinput" href="<%= 
request.getContextPath() 
%>${resource.path}.property.download?property=${property.name}">View (choose 
"Save as..." to download)</a>
-                                                                               
                                        </c:otherwise>
-                                                                               
                                </c:choose>
-                                                                               
                             </c:when>
-                                                                               
                             <c:otherwise>
-                                                                               
                                        <input class="propinput form-control" 
id="${property.name}" name="${property.name}" value="${property.string}"/>      
                                                  
-                                                                               
                             </c:otherwise>
-                                                                               
                             </c:choose>
-                                                                               
                     </c:otherwise>
-                                                                               
                 </c:choose>
-                                                                               
        </fieldset>
-                                                                               
</c:forEach>
-                                                                    </c:when>
-                                                                    
<c:otherwise>
-                                                                               
<c:forEach var="property" items="<%=resource.adaptTo(ValueMap.class)%>">        
-                                                                               
        <fieldset>                                                              
                
-                                                                               
                <label class="proplabel" 
for='${property.key}'>${property.key}</label>
-                                                                               
                <input class="propinput form-control" id="${property.key}" 
name="${property.key}" value="${property.value}"/>
-                                                                               
        </fieldset>                                                     
-                                                                               
</c:forEach>
-                                                                    
</c:otherwise>
-                                                                </c:choose>
-                                                       </form>
-                                               </div>
-                                       </div>
-                           </div>
-                       </div>
+                       
+                       <%@ include file="properties.jsp" %>
            </div>
                <div class="row" style="visibility:hidden; display:none;">
                        <div class="col-sm-12">
diff --git 
a/src/main/resources/SLING-INF/libs/sling/resource-editor/nodes.json.incl.jsp 
b/src/main/resources/SLING-INF/libs/sling/resource-editor/nodes.json.incl.jsp
index c6a44bc..72cb589 100644
--- 
a/src/main/resources/SLING-INF/libs/sling/resource-editor/nodes.json.incl.jsp
+++ 
b/src/main/resources/SLING-INF/libs/sling/resource-editor/nodes.json.incl.jsp
@@ -17,8 +17,8 @@
   under the License.
 --%>
 [
-       <c:forEach var="theResource" items="<%=resource.listChildren()%>" 
varStatus="status">
-               <c:set var="resourceIsNode" scope="request" 
value="<%=resource.adaptTo(Node.class) !=null %>"/>
+       <c:forEach var="theResource" items="${sling:listChildren(resource)}" 
varStatus="status">
+               <c:set var="resourceIsNode" scope="request" 
value="${sling:adaptTo(resource,'javax.jcr.Node') != null}"/>
                <%--Hiding the resource provider root. --%>
                <c:if test="${theResource.path != '/reseditor'}">
                        <% Resource theResource = (Resource) 
pageContext.getAttribute("theResource");
diff --git 
a/src/main/resources/SLING-INF/libs/sling/resource-editor/nodes.json.jsp 
b/src/main/resources/SLING-INF/libs/sling/resource-editor/nodes.json.jsp
index faa6f80..09f90d9 100644
--- a/src/main/resources/SLING-INF/libs/sling/resource-editor/nodes.json.jsp
+++ b/src/main/resources/SLING-INF/libs/sling/resource-editor/nodes.json.jsp
@@ -26,7 +26,7 @@
 
 <%@ taglib uri="http://java.sun.com/jsp/jstl/core"; prefix="c" %>
 <%@ taglib uri="http://java.sun.com/jsp/jstl/functions"; prefix="fn" %>
-<%@ taglib prefix="sling" uri="http://sling.apache.org/taglibs/sling/1.0"%>
+<%@ taglib prefix="sling" uri="http://sling.apache.org/taglibs/sling"%>
 <sling:defineObjects />
 <% response.setContentType("application/json"); %>
 
diff --git 
a/src/main/resources/SLING-INF/libs/sling/resource-editor/properties.jsp 
b/src/main/resources/SLING-INF/libs/sling/resource-editor/properties.jsp
new file mode 100644
index 0000000..6b75ad5
--- /dev/null
+++ b/src/main/resources/SLING-INF/libs/sling/resource-editor/properties.jsp
@@ -0,0 +1,180 @@
+<%@ taglib uri="http://java.sun.com/jsp/jstl/functions"; prefix="fn" %>
+<%@ taglib prefix="re" uri="http://sling.apache.org/resource-editor"%>
+
+<sling:defineObjects />
+
+                       <div id="properties" class="col-sm-8">
+                               <div id="outer_content" class="plate">
+                                       <div class="ie9filter-plate-div">
+                                               <div id="inner_content_margin">
+                                                       <div class="row">
+                                                               <div 
class="col-sm-12">
+                                                                       <div 
style="display: none;" class="info-content-container" >
+                                                                               
<div class="well well-sm info-content">
+                                                                               
        <button type="button" class="close"><span 
aria-hidden="true">&times;</span><span class="sr-only">Close</span></button>
+                                                                               
        <h4>Cheat Sheet</h4>
+                                                                               
        <p>You can use</p>
+                                                                               
        <ul>
+                                                                               
                <li><kbd><kbd>ctrl</kbd> + <kbd>s</kbd></kbd> or 
<kbd><kbd>cmd</kbd> + <kbd>s</kbd></kbd> (for Mac) for saving a property.</li>
+                                                                               
                <li><kbd><kbd>ctrl</kbd> + <kbd>del</kbd></kbd> or 
<kbd><kbd>cmd</kbd> + <kbd>del</kbd></kbd> (for Mac) for removing a 
property.</li>
+                                                                               
                <li><kbd><kbd>ctrl</kbd> + <kbd>n</kbd></kbd> or 
<kbd><kbd>cmd</kbd> + <kbd>n</kbd></kbd> (for Mac) for opening the add property 
menu.</li>
+                                                                               
        </ul>
+                                                                               
</div>
+                                                                       </div>  
+                                                                       <span 
id="properties-info-icon" class="info-icon info-icon-lightgray pull-right 
clearfix" ></span>
+                                                                       <ul 
class="nav nav-pills">
+                                                                         <li 
class="dropdown" role="presentation">
+                                                                               
<a class="add-property-menu-item dropdown-toggle" data-toggle="dropdown"  
href="#"><span class=""><span class="glyphicon glyphicon-plus"></span><span 
class="caret"></span></span>      
+                                                                               
</a>
+                                                                               
    <ul class="dropdown-menu add-property-menu" role="menu" 
aria-labelledby="propertyTypeMenu">
+                                                                               
        <li><a tabindex="-1" href="#" 
data-property-type="String">String</a></li>
+                                                                               
        <li><a tabindex="-1" href="#" data-property-type="Date">Date</a></li>
+                                                                               
        <li><a tabindex="-1" href="#" 
data-property-type="Boolean">Boolean</a></li>
+                                                                               
        <li><a tabindex="-1" href="#" data-property-type="Long">Long</a></li>
+                                                                               
        <li><a tabindex="-1" href="#" 
data-property-type="Double">Double</a></li>
+                                                                               
        <li><a tabindex="-1" href="#" 
data-property-type="Decimal">Decimal</a></li>
+                                                                               
        <li><a tabindex="-1" href="#" 
data-property-type="Binary">Binary</a></li>
+                                                                               
        <li><a tabindex="-1" href="#" data-property-type="Name">Name</a></li>
+                                                                               
        <li><a tabindex="-1" href="#" data-property-type="Path">Path</a></li>
+                                                                               
        <li><a tabindex="-1" href="#" 
data-property-type="Reference">Reference</a></li>
+                                                                               
        <li><a tabindex="-1" href="#" data-property-type="Uri">URI</a></li>
+                                                                               
    </ul>
+                                                                         </li>
+                                                                       </ul>
+                                                               </div>
+                                                       </div>
+                                                       <form 
action="not_configured_yet.change.properties" method="post">
+                                                               <c:set 
var="resourceIsNode" scope="request" value="<%=resource.adaptTo(Node.class) 
!=null %>"/>
+                                                               <c:choose>
+                                                                    <c:when 
test="${resourceIsNode}" >
+                                                                               
<%--
+                                                                               
For some reason I get the following exception when using the JSTL expression 
'${currentNode.properties}'
+                                                                               
instead of the scriptlet code 'currentNode.getProperties()':
+                                                                               
org.apache.sling.scripting.jsp.jasper.JasperException: Unable to compile class 
for JSP: 
+                                                                               
org.apache.sling.scripting.jsp.jasper.el.JspValueExpression cannot be resolved 
to a type
+                                                                               
see https://issues.apache.org/jira/browse/SLING-2455
+                                                                               
 --%>
+                                                                               
<c:forEach var="property" items="<%=currentNode.getProperties()%>" 
varStatus="propertyLoopStatus">
+                                                                       <%  
Property property = (Property) pageContext.getAttribute("property");%>
+                                                                               
        <div id="property-${propertyLoopStatus.index}" class="row property-row" 
data-property-name="${fn:escapeXml(property.name)}" >
+                                                                               
                <fieldset>
+                                                                               
                        <div class="col-sm-3">
+                                                                               
                                <label class="proplabel" 
for='${property.name}'>${property.name} 
[<%=PropertyType.nameFromValue(property.getType())%>${property.multiple ? ' 
multiple' : ''}]</label>
+                                                                               
                        </div>
+                                                                               
                        <div class="col-sm-7 property-col">
+                                                                               
                                <c:choose>
+                                                                               
                                     <c:when test="${property.multiple}" >
+                                                                               
                                        <fieldset class="propmultival_fieldset">
+                                                                               
                                                <div>&nbsp;</div>
+                                                                               
                                        <c:forEach var="value" 
items="<%=property.getValues()%>">
+                                                                               
                                                <c:choose>
+                                                                               
                                                        <c:when 
test="${property.type == PropertyType.BINARY}" >
+                                                                               
                                                                <p>I'm a binary 
property</p>
+                                                                               
                                                             </c:when>
+                                                                               
                                                        <c:when 
test="${property.type == PropertyType.STRING}" >
+                                                                               
                                                                
<re:string-editor></re:string-editor>
+                                                                               
                                                             </c:when>
+                                                                               
                                                             <c:otherwise>
+                                                                               
                                                                <input 
class="propinputmultival form-control" value="${value.string}"/>
+                                                                               
                                                             </c:otherwise>
+                                                                               
                                                     </c:choose>
+                                                                               
                                        </c:forEach>
+                                                                               
                                        </fieldset>
+                                                                               
                                     </c:when>
+                                                                               
                                     <c:otherwise>
+                                                                               
                                             <c:choose>
+                                                                               
                                                     <c:when 
test="<%=property.getType() == PropertyType.BINARY%>" >
+                                                                               
                                                        <c:choose>
+                                                                               
                                                                <c:when 
test='<%=currentNode.getParent().isNodeType("nt:file") %>'>
+                                                                               
                                                                        <a 
class="propinput" href="<%= request.getContextPath() 
%>${resource.parent.path}">Download</a>
+                                                                               
                                                                </c:when>
+                                                                               
                                                                <c:otherwise>
+                                                                               
                                                                        <a 
class="propinput" href="<%= request.getContextPath() 
%>${resource.path}.property.download?property=${property.name}">View (choose 
"Save as..." to download)</a>
+                                                                               
                                                                </c:otherwise>
+                                                                               
                                                        </c:choose>
+                                                                               
                                                     </c:when>
+                                                                               
                                                     <c:when 
test="<%=property.getType() == PropertyType.STRING%>" >
+                                                                               
                                                        <re:string-editor 
property_name="${fn:escapeXml(property.name)}-editor" 
value="${property.string}"></re:string-editor>
+                                                                               
                                                     </c:when>
+                                                                               
                                                     <c:when 
test="<%=property.getType() == PropertyType.PATH%>" >
+                                                                               
                                                        <re:path-editor 
value="${property.string}" 
component_id="property-${propertyLoopStatus.index}-path-editor"></re:path-editor>
+                                                                               
                                                        <re:path-viewer 
value="${property.string}" 
component_id="property-${propertyLoopStatus.index}-path-viewer" 
editor_component_id="property-${propertyLoopStatus.index}-path-editor"></re:path-viewer>
+                                                                               
                                                     </c:when>
+                                                                               
                                                     <c:otherwise>
+                                                                               
                                                                <input 
class="propinput form-control" id="${property.name}" name="${property.name}" 
value="${property.string}"/>                                                    
    
+                                                                               
                                                     </c:otherwise>
+                                                                               
                                             </c:choose>
+                                                                               
                                     </c:otherwise>
+                                                                               
                                 </c:choose>
+                                                                               
                        </div>
+                                                                               
                        <div class="col-sm-2">
+                                                                               
                                <span class="icon property-icon glyphicon 
glyphicon-save" aria-hidden="true"></span>
+                                                                               
                                <span class="icon property-icon glyphicon 
glyphicon-remove" aria-hidden="true"></span>
+                                                                               
                        </div>
+                                                                               
                </fieldset>
+                                                                               
        </div>
+                                                                               
</c:forEach>
+                                                                    </c:when>
+                                                                    
<c:otherwise>
+                                                                               
<c:forEach var="property" items="<%=resource.adaptTo(ValueMap.class)%>">        
+                                                                               
        <div class="row">
+                                                                               
                <fieldset>                      
+                                                                               
                        <div class="col-sm-3">                                  
                
+                                                                               
                                <label class="proplabel" 
for='${property.key}'>${property.key}</label>
+                                                                               
                        </div>
+                                                                               
                        <div class="col-sm-7">
+                                                                               
                                <input class="propinput form-control" 
id="${property.key}" name="${property.key}" value="${property.value}"/>
+                                                                               
                        </div>
+                                                                               
                </fieldset>
+                                                                               
        </div>                                                  
+                                                                               
</c:forEach>
+                                                                    
</c:otherwise>
+                                                                </c:choose>
+                                                       </form>
+                                               </div>
+                                       </div>
+                           </div>
+                       </div>
+       <div class="modal fade" id="addPropertyDialog" tabindex="-1" 
role="dialog" aria-labelledby="addPropertyDialogLabel" aria-hidden="true">
+         <div class="modal-dialog modal-lg">
+           <div class="modal-content">
+                     <div class="modal-header">
+                       <button type="button" class="close" 
data-dismiss="modal"><span aria-hidden="true">&times;</span><span 
class="sr-only">Close</span></button>
+                       <h4 class="modal-title" id="addPropertyDialogLabel">Add 
Property</h4>
+                     </div>
+                     <div class="modal-body">
+                               <div class="container-fluid">
+                                                                        <div 
class="row new-property">
+                                                                               
<fieldset>                                                              
+                                                                               
        <div class="col-sm-1">
+                                                                               
                <label class="proplabel" for='new-property-key'>Key</label>
+                                                                               
        </div>
+                                                                               
        <div class="col-sm-3">
+                                                                               
                <input id="new-property-key" class="propinput form-control" 
name="newPropertyKey" />
+                                                                               
        </div>                                          
+                                                                               
        <div class="col-sm-1">
+                                                                               
                <label class="proplabel" for='new-property-value'>Value</label>
+                                                                               
        </div>
+                                                                               
        <div class="col-sm-7">
+                                                                               
                <fieldset>                                                      
        
+                                                                               
                        <label class="sr-only" 
for='new-property-value'>Value</label>   
+                                                                               
                        <div class="property-editor" data-property-type="Path">
+<%--                                                                           
                                <sling:include resource="${resource}" 
resourceType="sling/resource-editor/property-editor" 
addSelectors="path-editor"/> --%>
+                                                                               
                                <re:path-editor value="" 
component_id="property-path-editor-new"></re:path-editor>
+                                                                               
                        </div>          
+                                                                               
                        <div class="property-editor" 
data-property-type="String">
+                                                                               
                                <re:string-editor rows="4"></re:string-editor>
+                                                                               
                        </div>
+                                                                               
                </fieldset>             
+                                                                               
        </div>  
+                                                                               
        </fieldset>             
+                                                                       </div>  
+                                       </div>
+                     </div>
+                     <div class="modal-footer">
+                       <button type="button" class="btn btn-default" 
data-dismiss="modal">Close</button>
+                       <button type="button" class="btn btn-primary 
submit">Save changes</button>
+                     </div>
+           </div>
+         </div>
+       </div>
\ No newline at end of file
diff --git 
a/src/main/resources/SLING-INF/libs/sling/resource-editor/rootnodes.json.jsp 
b/src/main/resources/SLING-INF/libs/sling/resource-editor/rootnodes.json.jsp
index 1457dbe..b2821b7 100644
--- a/src/main/resources/SLING-INF/libs/sling/resource-editor/rootnodes.json.jsp
+++ b/src/main/resources/SLING-INF/libs/sling/resource-editor/rootnodes.json.jsp
@@ -27,7 +27,7 @@
 
 <%@ taglib uri="http://java.sun.com/jsp/jstl/core"; prefix="c" %>
 <%@ taglib uri="http://java.sun.com/jsp/jstl/functions"; prefix="fn" %>
-<%@ taglib prefix="sling" uri="http://sling.apache.org/taglibs/sling/1.0"%>
+<%@ taglib prefix="sling" uri="http://sling.apache.org/taglibs/sling"%>
 <sling:defineObjects />
 <% response.setContentType("application/json"); %>
 [{
diff --git a/src/test/javascript/e2e/spec/e2e_spec.js 
b/src/test/javascript/e2e/spec/e2e_spec.js
index 9143602..984cf83 100644
--- a/src/test/javascript/e2e/spec/e2e_spec.js
+++ b/src/test/javascript/e2e/spec/e2e_spec.js
@@ -29,28 +29,7 @@ describe('A user of the Apache Sling Resource Editor', 
function() {
        client.timeouts("script", 1000);
        client.timeouts("implicit", 1000);
        client.timeouts("page load", 1000);
-
-       describe('can open the add node dialog with', function() {
-                 it('the icon', function(done) {
-                         client.url(homeURL).waitForExist('#last-element').
-                         click('#root_anchor 
i.add-icon').waitForVisible('#addNodeDialog', function(err, visible) {
-                         assert(typeof err === "undefined" || err === null);
-                         assert(true === visible);
-                     })
-                     .call(done);
-                 });
-
-                 it('the shortcut', function(done) {
-                          client.url(homeURL).waitForExist('#last-element')
-                         .click('#root_anchor i.jstree-themeicon')
-                         .keys("c").waitForVisible('#addNodeDialog', 
function(err, visible) {
-                         assert(typeof err === "undefined" || err === null);
-                         assert(true === visible);
-                     })
-                     .call(done);
-                 });
-       });
-
+       
          it('can login as admin', function(done) {
                  client.url(homeURL).waitForExist('#last-element')
                  .click('#login_tab').waitForVisible('#login_submit')
@@ -58,170 +37,334 @@ describe('A user of the Apache Sling Resource Editor', 
function() {
                  .setValue('#login_form input[name="j_password"]', 'admin')
                  .click('#login_submit').waitForExist('#login .logout')
                  .getText('#login_tab', function(err, text) {
-                 assert(typeof err === "undefined" || err === null);
+                 assert(typeof err === "undefined" || err === null);
                          assert("Logout admin" === text);
              })
              .call(done);
          });
-         
-         it('can add an unstructured node to the root node', function(done) {
-                 client.url(homeURL).waitForExist('#last-element')
-                 .click("#root 
i.add-icon").waitForVisible('#addNodeDialog.add-node-finished 
.node_name_dd_container input')
-                 .setValue('.node_name_dd_container input', "aTestNode")
-                 .addValue('.node_name_dd_container input', 'Return') // 
presses the 'return' key
-                 .click('#addNodeDialog 
.btn.btn-primary.submit').waitForExist("#root li[nodename=\"aTestNode\"]", 
function(err, existed) {
-                         assert(typeof err === "undefined" || err === null);
-                         assert(existed === true);
-             })
-             .call(done);
-         });
-         
-        it('can add a node with an encoded name on the second level ', 
function(done) {
-                 client.url(homeURL).waitForExist('#last-element')
-                 .click("#root li[nodename=\"aTestNode\"] 
i.add-icon").waitForVisible('#addNodeDialog.add-node-finished 
.node_name_dd_container input')
-                 .setValue('.node_name_dd_container input', "täßt ?<>")
-                 .addValue('.node_name_dd_container input', 'Return') // 
presses the 'return' key
-                 .click('#addNodeDialog 
.btn.btn-primary.submit').waitForExist("#root  
li[nodename=\"aTestNode\"].opened li[nodename=\"täßt ?&lt;&gt;\"]", 
function(err, existed) {
-                         assert(typeof err === "undefined" || err === null);
-                         assert(existed === true);
-             })
-             .call(done); 
-         });
-        
-         it('can link to a node with an encoded name', function(done) {
-                 var encodedNodeNameSelector = '#root 
li[nodename="aTestNode"].opened li[nodename="täßt ?&lt;&gt;"]';
-                 var encodedNodeNameOpenSelector = encodedNodeNameSelector +' 
i.open-icon';
-                 client.url(homeURL).waitForExist('#last-element')
-                 .click("#root li[nodename=\"aTestNode\"] 
i.jstree-ocl").waitForExist(encodedNodeNameOpenSelector)
-                 
.click(encodedNodeNameOpenSelector).waitForExist(encodedNodeNameSelector+' 
a.jstree-clicked', function(err, existed) {
-                         assert(typeof err === "undefined" || err === null);
-                         assert(existed === true);
-             })
-             .call(done);
-         });
-         
-
-         it('can add a node with a specific node type ', function(done) {
-                 client.url(homeURL);
-                 client.waitForExist('#last-element').click("#root 
li[nodename=\"aTestNode\"] 
i.add-icon").waitForVisible('#addNodeDialog.add-node-finished 
.node_name_dd_container', 1000)
-                 .setValue('.node_name_dd_container input', "aFolder")
-                 .addValue('.node_name_dd_container input', 'Return')
-                 .click(".form-group.node-type 
.select2-chosen").waitForExist('.node_type_dd_container input')
-                 .setValue('.node_type_dd_container input', "sling:Folder")
-                 .addValue('.node_type_dd_container input', 'Return')
-                 .click('#addNodeDialog 
.btn.btn-primary.submit').waitForExist('#root  li[nodename="aTestNode"] 
li[nodename="aFolder"][nodetype="sling:Folder"]', function(err, existed) {
-                         assert(typeof err === "undefined" || err === null);
-                         assert(existed === true);
-                 })
-             .call(done);
-         });
-         
-         it('can add a node with a resource type on the second level ', 
function(done) {
-                 var nodeName =  "a node with a resource type";
-                 var resourceType =  "test/resource-editor/resource-type";
-                 var resourceTypeSelector = '#root  
li[nodename="aTestNode"].opened li[nodename="a node with a resource type"] 
span.node-type';
-                 client.url(homeURL);
-                 client.waitForExist('#last-element').click("#root 
li[nodename=\"aTestNode\"] i.add-icon")
-                 .waitForVisible('#addNodeDialog.add-node-finished 
.node_name_dd_container', 1000)
-                 .setValue('.node_name_dd_container input', nodeName)
-                 .addValue('.node_name_dd_container input', 'Return') // 
presses the 'return' key
-                 .click(".form-group.resource-type 
.select2-chosen").waitForExist('.resource_type_dd_container input', 1000)
-                 .setValue('.resource_type_dd_container input', resourceType)
-                 .addValue('.resource_type_dd_container input', 'Return') // 
presses the 'return' key
-                 .click('#addNodeDialog 
.btn.btn-primary.submit').waitForExist(resourceTypeSelector, 1000)
-                 .getText(resourceTypeSelector, function(err, text) {
-                         assert(typeof err === "undefined" || err === null);
-                         assert(text === resourceType);
-                 })
-             .call(done);
-         });
-         
-         it('can rename a node with an encoded name', function(done) {
-                 client = client.url(homeURL);
-                 client.waitForExist('#last-element', function(err) {
-                         client.click("#root li[nodename=\"aTestNode\"] 
i.jstree-ocl", function(err, res) {
-                                 var encodedNodeNameSelector = '#root 
li[nodename="aTestNode"].opened li[nodename="täßt ?&lt;&gt;"]';
-                                 var encodedNodeNameAnchorSelector = 
encodedNodeNameSelector +' a .node-type';
-//                               The open node animation will take longer than 
500ms thus setting 2000ms as max.
-                                 
client.waitForExist(encodedNodeNameAnchorSelector, 2000, function(err, existed) 
{
-                                         
client.doubleClick(encodedNodeNameAnchorSelector, function(err) {
-                                                 var 
encodedNodeNameInputSelector = encodedNodeNameSelector+' 
input.jstree-rename-input';
-                                                 
client.waitForExist(encodedNodeNameInputSelector, function(err, existed) {
-                                                         
client.setValue(encodedNodeNameInputSelector, 'täßt2& <>');
-                                                         
client.execute(function() {
-                                                                 $('#root 
li[nodename="aTestNode"] li[nodename="täßt ?&lt;&gt;"] 
input.jstree-rename-input').blur();
-                                                                 $('#root 
li[nodename="aTestNode"] li[nodename="täßt ?&lt;&gt;"] 
input.jstree-rename-input').blur();
-                                                               });
-                                                         
client.waitForExist('#root li[nodename="aTestNode"].opened 
li[nodename="täßt2&amp; &lt;&gt;"]', 2000, function(err, existed) {
-                                                                 assert(typeof 
err === "undefined" || err === null);
-                                                                 assert(true 
=== existed);
-                                                                 
+       
+       describe('can manage nodes as he', function() {
+                 
+               describe('can open the add node dialog with', function() {
+                         it('the icon', function(done) {
+                                 
client.url(homeURL).waitForExist('#last-element').
+                                 click('#root_anchor 
i.add-icon').waitForVisible('#addNodeDialog', function(err, visible) {
+                                 assert(typeof err === "undefined" || err === 
null);
+                                 assert(true === visible);
+                             })
+                             .call(done);
+                         });
+       
+                         it('the shortcut', function(done) {
+                                  
client.url(homeURL).waitForExist('#last-element')
+                                 .click('#root_anchor i.jstree-themeicon')
+                                 .keys("c").waitForVisible('#addNodeDialog', 
function(err, visible) {
+                                 assert(typeof err === "undefined" || err === 
null);
+                                 assert(true === visible);
+                             })
+                             .call(done);
+                         });
+               });
+       
+                 
+                 it('can add an unstructured node to the root node', 
function(done) {
+                         client.url(homeURL).waitForExist('#last-element')
+                         .click("#root 
i.add-icon").waitForVisible('#addNodeDialog.add-node-finished 
.node_name_dd_container input', 1000)
+                         .setValue('.node_name_dd_container input', 
"aTestNode")
+                         .addValue('.node_name_dd_container input', 'Return') 
// presses the 'return' key
+                         .click('#addNodeDialog 
.btn.btn-primary.submit').waitForExist("#root li[nodename=\"aTestNode\"]", 
function(err, existed) {
+                                 assert(typeof err === "undefined" || err === 
null);
+                                 assert(existed === true);
+                     })
+                     .call(done);
+                 });
+                 
+                it('can add a node with an encoded name on the second level ', 
function(done) {
+                         client.url(homeURL).waitForExist('#last-element')
+                         .click("#root li[nodename=\"aTestNode\"] 
i.add-icon").waitForVisible('#addNodeDialog.add-node-finished 
.node_name_dd_container input', 1000)
+                         .setValue('.node_name_dd_container input', "täßt ?<>")
+                         .addValue('.node_name_dd_container input', 'Return') 
// presses the 'return' key
+                         .click('#addNodeDialog 
.btn.btn-primary.submit').waitForExist("#root  
li[nodename=\"aTestNode\"].opened li[nodename=\"täßt ?&lt;&gt;\"]", 
function(err, existed) {
+                                 assert(typeof err === "undefined" || err === 
null);
+                                 assert(existed === true);
+                     })
+                     .call(done); 
+                 });
+                
+                 it('can link to a node with an encoded name', function(done) {
+                         var encodedNodeNameSelector = '#root 
li[nodename="aTestNode"].opened li[nodename="täßt ?&lt;&gt;"]';
+                         var encodedNodeNameOpenSelector = 
encodedNodeNameSelector +' i.open-icon';
+                         client.url(homeURL).waitForExist('#last-element')
+                         .click("#root li[nodename=\"aTestNode\"] 
i.jstree-ocl").waitForExist(encodedNodeNameOpenSelector)
+                         
.click(encodedNodeNameOpenSelector).waitForExist(encodedNodeNameSelector+' 
a.jstree-clicked', function(err, existed) {
+                                 assert(typeof err === "undefined" || err === 
null);
+                                 assert(existed === true);
+                     })
+                     .call(done);
+                 });
+                 
+       
+                 it('can add a node with a specific node type ', 
function(done) {
+                         client.url(homeURL);
+                         client.waitForExist('#last-element').click("#root 
li[nodename=\"aTestNode\"] 
i.add-icon").waitForVisible('#addNodeDialog.add-node-finished 
.node_name_dd_container', 1000)
+                         .setValue('.node_name_dd_container input', "aFolder")
+                         .addValue('.node_name_dd_container input', 'Return')
+                         .click(".form-group.node-type 
.select2-chosen").waitForExist('.node_type_dd_container input')
+                         .setValue('.node_type_dd_container input', 
"sling:Folder")
+                         .addValue('.node_type_dd_container input', 'Return')
+                         .click('#addNodeDialog 
.btn.btn-primary.submit').waitForExist('#root  li[nodename="aTestNode"] 
li[nodename="aFolder"][nodetype="sling:Folder"]', function(err, existed) {
+                                 assert(typeof err === "undefined" || err === 
null);
+                                 assert(existed === true);
+                         })
+                     .call(done);
+                 });
+                 
+                 it('can add a node with a resource type on the second level 
', function(done) {
+                         var nodeName =  "a node with a resource type";
+                         var resourceType =  
"test/resource-editor/resource-type";
+                         var resourceTypeSelector = '#root  
li[nodename="aTestNode"].opened li[nodename="a node with a resource type"] 
span.node-type';
+                         client.url(homeURL);
+                         client.waitForExist('#last-element').click("#root 
li[nodename=\"aTestNode\"] i.add-icon")
+                         .waitForVisible('#addNodeDialog.add-node-finished 
.node_name_dd_container', 1000)
+                         .setValue('.node_name_dd_container input', nodeName)
+                         .addValue('.node_name_dd_container input', 'Return') 
// presses the 'return' key
+                         .click(".form-group.resource-type 
.select2-chosen").waitForExist('.resource_type_dd_container input', 1000)
+                         .setValue('.resource_type_dd_container input', 
resourceType)
+                         .addValue('.resource_type_dd_container input', 
'Return') // presses the 'return' key
+                         .click('#addNodeDialog 
.btn.btn-primary.submit').waitForExist(resourceTypeSelector, 1000)
+                         .getText(resourceTypeSelector, function(err, text) {
+                                 assert(typeof err === "undefined" || err === 
null);
+                                 assert(text === resourceType);
+                         })
+                     .call(done);
+                 });
+                 
+                 it('can rename a node with an encoded name', function(done) {
+                         client = client.url(homeURL);
+                         client.waitForExist('#last-element', function(err) {
+                                 client.click("#root 
li[nodename=\"aTestNode\"] i.jstree-ocl", function(err, res) {
+                                         var encodedNodeNameSelector = '#root 
li[nodename="aTestNode"].opened li[nodename="täßt ?&lt;&gt;"]';
+                                         var encodedNodeNameAnchorSelector = 
encodedNodeNameSelector +' a .node-type';
+       //                                The open node animation will take 
longer than 500ms thus setting 2000ms as max.
+                                         
client.waitForExist(encodedNodeNameAnchorSelector, 2000, function(err, existed) 
{
+                                                 
client.doubleClick(encodedNodeNameAnchorSelector, function(err) {
+                                                         var 
encodedNodeNameInputSelector = encodedNodeNameSelector+' 
input.jstree-rename-input';
+                                                         
client.waitForExist(encodedNodeNameInputSelector, function(err, existed) {
+                                                                 
client.setValue(encodedNodeNameInputSelector, 'täßt2& <>');
+                                                                 
client.execute(function() {
+                                                                         
$('#root li[nodename="aTestNode"] li[nodename="täßt ?&lt;&gt;"] 
input.jstree-rename-input').blur();
+                                                                         
$('#root li[nodename="aTestNode"] li[nodename="täßt ?&lt;&gt;"] 
input.jstree-rename-input').blur();
+                                                                       });
+                                                                 
client.waitForExist('#root li[nodename="aTestNode"].opened 
li[nodename="täßt2&amp; &lt;&gt;"]', 2000, function(err, existed) {
+                                                                         
assert(typeof err === "undefined" || err === null);
+                                                                         
assert(true === existed);
+                                                                         
+                                                                 });
                                                          });
                                                  });
-                                         });
+                                     })  
                              })  
-                     })  
-             })
-             .call(done);
+                     })
+                     .call(done);
+                 });
+                 it('can delete nodes via multi selection and shortcut', 
function(done) {
+                         client = client.url(homeURL);
+                         client
+                         .waitForExist('#last-element').click("#root 
li[nodename=\"aTestNode\"] i.add-icon")
+                               
.waitForVisible('#addNodeDialog.add-node-finished', 1000).click('#addNodeDialog 
.btn.btn-primary.submit')
+                               // The open node animation will take longer 
than 500ms thus setting 2000ms as max.
+                               .waitForExist('#root 
li[nodename="aTestNode"].opened', 2000).elements('#root 
li[nodename="aTestNode"].opened li a .jstree-themeicon', function(err, res) {
+                                   client
+                                .moveTo(res.value[0].ELEMENT, 0, 0)
+                                .buttonPress('left')
+                                .keys('Shift')
+                                .moveTo(res.value[1].ELEMENT, 0, 0)
+                                .buttonPress('left');
+       
+                                   client.keys('Shift'); // release the Shift 
key
+                                   
+                                   // On Mac the ctrl key opens the context 
menu in the browser
+                                   // this is why the Cmd key should be used 
in this case.
+                                   if ('darwin' === process.platform){
+                                       client.keys('Command');
+                                   } else {
+                                       client.keys('Control');
+                                   }
+                               
+                                   client.moveTo(res.value[3].ELEMENT, 0, 0)
+                               .buttonPress('left');
+                                   client.keys('NULL'); // release all keys
+                         });
+                         var confirmationOkBtn = 'div.bootbox-confirm 
div.modal-footer button[data-bb-handler="confirm"]';
+                         var openTestNodeIcon = '#root 
li[nodename=\"aTestNode\"] i.open-icon';
+                         client.keys('Delete')
+                         .waitForVisible(confirmationOkBtn)
+                         .click(confirmationOkBtn)
+                         .waitForVisible(openTestNodeIcon)
+                         .click(openTestNodeIcon)
+                         .waitForExist('#last-element').elements('#root 
li[nodename="aTestNode"] li a .jstree-themeicon', function(err, res) {
+                         assert(typeof err === "undefined" || err === null);
+                                 assert(1 === res.value.length);
+                         });
+                     client.call(done);
+                         
+                 });
+         });
+
+         describe('can add a', function(done){
+                 it('String property', function(done) {
+                         addProperty("String", "textarea");
+                         client.call(done);
+                 });
+
+                 it('Path property', function(done) {
+                         addProperty("Path", "input");
+                         client.call(done);
+                 });
+                 
+                 function addProperty(type, editorTagName){
+                         var encodedNodeNameSelector = '#root 
li[nodename="aTestNode"].opened li[nodename="a node with a resource type"]';
+                         var encodedNodeNameOpenSelector = 
encodedNodeNameSelector +' i.open-icon';
+                         var addPropertyMenuItemSelector = "#properties 
.add-property-menu [data-property-type='"+type+"']";
+                         var key="a"+type+"Key";
+                         var value="a "+type+" value";
+                         var propValueEditorSelector = "#addPropertyDialog 
div[data-property-type='"+type+"'] "+editorTagName;
+                         client.url(homeURL).waitForExist('#last-element')
+                         .click("#root li[nodename=\"aTestNode\"] 
i.open-icon").waitForExist("#properties .add-property-menu-item", 1000)
+                         .click("#properties 
.add-property-menu-item").waitForExist(addPropertyMenuItemSelector, 1000)
+                         
.click(addPropertyMenuItemSelector).waitForVisible('#new-property-key', 1000)
+                         /* 
+                          * The value is not always set completely the first 
time for some strange reason so I set it twice.
+                          * ToDo: Find a way to reproduce that and file a bug 
report. 
+                          * A simple test that fills some input fields on the 
facebook registration page did not show the problem.
+                          * See: 
https://groups.google.com/forum/#!topic/webdriverio/b7ohm7tkG7Q
+                          */
+                         .setValue('#new-property-key ', key)
+                         .setValue('#new-property-key ', key)
+                         .setValue(propValueEditorSelector, value)
+                         .click("#addPropertyDialog 
.btn-primary.submit").waitForExist("label.proplabel[for='"+key+"']", 1000, 
function(err, existed) {
+                                 assert(typeof err === "undefined" || err === 
null);
+                                 assert(existed === true);
+                                 client.getValue("#properties 
div[data-property-name='"+key+"'].row .propinput.property-value", function(err, 
resultingValue) {
+                                         assert(typeof err === "undefined" || 
err === null);
+                                         assert(value === resultingValue);
+                                 });
+                                 
+                     });
+                 }
          });
-         it('can delete nodes via multi selection and shortcut', 
function(done) {
-                 client = client.url(homeURL);
-                 client
-                 .waitForExist('#last-element').click("#root 
li[nodename=\"aTestNode\"] i.add-icon")
-                       .waitForVisible('#addNodeDialog.add-node-finished', 
1000).click('#addNodeDialog .btn.btn-primary.submit')
-                       // The open node animation will take longer than 500ms 
thus setting 2000ms as max.
-                       .waitForExist('#root li[nodename="aTestNode"].opened', 
2000).elements('#root li[nodename="aTestNode"].opened li a .jstree-themeicon', 
function(err, res) {
-                           client
-                        .moveTo(res.value[0].ELEMENT, 0, 0)
-                        .buttonPress('left')
-                        .keys('Shift')
-                        .moveTo(res.value[1].ELEMENT, 0, 0)
-                        .buttonPress('left');
 
-                           client.keys('Shift'); // release the Shift key
-                           
-                           // On Mac the ctrl key opens the context menu in 
the browser
-                           // this is why the Cmd key should be used in this 
case.
-                           if ('darwin' === process.platform){
-                               client.keys('Command');
-                           } else {
-                               client.keys('Control');
-                           }
-                       
-                           client.moveTo(res.value[3].ELEMENT, 0, 0)
-                       .buttonPress('left');
-                           client.keys('NULL'); // release all keys
+         describe('can save a String property', function(){
+                 var inputElementSelector = "#properties 
div[data-property-name='aStringKey'].row .propinput.property-value";
+                 
+                 it('with the icon', function(done) {
+                         var stringValue = "new String value";
+                         setStringFieldValue(client, stringValue);
+                         client.click("#properties 
div[data-property-name='aStringKey'].row 
.property-icon.glyphicon-save").waitForExist("div.alert-success.growl-notify", 
1000).refresh();
+                         testStringFieldValue(client, stringValue);
+                         client.call(done);
                  });
-                 var confirmationOkBtn = 'div.bootbox-confirm div.modal-footer 
button[data-bb-handler="confirm"]';
-                 var openTestNodeIcon = '#root li[nodename=\"aTestNode\"] 
i.open-icon';
-                 client.keys('Delete')
-                 .waitForVisible(confirmationOkBtn)
-                 .click(confirmationOkBtn)
-                 .waitForVisible(openTestNodeIcon)
-                 .click(openTestNodeIcon)
-                 .waitForExist('#last-element').elements('#root 
li[nodename="aTestNode"] li a .jstree-themeicon', function(err, res) {
-                 assert(typeof err === "undefined" || err === null);
-                         assert(1 === res.value.length);
+                 
+                 it('with the shortcut', function(done) {
+                         var stringValue = "3rd String value";
+                         setStringFieldValue(client, stringValue);
+                         // On Mac the ctrl key opens the context menu in the 
browser
+                         // this is why the Cmd key should be used in this 
case.
+                         if ('darwin' === process.platform){
+                               client.keys('Command');
+                               client.keys("s")
+                               client.keys('Command'); // releases the key
+                         } else {
+                               client.keys('Control');
+                               client.keys("s")
+                               client.keys('Control'); // releases the key
+                         };
+                         testStringFieldValue(client, stringValue);
+                         client.call(done);
                  });
-             client.call(done);
                  
+                 function setStringFieldValue(client, value){
+                         client.url(homeURL).waitForExist('#last-element')
+                         .click("#root li[nodename=\"aTestNode\"] 
i.open-icon").waitForExist("#properties label.proplabel[for='aStringKey']", 
1000)
+                         .setValue("#properties 
div[data-property-name='aStringKey'].row .propinput.property-value", value);
+                 }
+                 
+                 function testStringFieldValue(client, value){
+                         client
+                         .waitForExist("div.alert-success.growl-notify", 
1000).refresh()
+                         .waitForExist(inputElementSelector, 
1000).getValue(inputElementSelector, function(err, resultingValue){
+                                 assert(typeof err === "undefined" || err === 
null);
+                                 assert(value === resultingValue);
+                         })
+                 }
          });
+         
+         describe('can delete a property', function(){
+                 it('with the icon', function(done) {
+                         var value= "aStringKey";
+                         focusInputField(client, value);
+                         client
+                         .click("#properties 
div[data-property-name='"+value+"'].row .property-icon.glyphicon-remove");
+                         testRemoval(client, value);
+                         client.call(done);
+                 });
+
+                 it('with the shortcut', function(done) {
+                         var value= "aPathKey";
+                         focusInputField(client, value);
 
-         it('can delete a node with the icon', function(done) {
-                 client = client.url(homeURL);
-                 client.waitForExist('#last-element', function(err) {
-                         client.click('li[nodetype="rep:root"] 
li[nodename="aTestNode"] a i.remove-icon', function(err, res) {
-                                 client.waitForText('div.bootbox-confirm 
div.bootbox-body', function(err, result, third, fourth){
-                                         client.click('div.bootbox-confirm 
div.modal-footer button[data-bb-handler="confirm"]', function(err, res) {
-                                                 
client.waitForExist('li[nodetype="rep:root"] li[nodename="aTestNode"]', 
true/*reverse*/, function(err, existed) {
-                                                         assert(typeof err === 
"undefined" || err === null);
-                                                         assert(existed === 
false);
+                         // On Mac the ctrl key opens the context menu in the 
browser
+                         // this is why the Cmd key should be used in this 
case.
+                         if ('darwin' === process.platform){
+                               client.keys('Command');
+                               client.keys("Delete")
+                               client.keys('Command'); // releases the key
+                         } else {
+                               client.keys('Control');
+                               client.keys("Delete")
+                               client.keys('Control'); // releases the key
+                         };
+                         testRemoval(client, value);
+                         client.call(done);
+                 });
+                 
+                 function focusInputField(client, value){
+                         var stringPropertyInputFieldSelector = "#properties 
div[data-property-name='"+value+"'].row .propinput.property-value";
+                         client.url(homeURL).waitForExist('#last-element')
+                         .click("#root li[nodename=\"aTestNode\"] 
i.open-icon").waitForExist(stringPropertyInputFieldSelector, 1000)
+                         .click(stringPropertyInputFieldSelector);
+                 }
+                 
+                 function testRemoval(client, value){
+                         client
+                         .waitForVisible("div.bootbox-confirm .btn-primary", 
1000)
+                         .click("div.bootbox-confirm 
.btn-primary").waitForExist("div.alert-success.growl-notify", 1000).refresh()
+                         .waitForExist("#properties 
div[data-property-name='"+value+"'].row", true/*reverse*/, function(err, 
existed) {
+                                 assert(typeof err === "undefined" || err === 
null);
+                                 assert(existed === false);
+                         })
+                 }
+         });
+
+         // specs ("it" functions) are always executed before describe blocks
+         // that's why this spec is wrapped within a describe block as
+         // it has to be executed last
+         describe('can delete the (test) node', function(done){
+                 it('with the icon', function(done) {
+                         client = client.url(homeURL);
+                         client.waitForExist('#last-element', function(err) {
+                                 client.click('li[nodetype="rep:root"] 
li[nodename="aTestNode"] a i.remove-icon', function(err, res) {
+                                         
client.waitForText('div.bootbox-confirm div.bootbox-body', function(err, 
result, third, fourth){
+                                                 
client.click('div.bootbox-confirm div.modal-footer 
button[data-bb-handler="confirm"]', function(err, res) {
+                                                         
client.waitForExist('li[nodetype="rep:root"] li[nodename="aTestNode"]', 
true/*reverse*/, function(err, existed) {
+                                                                 assert(typeof 
err === "undefined" || err === null);
+                                                                 
assert(existed === false);
+                                                         });
                                                  });
                                          });
-                                 });
-                     })  
-             })
-             .call(done);
+                             })  
+                     })
+                     .call(done);
+                 });
          });
-       
 });
\ No newline at end of file

-- 
To stop receiving notification emails like this one, please contact
"[email protected]" <[email protected]>.

Reply via email to