From b05c4711ce7e5862ed9a8bacb464af5c415e8e2a Mon Sep 17 00:00:00 2001 From: Per Ploug Date: Mon, 30 Jan 2017 13:33:05 +0100 Subject: [PATCH 1/3] Fixes tree syncing issues --- .../src/views/partialviews/edit.controller.js | 3 +- src/Umbraco.Web/Editors/CodeFileController.cs | 33 +++++++++++++---- .../Models/ContentEditing/CodeFileDisplay.cs | 3 ++ .../Models/Mapping/CodeFileDisplayMapper.cs | 2 + .../Trees/FileSystemTreeController.cs | 4 +- src/Umbraco.Web/Trees/UrlHelperExtensions.cs | 37 +++++++++++++++++++ 6 files changed, 72 insertions(+), 10 deletions(-) diff --git a/src/Umbraco.Web.UI.Client/src/views/partialviews/edit.controller.js b/src/Umbraco.Web.UI.Client/src/views/partialviews/edit.controller.js index 11dba8a63e..dc388a906b 100644 --- a/src/Umbraco.Web.UI.Client/src/views/partialviews/edit.controller.js +++ b/src/Umbraco.Web.UI.Client/src/views/partialviews/edit.controller.js @@ -245,7 +245,8 @@ //sync state editorState.set(vm.partialView); - navigationService.syncTree({ tree: "partialViews", path: vm.partialView.virtualPath, forceReload: true }).then(function (syncArgs) { + + navigationService.syncTree({ tree: "partialViews", path: vm.partialView.path, forceReload: true }).then(function (syncArgs) { vm.page.menu.currentNode = syncArgs.node; }); diff --git a/src/Umbraco.Web/Editors/CodeFileController.cs b/src/Umbraco.Web/Editors/CodeFileController.cs index 60dcf624a0..58dd28a15e 100644 --- a/src/Umbraco.Web/Editors/CodeFileController.cs +++ b/src/Umbraco.Web/Editors/CodeFileController.cs @@ -8,6 +8,8 @@ using Umbraco.Web.Models.ContentEditing; using Umbraco.Web.Mvc; using Umbraco.Web.WebApi; using Umbraco.Web.WebApi.Filters; +using Umbraco.Web.Trees; +using Umbraco.Core.IO; namespace Umbraco.Web.Editors { @@ -62,7 +64,7 @@ namespace Umbraco.Web.Editors } virtualPath = System.Web.HttpUtility.UrlDecode(virtualPath); - + switch (type) { @@ -72,6 +74,7 @@ namespace Umbraco.Web.Editors { var display = Mapper.Map(view); display.FileType = Core.Constants.Trees.PartialViews; + display.Path = Url.GetTreePathFromFilePath(view.Path); return display; } return null; @@ -82,6 +85,7 @@ namespace Umbraco.Web.Editors { var display = Mapper.Map(viewMacro); display.FileType = Core.Constants.Trees.PartialViewMacros; + display.Path = Url.GetTreePathFromFilePath(viewMacro.Path); return display; } return null; @@ -92,6 +96,7 @@ namespace Umbraco.Web.Editors { var display = Mapper.Map(script); display.FileType = Core.Constants.Trees.Scripts; + display.Path = Url.GetTreePathFromFilePath(script.Path); return display; } return null; @@ -171,12 +176,15 @@ namespace Umbraco.Web.Editors // might need to find the path var orgPath = view.OriginalPath.Substring(0, view.OriginalPath.IndexOf(view.Name)); view.Path = orgPath + display.Name; - view.Content = display.Content; + + //Save the file and update the response to reflect any name and path changes var result = Services.FileService.SavePartialView(view, Security.CurrentUser.Id); if (result.Success == true) { - return Mapper.Map(view, display); + display = Mapper.Map(result.Result, display); + display.Path = Url.GetTreePathFromFilePath(view.Path); + return display; } display.AddErrorNotification( @@ -195,13 +203,19 @@ namespace Umbraco.Web.Editors { viewMacro.Content = display.Content; viewMacro.Path = display.Name; + + //save the file and update the display to reflect any path and name changes var result = Services.FileService.SavePartialViewMacro(viewMacro, Security.CurrentUser.Id); - if (result.Success == false) + if (result.Success == true) { - display.AddErrorNotification( - Services.TextService.Localize("speechBubbles/macroPartialViewErrorHeader"), - Services.TextService.Localize("speechBubbles/macroPartialViewErrorText")); + display = Mapper.Map(result.Result, display); + display.Path = Url.GetTreePathFromFilePath(result.Result.Path); + return display; } + + display.AddErrorNotification( + Services.TextService.Localize("speechBubbles/partialViewErrorHeader"), + Services.TextService.Localize("speechBubbles/partialViewErrorText")); } else { @@ -215,7 +229,12 @@ namespace Umbraco.Web.Editors { script.Content = display.Content; script.Path = display.Name; + Services.FileService.SaveScript(script, Security.CurrentUser.Id); + display = Mapper.Map(script, display); + display.Path = Url.GetTreePathFromFilePath(script.Path); + return display; + } else diff --git a/src/Umbraco.Web/Models/ContentEditing/CodeFileDisplay.cs b/src/Umbraco.Web/Models/ContentEditing/CodeFileDisplay.cs index c63e2b98c0..690897b9ad 100644 --- a/src/Umbraco.Web/Models/ContentEditing/CodeFileDisplay.cs +++ b/src/Umbraco.Web/Models/ContentEditing/CodeFileDisplay.cs @@ -14,6 +14,9 @@ namespace Umbraco.Web.Models.ContentEditing [DataMember(Name = "virtualPath", IsRequired = true)] public string VirtualPath { get; set; } + [DataMember(Name = "path", IsRequired = true)] + public string Path { get; set; } + [DataMember(Name = "name", IsRequired = true)] public string Name { get; set; } diff --git a/src/Umbraco.Web/Models/Mapping/CodeFileDisplayMapper.cs b/src/Umbraco.Web/Models/Mapping/CodeFileDisplayMapper.cs index 60edb87105..aa033c91b0 100644 --- a/src/Umbraco.Web/Models/Mapping/CodeFileDisplayMapper.cs +++ b/src/Umbraco.Web/Models/Mapping/CodeFileDisplayMapper.cs @@ -18,11 +18,13 @@ namespace Umbraco.Web.Models.Mapping config.CreateMap() .ForMember(x => x.FileType, exp => exp.Ignore()) .ForMember(x => x.Notifications, exp => exp.Ignore()) + .ForMember(x => x.Path, exp => exp.Ignore()) .ForMember(x => x.Snippet, exp => exp.Ignore()); config.CreateMap() .ForMember(x => x.FileType, exp => exp.Ignore()) .ForMember(x => x.Notifications, exp => exp.Ignore()) + .ForMember(x => x.Path, exp => exp.Ignore()) .ForMember(x => x.Snippet, exp => exp.Ignore()); config.CreateMap() diff --git a/src/Umbraco.Web/Trees/FileSystemTreeController.cs b/src/Umbraco.Web/Trees/FileSystemTreeController.cs index 8740d1c939..61ee8c4ff9 100644 --- a/src/Umbraco.Web/Trees/FileSystemTreeController.cs +++ b/src/Umbraco.Web/Trees/FileSystemTreeController.cs @@ -33,7 +33,7 @@ namespace Umbraco.Web.Trees string path = ""; if (!string.IsNullOrEmpty(id) && id != "-1") { - orgPath = id; + orgPath = System.Web.HttpUtility.UrlDecode(id); path = IOHelper.MapPath(FilePath + "/" + orgPath); orgPath += "/"; } @@ -51,7 +51,7 @@ namespace Umbraco.Web.Trees if ((dir.Attributes & FileAttributes.Hidden) == 0) { var HasChildren = dir.GetFiles().Length > 0 || dir.GetDirectories().Length > 0; - var node = CreateTreeNode(orgPath + dir.Name, orgPath, queryStrings, dir.Name, "icon-folder", HasChildren); + var node = CreateTreeNode(System.Web.HttpUtility.UrlEncode(orgPath + dir.Name), orgPath, queryStrings, dir.Name, "icon-folder", HasChildren); OnRenderFolderNode(ref node); if(node != null) diff --git a/src/Umbraco.Web/Trees/UrlHelperExtensions.cs b/src/Umbraco.Web/Trees/UrlHelperExtensions.cs index 0931fc0997..df24458870 100644 --- a/src/Umbraco.Web/Trees/UrlHelperExtensions.cs +++ b/src/Umbraco.Web/Trees/UrlHelperExtensions.cs @@ -1,5 +1,8 @@ using System; +using System.Linq; using System.Net.Http.Formatting; +using System.Text; +using System.Web; using System.Web.Http.Routing; using Umbraco.Core; @@ -30,5 +33,39 @@ namespace Umbraco.Web.Trees return actionUrl; } + + public static string GetTreePathFromFilePath(this UrlHelper urlHelper, string virtualPath, string basePath = "") + { + //This reuses the Logic from umbraco.cms.helpers.DeepLink class + //to convert a filepath to a tree syncing path string. + + //removes the basepath from the path + //and normalises paths - / is used consistently between trees and editors + basePath = basePath.TrimStart("~"); + virtualPath = virtualPath.TrimStart("~"); + virtualPath = virtualPath.Substring(basePath.Length); + virtualPath = virtualPath.Replace('\\', '/'); + + //-1 is the default root id for trees + var sb = new StringBuilder(); + sb.Append("-1"); + + //split the virtual path and iterate through it + string[] pathPaths = virtualPath.Split('/'); + + for (int p = 0; p < pathPaths.Length; p++) + { + var path = HttpUtility.UrlEncode(string.Join("/", pathPaths.Take(p + 1))); + if (string.IsNullOrEmpty(path) == false) + { + sb.Append(","); + sb.Append(path); + } + } + + return sb.ToString().Trim(","); + + } + } } \ No newline at end of file From 90448f1c78f5d9e056a0b5642cb55c253e120a18 Mon Sep 17 00:00:00 2001 From: Per Ploug Date: Tue, 31 Jan 2017 11:06:14 +0100 Subject: [PATCH 2/3] Added comments and made helper internal --- .../Models/ContentEditing/CodeFileDisplay.cs | 14 +++++++++++++- src/Umbraco.Web/Trees/UrlHelperExtensions.cs | 2 +- 2 files changed, 14 insertions(+), 2 deletions(-) diff --git a/src/Umbraco.Web/Models/ContentEditing/CodeFileDisplay.cs b/src/Umbraco.Web/Models/ContentEditing/CodeFileDisplay.cs index 690897b9ad..dd2425259b 100644 --- a/src/Umbraco.Web/Models/ContentEditing/CodeFileDisplay.cs +++ b/src/Umbraco.Web/Models/ContentEditing/CodeFileDisplay.cs @@ -11,10 +11,22 @@ namespace Umbraco.Web.Models.ContentEditing [DataContract(Name = "scriptFile", Namespace = "")] public class CodeFileDisplay : INotificationModel { + /// + /// VirtualPath is the path to the file on disk + /// /views/partials/file.cshtml + /// [DataMember(Name = "virtualPath", IsRequired = true)] public string VirtualPath { get; set; } - [DataMember(Name = "path", IsRequired = true)] + /// + /// Path represents the path used by the backoffice tree + /// For files stored on disk, this is a urlencoded, comma seperated + /// path to the file, always starting with -1. + /// + /// -1,Partials,Parials%2FFolder,Partials%2FFolder%2FFile.cshtml + /// + [DataMember(Name = "path")] + [ReadOnly(true)] public string Path { get; set; } [DataMember(Name = "name", IsRequired = true)] diff --git a/src/Umbraco.Web/Trees/UrlHelperExtensions.cs b/src/Umbraco.Web/Trees/UrlHelperExtensions.cs index df24458870..acb10e31c5 100644 --- a/src/Umbraco.Web/Trees/UrlHelperExtensions.cs +++ b/src/Umbraco.Web/Trees/UrlHelperExtensions.cs @@ -34,7 +34,7 @@ namespace Umbraco.Web.Trees } - public static string GetTreePathFromFilePath(this UrlHelper urlHelper, string virtualPath, string basePath = "") + internal static string GetTreePathFromFilePath(this UrlHelper urlHelper, string virtualPath, string basePath = "") { //This reuses the Logic from umbraco.cms.helpers.DeepLink class //to convert a filepath to a tree syncing path string. From 06c829eb27e30e10a35a18cef5a56c121edcdb84 Mon Sep 17 00:00:00 2001 From: Claus Date: Wed, 1 Feb 2017 14:03:03 +0100 Subject: [PATCH 3/3] initializing stringbuilder with text instead of appending after init. trimming end instead of both beginning and end, since we know whats in the beginning. --- src/Umbraco.Web/Trees/UrlHelperExtensions.cs | 14 +++++--------- 1 file changed, 5 insertions(+), 9 deletions(-) diff --git a/src/Umbraco.Web/Trees/UrlHelperExtensions.cs b/src/Umbraco.Web/Trees/UrlHelperExtensions.cs index acb10e31c5..4b94f548ca 100644 --- a/src/Umbraco.Web/Trees/UrlHelperExtensions.cs +++ b/src/Umbraco.Web/Trees/UrlHelperExtensions.cs @@ -47,25 +47,21 @@ namespace Umbraco.Web.Trees virtualPath = virtualPath.Replace('\\', '/'); //-1 is the default root id for trees - var sb = new StringBuilder(); - sb.Append("-1"); + var sb = new StringBuilder("-1"); //split the virtual path and iterate through it - string[] pathPaths = virtualPath.Split('/'); + var pathPaths = virtualPath.Split('/'); - for (int p = 0; p < pathPaths.Length; p++) + for (var p = 0; p < pathPaths.Length; p++) { var path = HttpUtility.UrlEncode(string.Join("/", pathPaths.Take(p + 1))); if (string.IsNullOrEmpty(path) == false) { sb.Append(","); - sb.Append(path); + sb.Append(path); } } - - return sb.ToString().Trim(","); - + return sb.ToString().TrimEnd(","); } - } } \ No newline at end of file