You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@sling.apache.org by bd...@apache.org on 2014/11/26 17:27:37 UTC

svn commit: r1641848 [7/8] - in /sling/trunk/contrib/explorers/resourceeditor: ./ src/main/resources/SLING-INF/libs/sling/ src/main/resources/SLING-INF/libs/sling/resource-editor-static-content/ src/main/resources/SLING-INF/libs/sling/resource-editor-s...

Added: sling/trunk/contrib/explorers/resourceeditor/src/main/resources/SLING-INF/libs/sling/resource-editor-static-content/js/reseditor/LoginController.js
URL: http://svn.apache.org/viewvc/sling/trunk/contrib/explorers/resourceeditor/src/main/resources/SLING-INF/libs/sling/resource-editor-static-content/js/reseditor/LoginController.js?rev=1641848&view=auto
==============================================================================
--- sling/trunk/contrib/explorers/resourceeditor/src/main/resources/SLING-INF/libs/sling/resource-editor-static-content/js/reseditor/LoginController.js (added)
+++ sling/trunk/contrib/explorers/resourceeditor/src/main/resources/SLING-INF/libs/sling/resource-editor-static-content/js/reseditor/LoginController.js Wed Nov 26 16:27:36 2014
@@ -0,0 +1,188 @@
+/*
+ * 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.
+ */
+
+/*
+ * As the name implies, the LoginController contains functionality for the user login.
+ */
+
+// creating the namespace
+var org = org || {};
+org.apache = org.apache || {};
+org.apache.sling = org.apache.sling || {};
+org.apache.sling.reseditor = org.apache.sling.reseditor || {};
+
+//defining the module
+org.apache.sling.reseditor.LoginController = (function() {
+
+	function LoginController(settings, mainController){
+		var authorized = settings.authorized;
+		$(document).ready(function() {
+			setLoginTabLabel(settings.authorizedUser);
+			
+			$('#login_tab').click(function(e) {	
+				if (authorized) {
+					//@TODO: Use real <a href="/system/sling/logout.html"... instead
+					//make sure the context path is used
+					//check if there is a settings.requestURI, if not redirect to "/"
+		        	location.href='/system/sling/logout.html?resource='+settings.requestURI;
+				} else {
+					$('#login_tab_content').slideToggle(function() {mainController.adjust_height();});
+					$("#login_form input[name='j_username']").focus();
+				}
+			});
+
+			$('#login_form input').keydown(function(event) {
+		        if (event.keyCode == 13/*Return key*/) {	
+		    		submitForm();
+		            return false;
+		         }
+		    });
+			
+			$('#login_submit').click(function(e) {	
+				submitForm();
+			});
+		});
+		
+
+		function setLoginTabLabel(authorizedUser){
+			$('#login_tab').text(authorized ? 'Logout '+authorizedUser : authorizedUser);
+			if (authorized) {
+				$('#login .nav-tabs').removeClass('nav-tabs').addClass('logout');
+			}
+		}
+
+		function submitForm(){
+			$('#login').removeClass('animated shake');
+			$('#login .form-group.error').hide();
+			
+			$.ajax({
+		  	  type: 'POST',
+				  url: settings.contextPath + $('#login_form').attr('action') + '?' + $('#login_form').serialize(),
+		  	  success: function(data, textStatus, jqXHR) {
+		  		authorized=true;
+		  		$('#login_tab_content').slideToggle(function() {
+		  			mainController.adjust_height();
+		  			setLoginTabLabel($('#login_form input[name="j_username"]').val());
+		  		});
+			  },
+		  	  error: function(data) {
+		  			$('#login_error').text(data.responseText);
+		  			$('#login .form-group.error').slideToggle();
+		  			$('#login').addClass('animated shake');
+			  }
+		  	});
+		}
+	};
+
+	return LoginController;
+}());
+/*
+ * 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.
+ */
+
+/*
+ * As the name implies, the LoginController contains functionality for the user login.
+ */
+
+// creating the namespace
+var org = org || {};
+org.apache = org.apache || {};
+org.apache.sling = org.apache.sling || {};
+org.apache.sling.reseditor = org.apache.sling.reseditor || {};
+
+//defining the module
+org.apache.sling.reseditor.LoginController = (function() {
+
+	function LoginController(settings, mainController){
+		var authorized = settings.authorized;
+		$(document).ready(function() {
+			setLoginTabLabel(settings.authorizedUser);
+			
+			$('#login_tab').click(function(e) {	
+				if (authorized) {
+					//@TODO: Use real <a href="/system/sling/logout.html"... instead
+					//make sure the context path is used
+					//check if there is a settings.requestURI, if not redirect to "/"
+		        	location.href='/system/sling/logout.html?resource='+settings.requestURI;
+				} else {
+					$('#login_tab_content').slideToggle(function() {mainController.adjust_height();});
+					$("#login_form input[name='j_username']").focus();
+				}
+			});
+
+			$('#login_form input').keydown(function(event) {
+		        if (event.keyCode == 13/*Return key*/) {	
+		    		submitForm();
+		            return false;
+		         }
+		    });
+			
+			$('#login_submit').click(function(e) {	
+				submitForm();
+			});
+		});
+		
+
+		function setLoginTabLabel(authorizedUser){
+			$('#login_tab').text(authorized ? 'Logout '+authorizedUser : authorizedUser);
+			if (authorized) {
+				$('#login .nav-tabs').removeClass('nav-tabs').addClass('logout');
+			}
+		}
+
+		function submitForm(){
+			$('#login').removeClass('animated shake');
+			$('#login .form-group.error').hide();
+			
+			$.ajax({
+		  	  type: 'POST',
+				  url: settings.contextPath + $('#login_form').attr('action') + '?' + $('#login_form').serialize(),
+		  	  success: function(data, textStatus, jqXHR) {
+		  		authorized=true;
+		  		$('#login_tab_content').slideToggle(function() {
+		  			mainController.adjust_height();
+		  			setLoginTabLabel($('#login_form input[name="j_username"]').val());
+		  		});
+			  },
+		  	  error: function(data) {
+		  			$('#login_error').text(data.responseText);
+		  			$('#login .form-group.error').slideToggle();
+		  			$('#login').addClass('animated shake');
+			  }
+		  	});
+		}
+	};
+
+	return LoginController;
+}());

