You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@sling.apache.org by ro...@apache.org on 2017/10/18 23:23:54 UTC
[sling-org-apache-sling-resource-editor] 38/50: 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 [...]
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 <sb...@apache.org>
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> </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">×</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> </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">×</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 ?<>\"]", 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 ?<>"]';
- 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 ?<>"]';
- 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 ?<>"] input.jstree-rename-input').blur();
- $('#root li[nodename="aTestNode"] li[nodename="täßt ?<>"] input.jstree-rename-input').blur();
- });
- client.waitForExist('#root li[nodename="aTestNode"].opened li[nodename="täßt2& <>"]', 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 ?<>\"]", 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 ?<>"]';
+ 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 ?<>"]';
+ 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 ?<>"] input.jstree-rename-input').blur();
+ $('#root li[nodename="aTestNode"] li[nodename="täßt ?<>"] input.jstree-rename-input').blur();
+ });
+ client.waitForExist('#root li[nodename="aTestNode"].opened li[nodename="täßt2& <>"]', 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
"commits@sling.apache.org" <co...@sling.apache.org>.