Added: sling/trunk/contrib/explorers/resourceeditor/src/main/resources/SLING-INF/libs/sling/resource-editor-static-content/js/reseditor/MainController.js
URL: http://svn.apache.org/viewvc/sling/trunk/contrib/explorers/resourceeditor/src/main/resources/SLING-INF/libs/sling/resource-editor-static-content/js/reseditor/MainController.js?rev=1641848&view=auto
==============================================================================
--- sling/trunk/contrib/explorers/resourceeditor/src/main/resources/SLING-INF/libs/sling/resource-editor-static-content/js/reseditor/MainController.js (added)
+++ sling/trunk/contrib/explorers/resourceeditor/src/main/resources/SLING-INF/libs/sling/resource-editor-static-content/js/reseditor/MainController.js Wed Nov 26 16:27:36 2014
@@ -0,0 +1,226 @@
+/*
+ * 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 MainController is responsible for every functionality 
+ * that is not handled by other, more specific controllers.
+ */
+
+//defining the module
+org.apache.sling.reseditor.MainController = (function() {
+
+	function MainController(settings, ntManager){
+		this.ntManager = ntManager;
+		this.settings = settings;
+		
+		var thisMainController = this;
+		
+		$(document).ready(function() {
+			$('#alertClose').click(function () {
+				$("#alert").slideUp(function() {
+					thisMainController.adjust_height();
+					$('#alertMsg #Message').remove();
+				});
+			})
+		});
+	};
+
+	MainController.prototype.getNodeTypes = function(){
+		return this.settings.nodeTypes;
+	}
+
+	MainController.prototype.getContextPath = function(){
+		return this.settings.contextPath;
+	}
+
+	MainController.prototype.encodeURL = function(unencodedURL){
+		url = encodeURIComponent(unencodedURL);
+		return url.replace(/%2F/g, "/");
+	}
+
+	MainController.prototype.encodeToHTML = function(unencodedHTML){
+		//create a in-memory div, set it's inner text(which jQuery automatically encodes)
+		//then grab the encoded contents back out.The div never exists on the page.
+		return $('<div/>').text(unencodedHTML).html();
+	}
+
+	MainController.prototype.decodeFromHTML = function(encodedHTML){
+		return $("<div/>").html(encodedHTML).text();
+	}
+	
+	
+	MainController.prototype.adjust_height = function(objectId){
+		var login_height = $("#login").outerHeight(true);
+		var header_height = $("#header").outerHeight(true);
+		var alert_height = $("#alerts").outerHeight(true);
+		var footer_height = $("#footer").outerHeight(true);
+		var sidebar_margin = $("#sidebar").outerHeight(true)-$("#sidebar").outerHeight(false);
+		var usable_height = $(window).height() - login_height - header_height - alert_height - sidebar_margin - 1;
+		
+	// activate again if the footer is needed	
+//	 	var usable_height = $(window).height() - header_height - footer_height - sidebar_margin - 1;
+		$("#sidebar").height( usable_height );
+		$("#outer_content").height( usable_height );
+	}
+
+	MainController.prototype.displayAlert = function(error, resourcePath){
+		var thisMainController = this;
+		var errorJson = error.responseJSON;
+		var encodedTitle = this.encodeToHTML(errorJson.title);
+		var encodedMsg = this.encodeToHTML(errorJson["status.message"]);
+		var errorMsg = encodedTitle+" ("+"Status "+errorJson["status.code"]+") "+encodedMsg;
+		$('#alertMsg').append($("<div id='Message'>").append((resourcePath) ? "'"+resourcePath+"': "+errorMsg : errorMsg));
+		$("#alert").slideDown(function() {
+			thisMainController.adjust_height();
+		});
+	}
+
+
+	MainController.prototype.getNTFromLi = function(li){
+		var nt_name = $(li).children("a").find("span span.node-type").text();
+	    return this.ntManager.getNodeType(nt_name);	
+	}
+	
+	MainController.prototype.redirectTo = function(unencodedTargetPath){
+		var newURIencoded = this.encodeURL(unencodedTargetPath);
+  	  	var target = this.settings.contextPath+"/reseditor"+newURIencoded;
+  	  	location.href=target+".html";
+	}
+	
+	return MainController;
+}());
+/*
+ * 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 MainController is responsible for every functionality 
+ * that is not handled by other, more specific controllers.
+ */
+
+//defining the module
+org.apache.sling.reseditor.MainController = (function() {
+
+	function MainController(settings, ntManager){
+		this.ntManager = ntManager;
+		this.settings = settings;
+		
+		var thisMainController = this;
+		
+		$(document).ready(function() {
+			$('#alertClose').click(function () {
+				$("#alert").slideUp(function() {
+					thisMainController.adjust_height();
+					$('#alertMsg #Message').remove();
+				});
+			})
+		});
+	};
+
+	MainController.prototype.getNodeTypes = function(){
+		return this.settings.nodeTypes;
+	}
+
+	MainController.prototype.getContextPath = function(){
+		return this.settings.contextPath;
+	}
+
+	MainController.prototype.encodeURL = function(unencodedURL){
+		url = encodeURIComponent(unencodedURL);
+		return url.replace(/%2F/g, "/");
+	}
+
+	MainController.prototype.encodeToHTML = function(unencodedHTML){
+		//create a in-memory div, set it's inner text(which jQuery automatically encodes)
+		//then grab the encoded contents back out.The div never exists on the page.
+		return $('<div/>').text(unencodedHTML).html();
+	}
+
+	MainController.prototype.decodeFromHTML = function(encodedHTML){
+		return $("<div/>").html(encodedHTML).text();
+	}
+	
+	
+	MainController.prototype.adjust_height = function(objectId){
+		var login_height = $("#login").outerHeight(true);
+		var header_height = $("#header").outerHeight(true);
+		var alert_height = $("#alerts").outerHeight(true);
+		var footer_height = $("#footer").outerHeight(true);
+		var sidebar_margin = $("#sidebar").outerHeight(true)-$("#sidebar").outerHeight(false);
+		var usable_height = $(window).height() - login_height - header_height - alert_height - sidebar_margin - 1;
+		
+	// activate again if the footer is needed	
+//	 	var usable_height = $(window).height() - header_height - footer_height - sidebar_margin - 1;
+		$("#sidebar").height( usable_height );
+		$("#outer_content").height( usable_height );
+	}
+
+	MainController.prototype.displayAlert = function(error, resourcePath){
+		var thisMainController = this;
+		var errorJson = error.responseJSON;
+		var encodedTitle = this.encodeToHTML(errorJson.title);
+		var encodedMsg = this.encodeToHTML(errorJson["status.message"]);
+		var errorMsg = encodedTitle+" ("+"Status "+errorJson["status.code"]+") "+encodedMsg;
+		$('#alertMsg').append($("<div id='Message'>").append((resourcePath) ? "'"+resourcePath+"': "+errorMsg : errorMsg));
+		$("#alert").slideDown(function() {
+			thisMainController.adjust_height();
+		});
+	}
+
+
+	MainController.prototype.getNTFromLi = function(li){
+		var nt_name = $(li).children("a").find("span span.node-type").text();
+	    return this.ntManager.getNodeType(nt_name);	
+	}
+	
+	MainController.prototype.redirectTo = function(unencodedTargetPath){
+		var newURIencoded = this.encodeURL(unencodedTargetPath);
+  	  	var target = this.settings.contextPath+"/reseditor"+newURIencoded;
+  	  	location.href=target+".html";
+	}
+	
+	return MainController;
+}());

Added: sling/trunk/contrib/explorers/resourceeditor/src/main/resources/SLING-INF/libs/sling/resource-editor-static-content/js/reseditor/tree/AddNodeController.js
URL: http://svn.apache.org/viewvc/sling/trunk/contrib/explorers/resourceeditor/src/main/resources/SLING-INF/libs/sling/resource-editor-static-content/js/reseditor/tree/AddNodeController.js?rev=1641848&view=auto
==============================================================================
--- sling/trunk/contrib/explorers/resourceeditor/src/main/resources/SLING-INF/libs/sling/resource-editor-static-content/js/reseditor/tree/AddNodeController.js (added)
+++ sling/trunk/contrib/explorers/resourceeditor/src/main/resources/SLING-INF/libs/sling/resource-editor-static-content/js/reseditor/tree/AddNodeController.js Wed Nov 26 16:27:36 2014
@@ -0,0 +1,278 @@
+/*
+ * 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 || {};
+
+/*
+ * Handles the Add Node dialog functionality
+ */
+
+//defining the module
+org.apache.sling.reseditor.AddNodeController = (function() {
+
+	function AddNodeController(settings, mainController){
+		var thatAddNodeController = this;
+		this.settings = settings;
+		this.mainController = mainController;
+		this.lastAddNodeURL = "";
+		
+		$(document).ready(function() {
+			$('#addNodeDialog .submit').click(function(){
+				thatAddNodeController.addNode();
+			});
+			
+			var nodeTypeObjects = jQuery.map( mainController.getNodeTypes(), function( nt, i ) {
+				return {id: nt, text: nt};
+			});
+
+			$("#nodeType").select2({
+				placeholder: "Node Type",
+				allowClear: true, 
+				data: nodeTypeObjects
+			})
+
+			function format(element) {
+				return "<span><span class=\"search-choice-close\"></span>"+element.text+"</span>";
+			}
+
+			var data=[];
+
+			var select2 = $("#resourceType").select2({
+				placeholder: "Resource Type",
+				allowClear: true, 
+				formatResult: format,
+				data: data,
+				createSearchChoice: function(searchTerm){
+					return {id:searchTerm, text:searchTerm};
+				}
+			}).data("select2");
+			
+			// To get called on a click in the result list:
+			// http://stackoverflow.com/a/15637696/1743551
+			select2.onSelect = (function(fn) {
+			    return function(data, options) {
+			        var target;
+			        
+			        if (options != null) {
+			            target = $(options.target);
+			        }
+			        
+			        if (target && target.hasClass('search-choice-close')) {
+			            alert('click!');
+			        } else {
+			            return fn.apply(this, arguments);
+			        }
+			    }
+			})(select2.onSelect);
+		});
+
+		AddNodeController.prototype.addNode = function() {
+			var thatAddNodeController = this;
+			var nodeName = $("#nodeName").val().trim();
+			var nodeType = $("#nodeType").val();
+			var resourceType = $("#resourceType").val().trim();
+			
+			var data = {"_charset_": "utf-8"};
+			if ("" != nodeType){
+				data["jcr:primaryType"] = nodeType;
+			}
+			if ("" != resourceType){
+				data["sling:resourceType"] = resourceType;
+			}
+			var targetURL = (this.lastAddNodeURL=="/") ? "/" : this.lastAddNodeURL+"/";
+			targetURL = this.mainController.decodeFromHTML(targetURL);
+			if ("" != nodeName) {
+				targetURL += nodeName;
+			}
+			if (targetURL=="/"){
+				//adding a node without a specified name to the root node 
+				targetURL = "/*";
+			}
+			var encodedTargetURL = this.mainController.encodeURL(targetURL);
+
+			$.ajax({
+		  	  type: 'POST',
+			  url: encodedTargetURL,
+			  dataType: "json",
+		  	  data: data
+		  	})
+			.done(function() {
+				$('#addNodeDialog').modal("hide");
+				var htmlDecodedLastAddNodeURL = thatAddNodeController.mainController.decodeFromHTML(thatAddNodeController.lastAddNodeURL);
+				thatAddNodeController.mainController.redirectTo(htmlDecodedLastAddNodeURL);
+			})
+			.fail(function(errorJson) {
+				$('#addNodeDialog').modal("hide");
+				thatAddNodeController.mainController.displayAlert(errorJson);
+			});
+			
+		}
+	};
+	
+	AddNodeController.prototype.openAddNodeDialog = function(resourcePath) {
+		$('#addNodeDialog').modal({});
+		var contextPath = this.mainController.getContextPath() == "/" && resourcePath=="/" ? "" : this.mainController.getContextPath(); 
+		this.lastAddNodeURL = contextPath+resourcePath;
+	}
+	
+	return AddNodeController;
+}());
+/*
+ * 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 || {};
+
+/*
+ * Handles the Add Node dialog functionality
+ */
+
+//defining the module
+org.apache.sling.reseditor.AddNodeController = (function() {
+
+	function AddNodeController(settings, mainController){
+		var thatAddNodeController = this;
+		this.settings = settings;
+		this.mainController = mainController;
+		this.lastAddNodeURL = "";
+		
+		$(document).ready(function() {
+			$('#addNodeDialog .submit').click(function(){
+				thatAddNodeController.addNode();
+			});
+			
+			var nodeTypeObjects = jQuery.map( mainController.getNodeTypes(), function( nt, i ) {
+				return {id: nt, text: nt};
+			});
+
+			$("#nodeType").select2({
+				placeholder: "Node Type",
+				allowClear: true, 
+				data: nodeTypeObjects
+			})
+
+			function format(element) {
+				return "<span><span class=\"search-choice-close\"></span>"+element.text+"</span>";
+			}
+
+			var data=[];
+
+			var select2 = $("#resourceType").select2({
+				placeholder: "Resource Type",
+				allowClear: true, 
+				formatResult: format,
+				data: data,
+				createSearchChoice: function(searchTerm){
+					return {id:searchTerm, text:searchTerm};
+				}
+			}).data("select2");
+			
+			// To get called on a click in the result list:
+			// http://stackoverflow.com/a/15637696/1743551
+			select2.onSelect = (function(fn) {
+			    return function(data, options) {
+			        var target;
+			        
+			        if (options != null) {
+			            target = $(options.target);
+			        }
+			        
+			        if (target && target.hasClass('search-choice-close')) {
+			            alert('click!');
+			        } else {
+			            return fn.apply(this, arguments);
+			        }
+			    }
+			})(select2.onSelect);
+		});
+
+		AddNodeController.prototype.addNode = function() {
+			var thatAddNodeController = this;
+			var nodeName = $("#nodeName").val().trim();
+			var nodeType = $("#nodeType").val();
+			var resourceType = $("#resourceType").val().trim();
+			
+			var data = {"_charset_": "utf-8"};
+			if ("" != nodeType){
+				data["jcr:primaryType"] = nodeType;
+			}
+			if ("" != resourceType){
+				data["sling:resourceType"] = resourceType;
+			}
+			var targetURL = (this.lastAddNodeURL=="/") ? "/" : this.lastAddNodeURL+"/";
+			targetURL = this.mainController.decodeFromHTML(targetURL);
+			if ("" != nodeName) {
+				targetURL += nodeName;
+			}
+			if (targetURL=="/"){
+				//adding a node without a specified name to the root node 
+				targetURL = "/*";
+			}
+			var encodedTargetURL = this.mainController.encodeURL(targetURL);
+
+			$.ajax({
+		  	  type: 'POST',
+			  url: encodedTargetURL,
+			  dataType: "json",
+		  	  data: data
+		  	})
+			.done(function() {
+				$('#addNodeDialog').modal("hide");
+				var htmlDecodedLastAddNodeURL = thatAddNodeController.mainController.decodeFromHTML(thatAddNodeController.lastAddNodeURL);
+				thatAddNodeController.mainController.redirectTo(htmlDecodedLastAddNodeURL);
+			})
+			.fail(function(errorJson) {
+				$('#addNodeDialog').modal("hide");
+				thatAddNodeController.mainController.displayAlert(errorJson);
+			});
+			
+		}
+	};
+	
+	AddNodeController.prototype.openAddNodeDialog = function(resourcePath) {
+		$('#addNodeDialog').modal({});
+		var contextPath = this.mainController.getContextPath() == "/" && resourcePath=="/" ? "" : this.mainController.getContextPath(); 
+		this.lastAddNodeURL = contextPath+resourcePath;
+	}
+	
+	return AddNodeController;
+}());

Added: sling/trunk/contrib/explorers/resourceeditor/src/main/resources/SLING-INF/libs/sling/resource-editor-static-content/js/reseditor/tree/JSTreeAdapter.js
URL: http://svn.apache.org/viewvc/sling/trunk/contrib/explorers/resourceeditor/src/main/resources/SLING-INF/libs/sling/resource-editor-static-content/js/reseditor/tree/JSTreeAdapter.js?rev=1641848&view=auto
==============================================================================
--- sling/trunk/contrib/explorers/resourceeditor/src/main/resources/SLING-INF/libs/sling/resource-editor-static-content/js/reseditor/tree/JSTreeAdapter.js (added)
+++ sling/trunk/contrib/explorers/resourceeditor/src/main/resources/SLING-INF/libs/sling/resource-editor-static-content/js/reseditor/tree/JSTreeAdapter.js Wed Nov 26 16:27:36 2014
@@ -0,0 +1,348 @@
+/*
+ * 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 || {};
+
+
+/*
+ JSTreeAdapter - It adapts the JSTree library for the use in the Sling Resource Editor.
+ This JSTreeAdapter contains as less logic as needed to configure the JSTree for the Sling Resource Editor. For 
+ everything that goes beyond that and contains more functionality, the other Sling Resource Editor controllers are called.
+*/
+
+//defining the module
+org.apache.sling.reseditor.JSTreeAdapter = (function() {
+
+	function JSTreeAdapter(settings, treeController, mainController){
+		this.settings = settings;
+		this.treeController = treeController;
+		this.mainController = mainController;
+var pathSuffix = ".html";
+var pathEndsWithPathSuffix = settings.resourcePath.substring(settings.resourcePath.length-pathSuffix.length) == pathSuffix;
+var resourcePath = (pathEndsWithPathSuffix) ? settings.resourcePath.substring(0,settings.resourcePath.length-pathSuffix.length) : settings.resourcePath; 
+var currentNodePath = this.mainController.encodeToHTML(resourcePath);
+var paths = currentNodePath.substring(1).split("/");
+var selectingNodeWhileOpeningTree=true;
+
+var thisJSTreeAdapter = this;
+
+$(document).ready(function() {
+	$(window).resize( function() {
+		thisJSTreeAdapter.mainController.adjust_height();
+	});
+	
+	var selectorFromCurrentPath = treeController.getSelectorFromPath(currentNodePath);
+	
+	var scrollToPathFinished=false;
+	
+	thisJSTreeAdapter.mainController.adjust_height();
+	
+	
+	// TO CREATE AN INSTANCE
+	// select the tree container using jQuery
+	$("#tree")
+	.bind("loaded.jstree", function (event, data) {
+		if (currentNodePath != "/") {
+			treeController.openElement($("#tree > ul > li[nodename=''] > ul"), paths);
+		}
+		selectingNodeWhileOpeningTree=false;
+	})
+	// call `.jstree` with the options object
+	.jstree({
+		"core"      : {
+		    "check_callback" : true,
+		    multiple: true,
+			animation: 600,
+			'data' : {
+				'url' : function (liJson) {
+					// initial call for the root element
+					if (liJson.id === '#'){
+						return settings.contextPath+"/reseditor/.rootnodes.json";
+					} else {
+						// the li the user clicked on.
+						var li = $('#'+liJson.id);
+						return treeController.get_uri_from_li(li,".nodes.json");
+					}
+				},
+			    'data' : function (node) {
+			        return { 'id' : node.id };
+			      }
+			}
+		},
+		"ui"      : {
+			"select_limit" : 2
+		},
+		"crrm"      : {
+			"move" : {
+				"always_copy" : false,
+		        "check_move"  : function (m) {
+			        // you find the member description here
+			        // http://www.jstree.com/documentation/core.html#_get_move
+			        var src_li = m.o;
+			        var src_nt = mainController.getNTFromLi(src_li);
+			        var src_nodename = src_li.attr("nodename");
+			        
+			        var new_parent_ul = m.np.children("ul");
+			        var calculated_position = m.cp;
+			        var liAlreadySelected = new_parent_ul.length==0 && m.np.prop("tagName").toUpperCase() == 'LI';
+			        var dest_li = liAlreadySelected ? m.np : new_parent_ul.children("li:eq("+(calculated_position-1)+")");
+			        var dest_nt = mainController.getNTFromLi(dest_li);
+					var result;
+					if (dest_nt != null){ 
+						result = dest_nt.canAddChildNode(src_nodename, src_nt);
+					}
+                    return result;
+                  }
+			}
+		},
+		"dnd" : {
+			"drop_finish" : function () {
+				console.log("drop");
+				alert("DROP"); 
+			},
+			"drag_finish" : function (data) {
+				console.log("drag");
+				alert("DRAG OK"); 
+			}
+		},
+		// the `plugins` array allows you to configure the active plugins on this instance
+		"plugins" : [ "themes", "ui", "core", "hotkeys", "crrm", "dnd"]
+    }).bind("rename_node.jstree", function (e, data) {
+    	treeController.renameNode(e, data);
+    }).bind("move_node.jstree", function (e, data) {
+    	// see http://www.jstree.com/documentation/core ._get_move()
+    	// refactor to the new jsTree version
+    	var src_li = data.rslt.o;
+    	var src_path = ""+settings.contextPath+src_li.children("a").attr("target");
+    	var dest_li = data.rslt.np; // new parent .cr - same as np, but if a root node is created this is -1
+    	var dest_li_path = dest_li.children("a").attr("target") == "/" ? "" : dest_li.children("a").attr("target");
+    	var dest_path = ""+settings.contextPath+dest_li_path+"/"+src_li.attr("nodename");
+    	var original_parent = data.rslt.op;
+    	var is_copy = data.rslt.cy;
+    	var position = data.rslt.cp;
+    	$.ajax({
+      	  type: 'POST',
+		  url: src_path,
+		  dataType: "json",
+      	  success: function(server_data) {
+        		var target = ""+settings.contextPath+dest_path;
+            	location.href=target+".reseditor.html";
+    		  },
+      	  error: function(errorJson) {
+      			displayAlert(errorJson);
+    		  },
+      	  data: { 
+       		":operation": "move",
+//          	":order": position,
+      		":dest": dest_path
+      		  }
+      	});
+    }).on('hover_node.jstree', function (event, nodeObj) {
+        $('#'+nodeObj.node.id+' a:first').focus();
+    }).on('keydown.jstree', '.jstree-anchor', function (e) {
+    	// see http://www.javascripter.net/faq/keycodes.htm
+    	if (46==e.which) {
+    		treeController.deleteNodes();
+    	}
+    }).on('select_node.jstree', function (e, data) {
+    	;
+    });
+});
+
+	};
+	return JSTreeAdapter;
+}());
+/*
+ * 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 || {};
+
+
+/*
+ JSTreeAdapter - It adapts the JSTree library for the use in the Sling Resource Editor.
+ This JSTreeAdapter contains as less logic as needed to configure the JSTree for the Sling Resource Editor. For 
+ everything that goes beyond that and contains more functionality, the other Sling Resource Editor controllers are called.
+*/
+
+//defining the module
+org.apache.sling.reseditor.JSTreeAdapter = (function() {
+
+	function JSTreeAdapter(settings, treeController, mainController){
+		this.settings = settings;
+		this.treeController = treeController;
+		this.mainController = mainController;
+var pathSuffix = ".html";
+var pathEndsWithPathSuffix = settings.resourcePath.substring(settings.resourcePath.length-pathSuffix.length) == pathSuffix;
+var resourcePath = (pathEndsWithPathSuffix) ? settings.resourcePath.substring(0,settings.resourcePath.length-pathSuffix.length) : settings.resourcePath; 
+var currentNodePath = this.mainController.encodeToHTML(resourcePath);
+var paths = currentNodePath.substring(1).split("/");
+var selectingNodeWhileOpeningTree=true;
+
+var thisJSTreeAdapter = this;
+
+$(document).ready(function() {
+	$(window).resize( function() {
+		thisJSTreeAdapter.mainController.adjust_height();
+	});
+	
+	var selectorFromCurrentPath = treeController.getSelectorFromPath(currentNodePath);
+	
+	var scrollToPathFinished=false;
+	
+	thisJSTreeAdapter.mainController.adjust_height();
+	
+	
+	// TO CREATE AN INSTANCE
+	// select the tree container using jQuery
+	$("#tree")
+	.bind("loaded.jstree", function (event, data) {
+		if (currentNodePath != "/") {
+			treeController.openElement($("#tree > ul > li[nodename=''] > ul"), paths);
+		}
+		selectingNodeWhileOpeningTree=false;
+	})
+	// call `.jstree` with the options object
+	.jstree({
+		"core"      : {
+		    "check_callback" : true,
+		    multiple: true,
+			animation: 600,
+			'data' : {
+				'url' : function (liJson) {
+					// initial call for the root element
+					if (liJson.id === '#'){
+						return settings.contextPath+"/reseditor/.rootnodes.json";
+					} else {
+						// the li the user clicked on.
+						var li = $('#'+liJson.id);
+						return treeController.get_uri_from_li(li,".nodes.json");
+					}
+				},
+			    'data' : function (node) {
+			        return { 'id' : node.id };
+			      }
+			}
+		},
+		"ui"      : {
+			"select_limit" : 2
+		},
+		"crrm"      : {
+			"move" : {
+				"always_copy" : false,
+		        "check_move"  : function (m) {
+			        // you find the member description here
+			        // http://www.jstree.com/documentation/core.html#_get_move
+			        var src_li = m.o;
+			        var src_nt = mainController.getNTFromLi(src_li);
+			        var src_nodename = src_li.attr("nodename");
+			        
+			        var new_parent_ul = m.np.children("ul");
+			        var calculated_position = m.cp;
+			        var liAlreadySelected = new_parent_ul.length==0 && m.np.prop("tagName").toUpperCase() == 'LI';
+			        var dest_li = liAlreadySelected ? m.np : new_parent_ul.children("li:eq("+(calculated_position-1)+")");
+			        var dest_nt = mainController.getNTFromLi(dest_li);
+					var result;
+					if (dest_nt != null){ 
+						result = dest_nt.canAddChildNode(src_nodename, src_nt);
+					}
+                    return result;
+                  }
+			}
+		},
+		"dnd" : {
+			"drop_finish" : function () {
+				console.log("drop");
+				alert("DROP"); 
+			},
+			"drag_finish" : function (data) {
+				console.log("drag");
+				alert("DRAG OK"); 
+			}
+		},
+		// the `plugins` array allows you to configure the active plugins on this instance
+		"plugins" : [ "themes", "ui", "core", "hotkeys", "crrm", "dnd"]
+    }).bind("rename_node.jstree", function (e, data) {
+    	treeController.renameNode(e, data);
+    }).bind("move_node.jstree", function (e, data) {
+    	// see http://www.jstree.com/documentation/core ._get_move()
+    	// refactor to the new jsTree version
+    	var src_li = data.rslt.o;
+    	var src_path = ""+settings.contextPath+src_li.children("a").attr("target");
+    	var dest_li = data.rslt.np; // new parent .cr - same as np, but if a root node is created this is -1
+    	var dest_li_path = dest_li.children("a").attr("target") == "/" ? "" : dest_li.children("a").attr("target");
+    	var dest_path = ""+settings.contextPath+dest_li_path+"/"+src_li.attr("nodename");
+    	var original_parent = data.rslt.op;
+    	var is_copy = data.rslt.cy;
+    	var position = data.rslt.cp;
+    	$.ajax({
+      	  type: 'POST',
+		  url: src_path,
+		  dataType: "json",
+      	  success: function(server_data) {
+        		var target = ""+settings.contextPath+dest_path;
+            	location.href=target+".reseditor.html";
+    		  },
+      	  error: function(errorJson) {
+      			displayAlert(errorJson);
+    		  },
+      	  data: { 
+       		":operation": "move",
+//          	":order": position,
+      		":dest": dest_path
+      		  }
+      	});
+    }).on('hover_node.jstree', function (event, nodeObj) {
+        $('#'+nodeObj.node.id+' a:first').focus();
+    }).on('keydown.jstree', '.jstree-anchor', function (e) {
+    	// see http://www.javascripter.net/faq/keycodes.htm
+    	if (46==e.which) {
+    		treeController.deleteNodes();
+    	}
+    }).on('select_node.jstree', function (e, data) {
+    	;
+    });
+});
+
+	};
+	return JSTreeAdapter;
+}());

Added: sling/trunk/contrib/explorers/resourceeditor/src/main/resources/SLING-INF/libs/sling/resource-editor-static-content/js/reseditor/tree/TreeController.js
URL: http://svn.apache.org/viewvc/sling/trunk/contrib/explorers/resourceeditor/src/main/resources/SLING-INF/libs/sling/resource-editor-static-content/js/reseditor/tree/TreeController.js?rev=1641848&view=auto
==============================================================================
--- sling/trunk/contrib/explorers/resourceeditor/src/main/resources/SLING-INF/libs/sling/resource-editor-static-content/js/reseditor/tree/TreeController.js (added)
+++ sling/trunk/contrib/explorers/resourceeditor/src/main/resources/SLING-INF/libs/sling/resource-editor-static-content/js/reseditor/tree/TreeController.js Wed Nov 26 16:27:36 2014
@@ -0,0 +1,486 @@
+/*
+ * 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 TreeController is responsible for the node tree functionality of the Sling Resource Editor
+ * that is not specific for a 3rd party library.
+ * JSTree-specific functionality is implemented in the JSTreeAdapter instead.
+ */
+
+//defining the module
+org.apache.sling.reseditor.TreeController = (function() {
+
+	function TreeController(settings, mainController){
+		var thatTreeController = this;
+		this.settings = settings;
+		this.mainController = mainController;
+
+		var addNodeControllerSettings = {};
+		this.addNodeController = new org.apache.sling.reseditor.AddNodeController(addNodeControllerSettings, mainController);
+		
+		$(document).ready(function() {
+			$("#tree").on("click", "li.jstree-node>a.jstree-anchor>i.open-icon",function(e, data) {
+				thatTreeController.openNodeTarget(e);
+			});
+			$("#tree").on("click", "li.jstree-node>a.jstree-anchor>i.add-icon",function(e, data) {
+				thatTreeController.openAddNodeDialog($(e.target).parents("li"));
+			});
+			$("#tree").on("click", "li.jstree-node>a.jstree-anchor>i.remove-icon",function(e, data) {
+				thatTreeController.deleteSingleNode($(e.target).parents("li"));
+			});
+	
+			$("#tree").on("dblclick", "li.jstree-node>a.jstree-anchor",function(e, data) {
+				var id = $(e.target).parents("li:first").attr("id");
+				thatTreeController.openRenameNodeDialog(id);
+			});
+		});
+	};
+
+	TreeController.prototype.openNodeTarget = function(e) {
+		var url = $(e.target).parent().attr("href");
+		url = this.mainController.decodeFromHTML(url);
+		url = this.mainController.encodeURL(url);
+		location.href=url;
+	}
+
+	TreeController.prototype.openRenameNodeDialog = function(id) {
+		var liElement = $('#'+id);
+		$("#tree").jstree("edit", $('#'+id), this.mainController.decodeFromHTML(liElement.attr("nodename")));
+	}
+	
+	TreeController.prototype.renameNode = function(e, data) {
+		var thatTreeController = this;
+		var newName = this.mainController.decodeFromHTML(data.text);
+		var oldName = data.old;
+		if (oldName!==newName){
+			var currentURL = this.getPathFromLi($('#'+data.node.id));
+			var unencodedURI = currentURL;
+			var decodedCurrentURI = this.mainController.decodeFromHTML(unencodedURI);
+			var newURI = decodedCurrentURI.replace(oldName, newName);
+			currentURL = this.mainController.encodeURL(decodedCurrentURI);
+			$.ajax({
+		  	  type: 'POST',
+			  url: currentURL,
+		  	  success: function(server_data) {
+		  		  thatTreeController.mainController.redirectTo(newURI);
+			  },
+		  	  error: function(errorJson) {
+		  		  thatTreeController.mainController.displayAlert(errorJson);
+			  },
+			  dataType: "json",
+			  contentType : 'application/x-www-form-urlencoded; charset=UTF-8',
+		  	  data: { 
+		  		":operation": "move",
+		  		"_charset_": "utf-8",
+		  		":dest": newURI
+		  		  }
+		  	});
+		}
+	}
+	
+	TreeController.prototype.getSelectorFromPath = function(path){
+		var paths = path.substring(1).split("/");
+		return "#tree > ul [nodename='"+paths.join("'] > ul > [nodename='")+"']";
+	}
+
+	TreeController.prototype.getPathFromLi = function(li){
+		var path = $(li).parentsUntil(".root").andSelf().map(
+				function() {
+					return this.tagName == "LI"
+							? $(this).attr("nodename") 
+							: null;
+				}
+			).get().join("/");
+		return "" == path ? "/" : path;
+	};
+
+	TreeController.prototype.getURLEncodedPathFromLi = function(li){
+		var htmlEncodedPath = this.getPathFromLi(li);
+		var htmlDecodedPath = this.mainController.decodeFromHTML(htmlEncodedPath);
+		return this.mainController.encodeURL(htmlDecodedPath);
+	};
+
+	TreeController.prototype.openElement = function(root, paths) {
+		var thisTreeController = this;
+		var pathElementName = paths.shift();
+		var pathElementLi = root.children("[nodename='"+pathElementName+"']");
+		if (pathElementLi.length === 0){
+			alert("Couldn't find "+pathElementName+" under the path "+this.getPathFromLi(root.parent()));
+		} else {
+			$('#tree').jstree('open_node', pathElementLi,
+					function(){
+						if (paths.length>0){
+							thisTreeController.openElement($("#"+pathElementLi.attr('id')).children("ul"), paths);
+						} else  {
+							selectingNodeWhileOpeningTree=true;
+							$('#tree').jstree('select_node', pathElementLi.attr('id'), 'true'/*doesn't seem to work*/);
+							selectingNodeWhileOpeningTree=false;
+					        var target = $('#'+pathElementLi.attr('id')+' a:first');
+					        target.focus();
+						}
+					}
+				);
+		}
+	}
+
+	TreeController.prototype.get_uri_from_li = function(li, extension){
+		var path = this.getPathFromLi(li);
+		path = this.mainController.decodeFromHTML(path);
+		path = this.mainController.encodeURL(path);
+		return this.settings.contextPath+"/reseditor"+path+extension;
+	}
+
+	TreeController.prototype.deleteNodes = function() {
+		var thatTreeController = this;
+		var lastDeletedLI;
+		var selectedIds = $("#tree").jstree('get_selected');
+		var firstId = selectedIds[0];
+		var parentLi = $('#'+firstId).parents('li');
+		var parentPath = this.getURLEncodedPathFromLi(parentLi);
+		var otherPathsToDelete = [];
+		var otherPathsToDeleteDecoded = [];
+		for (var i=0; i<selectedIds.length; i++){
+			var id = selectedIds[i];
+			var li = $('#'+id);
+			var resourcePathToDelete = this.getPathFromLi(li);
+			otherPathsToDelete.push(resourcePathToDelete);
+			var decodedResourcePath = this.mainController.decodeFromHTML(resourcePathToDelete);
+			otherPathsToDeleteDecoded.push(decodedResourcePath);
+		}
+		var confirmationMsg = "You are about to delete '"+otherPathsToDelete+"' and all its sub nodes. Are you sure?";
+		bootbox.confirm(confirmationMsg, function(result) {
+			if (result){
+					//http://www.jstree.com/api/#/?q=delete&f=delete_node.jstree
+			    	$.ajax({
+			        	  type: 'POST',
+						  url: parentPath,
+			        	  success: function(server_data) {
+							var tree = $('#tree').jstree(true);
+							for (var i=0; i<selectedIds.length; i++){
+								var id = selectedIds[i];
+								tree.delete_node(id);
+							}
+			      		  },
+			        	  error: function(errorJson) {
+			        		thatTreeController.mainController.displayAlert(errorJson);
+			      		  },
+			      		  traditional: true,
+			      		  dataType: "json",
+						  contentType : 'application/x-www-form-urlencoded; charset=UTF-8',
+			        	  data: { 
+			        		  ":operation": "delete",
+			  		  		  "_charset_": "utf-8",
+			            	  ":applyTo": otherPathsToDeleteDecoded        		
+			        	  }
+			        });
+			}
+		});
+	}
+
+	TreeController.prototype.deleteSingleNode = function(li) {
+		var thatTreeController = this;
+		var resourcePathToDelete = this.getPathFromLi(li);
+		var confirmationMsg = "You are about to delete '"+resourcePathToDelete+"' and all its sub nodes. Are you sure?";
+		var decodedResourcePath = this.mainController.decodeFromHTML(resourcePathToDelete);
+		var encodedResourcePathToDelete = this.mainController.encodeURL(decodedResourcePath);
+		bootbox.confirm(confirmationMsg, function(result) {
+			if (result){
+		    	$.ajax({
+		        	  type: 'POST',
+					  url: encodedResourcePathToDelete,
+		        	  success: function(server_data) {
+		        		var id = li.attr("id");
+						var tree = $('#tree').jstree(true);
+						tree.delete_node(id);
+		      		  },
+		        	  error: function(errorJson) {
+		        		thatTreeController.mainController.displayAlert(errorJson);
+		      		  },
+					  dataType: "json",
+		        	  data: { 
+		        		  ":operation": "delete"
+		        	  }
+		        });
+			}
+		});
+	}
+
+	TreeController.prototype.openAddNodeDialog = function(li) {
+		var thatTreeController = this;
+		var resourcePath = this.getPathFromLi(li);
+		this.addNodeController.openAddNodeDialog(resourcePath);
+	}
+
+	/*
+	function isModifierPressed(e){
+		return (e.shiftKey || e.altKey || e.ctrlKey);
+	}
+	*/
+
+	return TreeController;
+}());
+/*
+ * 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 TreeController is responsible for the node tree functionality of the Sling Resource Editor
+ * that is not specific for a 3rd party library.
+ * JSTree-specific functionality is implemented in the JSTreeAdapter instead.
+ */
+
+//defining the module
+org.apache.sling.reseditor.TreeController = (function() {
+
+	function TreeController(settings, mainController){
+		var thatTreeController = this;
+		this.settings = settings;
+		this.mainController = mainController;
+
+		var addNodeControllerSettings = {};
+		this.addNodeController = new org.apache.sling.reseditor.AddNodeController(addNodeControllerSettings, mainController);
+		
+		$(document).ready(function() {
+			$("#tree").on("click", "li.jstree-node>a.jstree-anchor>i.open-icon",function(e, data) {
+				thatTreeController.openNodeTarget(e);
+			});
+			$("#tree").on("click", "li.jstree-node>a.jstree-anchor>i.add-icon",function(e, data) {
+				thatTreeController.openAddNodeDialog($(e.target).parents("li"));
+			});
+			$("#tree").on("click", "li.jstree-node>a.jstree-anchor>i.remove-icon",function(e, data) {
+				thatTreeController.deleteSingleNode($(e.target).parents("li"));
+			});
+	
+			$("#tree").on("dblclick", "li.jstree-node>a.jstree-anchor",function(e, data) {
+				var id = $(e.target).parents("li:first").attr("id");
+				thatTreeController.openRenameNodeDialog(id);
+			});
+		});
+	};
+
+	TreeController.prototype.openNodeTarget = function(e) {
+		var url = $(e.target).parent().attr("href");
+		url = this.mainController.decodeFromHTML(url);
+		url = this.mainController.encodeURL(url);
+		location.href=url;
+	}
+
+	TreeController.prototype.openRenameNodeDialog = function(id) {
+		var liElement = $('#'+id);
+		$("#tree").jstree("edit", $('#'+id), this.mainController.decodeFromHTML(liElement.attr("nodename")));
+	}
+	
+	TreeController.prototype.renameNode = function(e, data) {
+		var thatTreeController = this;
+		var newName = this.mainController.decodeFromHTML(data.text);
+		var oldName = data.old;
+		if (oldName!==newName){
+			var currentURL = this.getPathFromLi($('#'+data.node.id));
+			var unencodedURI = currentURL;
+			var decodedCurrentURI = this.mainController.decodeFromHTML(unencodedURI);
+			var newURI = decodedCurrentURI.replace(oldName, newName);
+			currentURL = this.mainController.encodeURL(decodedCurrentURI);
+			$.ajax({
+		  	  type: 'POST',
+			  url: currentURL,
+		  	  success: function(server_data) {
+		  		  thatTreeController.mainController.redirectTo(newURI);
+			  },
+		  	  error: function(errorJson) {
+		  		  thatTreeController.mainController.displayAlert(errorJson);
+			  },
+			  dataType: "json",
+			  contentType : 'application/x-www-form-urlencoded; charset=UTF-8',
+		  	  data: { 
+		  		":operation": "move",
+		  		"_charset_": "utf-8",
+		  		":dest": newURI
+		  		  }
+		  	});
+		}
+	}
+	
+	TreeController.prototype.getSelectorFromPath = function(path){
+		var paths = path.substring(1).split("/");
+		return "#tree > ul [nodename='"+paths.join("'] > ul > [nodename='")+"']";
+	}
+
+	TreeController.prototype.getPathFromLi = function(li){
+		var path = $(li).parentsUntil(".root").andSelf().map(
+				function() {
+					return this.tagName == "LI"
+							? $(this).attr("nodename") 
+							: null;
+				}
+			).get().join("/");
+		return "" == path ? "/" : path;
+	};
+
+	TreeController.prototype.getURLEncodedPathFromLi = function(li){
+		var htmlEncodedPath = this.getPathFromLi(li);
+		var htmlDecodedPath = this.mainController.decodeFromHTML(htmlEncodedPath);
+		return this.mainController.encodeURL(htmlDecodedPath);
+	};
+
+	TreeController.prototype.openElement = function(root, paths) {
+		var thisTreeController = this;
+		var pathElementName = paths.shift();
+		var pathElementLi = root.children("[nodename='"+pathElementName+"']");
+		if (pathElementLi.length === 0){
+			alert("Couldn't find "+pathElementName+" under the path "+this.getPathFromLi(root.parent()));
+		} else {
+			$('#tree').jstree('open_node', pathElementLi,
+					function(){
+						if (paths.length>0){
+							thisTreeController.openElement($("#"+pathElementLi.attr('id')).children("ul"), paths);
+						} else  {
+							selectingNodeWhileOpeningTree=true;
+							$('#tree').jstree('select_node', pathElementLi.attr('id'), 'true'/*doesn't seem to work*/);
+							selectingNodeWhileOpeningTree=false;
+					        var target = $('#'+pathElementLi.attr('id')+' a:first');
+					        target.focus();
+						}
+					}
+				);
+		}
+	}
+
+	TreeController.prototype.get_uri_from_li = function(li, extension){
+		var path = this.getPathFromLi(li);
+		path = this.mainController.decodeFromHTML(path);
+		path = this.mainController.encodeURL(path);
+		return this.settings.contextPath+"/reseditor"+path+extension;
+	}
+
+	TreeController.prototype.deleteNodes = function() {
+		var thatTreeController = this;
+		var lastDeletedLI;
+		var selectedIds = $("#tree").jstree('get_selected');
+		var firstId = selectedIds[0];
+		var parentLi = $('#'+firstId).parents('li');
+		var parentPath = this.getURLEncodedPathFromLi(parentLi);
+		var otherPathsToDelete = [];
+		var otherPathsToDeleteDecoded = [];
+		for (var i=0; i<selectedIds.length; i++){
+			var id = selectedIds[i];
+			var li = $('#'+id);
+			var resourcePathToDelete = this.getPathFromLi(li);
+			otherPathsToDelete.push(resourcePathToDelete);
+			var decodedResourcePath = this.mainController.decodeFromHTML(resourcePathToDelete);
+			otherPathsToDeleteDecoded.push(decodedResourcePath);
+		}
+		var confirmationMsg = "You are about to delete '"+otherPathsToDelete+"' and all its sub nodes. Are you sure?";
+		bootbox.confirm(confirmationMsg, function(result) {
+			if (result){
+					//http://www.jstree.com/api/#/?q=delete&f=delete_node.jstree
+			    	$.ajax({
+			        	  type: 'POST',
+						  url: parentPath,
+			        	  success: function(server_data) {
+							var tree = $('#tree').jstree(true);
+							for (var i=0; i<selectedIds.length; i++){
+								var id = selectedIds[i];
+								tree.delete_node(id);
+							}
+			      		  },
+			        	  error: function(errorJson) {
+			        		thatTreeController.mainController.displayAlert(errorJson);
+			      		  },
+			      		  traditional: true,
+			      		  dataType: "json",
+						  contentType : 'application/x-www-form-urlencoded; charset=UTF-8',
+			        	  data: { 
+			        		  ":operation": "delete",
+			  		  		  "_charset_": "utf-8",
+			            	  ":applyTo": otherPathsToDeleteDecoded        		
+			        	  }
+			        });
+			}
+		});
+	}
+
+	TreeController.prototype.deleteSingleNode = function(li) {
+		var thatTreeController = this;
+		var resourcePathToDelete = this.getPathFromLi(li);
+		var confirmationMsg = "You are about to delete '"+resourcePathToDelete+"' and all its sub nodes. Are you sure?";
+		var decodedResourcePath = this.mainController.decodeFromHTML(resourcePathToDelete);
+		var encodedResourcePathToDelete = this.mainController.encodeURL(decodedResourcePath);
+		bootbox.confirm(confirmationMsg, function(result) {
+			if (result){
+		    	$.ajax({
+		        	  type: 'POST',
+					  url: encodedResourcePathToDelete,
+		        	  success: function(server_data) {
+		        		var id = li.attr("id");
+						var tree = $('#tree').jstree(true);
+						tree.delete_node(id);
+		      		  },
+		        	  error: function(errorJson) {
+		        		thatTreeController.mainController.displayAlert(errorJson);
+		      		  },
+					  dataType: "json",
+		        	  data: { 
+		        		  ":operation": "delete"
+		        	  }
+		        });
+			}
+		});
+	}
+
+	TreeController.prototype.openAddNodeDialog = function(li) {
+		var thatTreeController = this;
+		var resourcePath = this.getPathFromLi(li);
+		this.addNodeController.openAddNodeDialog(resourcePath);
+	}
+
+	/*
+	function isModifierPressed(e){
+		return (e.shiftKey || e.altKey || e.ctrlKey);
+	}
+	*/
+
+	return TreeController;
+}());