From 291d92bfc9209a471200c06605a8675331392a92 Mon Sep 17 00:00:00 2001 From: Claus Date: Fri, 22 Jan 2016 13:38:43 +0100 Subject: [PATCH 1/6] Fixes: U4-7700 7.4 beta Backoffice Routing problem for Custom Sections or Installed Packages with a custom section Reverting the lowercasing happening in the angular routing and navigation. Ensuring tree section registrations are updated instead of added in trees.config. The lowercasing was introduced to compensate for this. --- .../Services/ApplicationTreeService.cs | 39 +++++++++++++------ .../src/common/services/navigation.service.js | 14 ++++--- src/Umbraco.Web.UI.Client/src/routes.js | 6 +-- 3 files changed, 39 insertions(+), 20 deletions(-) diff --git a/src/Umbraco.Core/Services/ApplicationTreeService.cs b/src/Umbraco.Core/Services/ApplicationTreeService.cs index c9ce839450..01e2883435 100644 --- a/src/Umbraco.Core/Services/ApplicationTreeService.cs +++ b/src/Umbraco.Core/Services/ApplicationTreeService.cs @@ -3,6 +3,7 @@ using System.Collections.Generic; using System.IO; using System.Linq; using System.Xml.Linq; +using System.Xml.XPath; using Umbraco.Core.Cache; using Umbraco.Core.Events; using Umbraco.Core.IO; @@ -84,7 +85,7 @@ namespace Umbraco.Core.Services // based on the ApplicationTreeRegistrar - and as noted there this is not an ideal way to do things but were stuck like this // currently because of the legacy assemblies and types not in the Core. - //Get all the trees not registered in the config + //Get all the trees not registered in the config (those not matching by alias casing will be detected as "unregistered") var unregistered = _allAvailableTrees .Where(x => list.Any(l => l.Alias == x.Alias) == false) .ToArray(); @@ -93,19 +94,35 @@ namespace Umbraco.Core.Services if (hasChanges == false) return false; - //add the unregistered ones to the list and re-save the file if any changes were found + //add or edit the unregistered ones and re-save the file if any changes were found var count = 0; foreach (var tree in unregistered) { - doc.Root.Add(new XElement("add", - new XAttribute("initialize", tree.Initialize), - new XAttribute("sortOrder", tree.SortOrder), - new XAttribute("alias", tree.Alias), - new XAttribute("application", tree.ApplicationAlias), - new XAttribute("title", tree.Title), - new XAttribute("iconClosed", tree.IconClosed), - new XAttribute("iconOpen", tree.IconOpened), - new XAttribute("type", tree.Type))); + //ugly translate hack to allow case insensitive matching since 'matches' is a xpath2.0 feature... + var existingElement = doc.Root.XPathSelectElement("//add[translate(@alias,'abcdefghijklmnopqrstuvwxyz','ABCDEFGHIJKLMNOPQRSTUVWXYZ')=translate('" + tree.Alias + "','abcdefghijklmnopqrstuvwxyz','ABCDEFGHIJKLMNOPQRSTUVWXYZ')]"); + if (existingElement != null) + { + existingElement.SetAttributeValue("initialize", tree.Initialize); + existingElement.SetAttributeValue("sortOrder", tree.Initialize); + existingElement.SetAttributeValue("alias", tree.Alias); + existingElement.SetAttributeValue("application", tree.ApplicationAlias); + existingElement.SetAttributeValue("title", tree.Title); + existingElement.SetAttributeValue("iconClosed", tree.IconClosed); + existingElement.SetAttributeValue("iconOpen", tree.IconOpened); + existingElement.SetAttributeValue("type", tree.Type); + } + else + { + doc.Root.Add(new XElement("add", + new XAttribute("initialize", tree.Initialize), + new XAttribute("sortOrder", tree.SortOrder), + new XAttribute("alias", tree.Alias), + new XAttribute("application", tree.ApplicationAlias), + new XAttribute("title", tree.Title), + new XAttribute("iconClosed", tree.IconClosed), + new XAttribute("iconOpen", tree.IconOpened), + new XAttribute("type", tree.Type))); + } count++; } diff --git a/src/Umbraco.Web.UI.Client/src/common/services/navigation.service.js b/src/Umbraco.Web.UI.Client/src/common/services/navigation.service.js index 7bc069ef44..1c495b1d18 100644 --- a/src/Umbraco.Web.UI.Client/src/common/services/navigation.service.js +++ b/src/Umbraco.Web.UI.Client/src/common/services/navigation.service.js @@ -108,7 +108,7 @@ function navigationService($rootScope, $routeParams, $log, $location, $q, $timeo * @param {String} source The URL to load into the iframe */ loadLegacyIFrame: function (source) { - $location.path("/" + appState.getSectionState("currentSection").toLowerCase() + "/framed/" + encodeURIComponent(source)); + $location.path("/" + appState.getSectionState("currentSection") + "/framed/" + encodeURIComponent(source)); }, /** @@ -132,7 +132,7 @@ function navigationService($rootScope, $routeParams, $log, $location, $q, $timeo appState.setSectionState("currentSection", sectionAlias); this.showTree(sectionAlias); - $location.path(sectionAlias.toLowerCase()); + $location.path(sectionAlias); }, /** @@ -214,7 +214,9 @@ function navigationService($rootScope, $routeParams, $log, $location, $q, $timeo //this reacts to tree items themselves being clicked //the tree directive should not contain any handling, simply just bubble events - mainTreeEventHandler.bind("treeNodeSelect", function(ev, args) { + mainTreeEventHandler.bind("treeNodeSelect", function (ev, args) { + console.log('navigating-ev', ev); + console.log('navigating-args', args); var n = args.node; ev.stopPropagation(); ev.preventDefault(); @@ -250,10 +252,10 @@ function navigationService($rootScope, $routeParams, $log, $location, $q, $timeo appState.setMenuState("currentNode", args.node); //not legacy, lets just set the route value and clear the query string if there is one. - $location.path(n.routePath.toLowerCase()).search(""); + $location.path(n.routePath).search(""); } else if (args.element.section) { - $location.path(args.element.section.toLowerCase()).search(""); + $location.path(args.element.section).search(""); } service.hideNavigation(); @@ -446,7 +448,7 @@ function navigationService($rootScope, $routeParams, $log, $location, $q, $timeo if (action.metaData && action.metaData["actionRoute"] && angular.isString(action.metaData["actionRoute"])) { //first check if the menu item simply navigates to a route var parts = action.metaData["actionRoute"].split("?"); - $location.path(parts[0].toLowerCase()).search(parts.length > 1 ? parts[1] : ""); + $location.path(parts[0]).search(parts.length > 1 ? parts[1] : ""); this.hideNavigation(); return; } diff --git a/src/Umbraco.Web.UI.Client/src/routes.js b/src/Umbraco.Web.UI.Client/src/routes.js index bd122a6c7c..5d641fcb6c 100644 --- a/src/Umbraco.Web.UI.Client/src/routes.js +++ b/src/Umbraco.Web.UI.Client/src/routes.js @@ -130,7 +130,7 @@ app.config(function ($routeProvider) { // angular dashboards working. Perhaps a normal section dashboard would list out the registered // dashboards (as tabs if we wanted) and each tab could actually be a route link to one of these views? - return ('views/' + rp.tree + '/' + rp.method + '.html').toLowerCase(); + return ('views/' + rp.tree + '/' + rp.method + '.html'); }, resolve: canRoute(true) }) @@ -156,10 +156,10 @@ app.config(function ($routeProvider) { if (packageTreeFolder) { $scope.templateUrl = (Umbraco.Sys.ServerVariables.umbracoSettings.appPluginsPath + "/" + packageTreeFolder + - "/backoffice/" + $routeParams.tree + "/" + $routeParams.method + ".html").toLowerCase(); + "/backoffice/" + $routeParams.tree + "/" + $routeParams.method + ".html"); } else { - $scope.templateUrl = ('views/' + $routeParams.tree + '/' + $routeParams.method + '.html').toLowerCase(); + $scope.templateUrl = ('views/' + $routeParams.tree + '/' + $routeParams.method + '.html'); } }, From c4e8e20f02748d027909e6d521cf22b095fa4125 Mon Sep 17 00:00:00 2001 From: Claus Date: Sun, 24 Jan 2016 15:36:29 +0100 Subject: [PATCH 2/6] Reverted to only update exactly what is needed for this to work. Switched away from ugly xpath - using linq. --- .../Services/ApplicationTreeService.cs | 18 +++++------------- 1 file changed, 5 insertions(+), 13 deletions(-) diff --git a/src/Umbraco.Core/Services/ApplicationTreeService.cs b/src/Umbraco.Core/Services/ApplicationTreeService.cs index 01e2883435..a3ab673e86 100644 --- a/src/Umbraco.Core/Services/ApplicationTreeService.cs +++ b/src/Umbraco.Core/Services/ApplicationTreeService.cs @@ -98,18 +98,14 @@ namespace Umbraco.Core.Services var count = 0; foreach (var tree in unregistered) { - //ugly translate hack to allow case insensitive matching since 'matches' is a xpath2.0 feature... - var existingElement = doc.Root.XPathSelectElement("//add[translate(@alias,'abcdefghijklmnopqrstuvwxyz','ABCDEFGHIJKLMNOPQRSTUVWXYZ')=translate('" + tree.Alias + "','abcdefghijklmnopqrstuvwxyz','ABCDEFGHIJKLMNOPQRSTUVWXYZ')]"); + var existingElement = doc.Root.Elements("add").SingleOrDefault(x => + string.Equals(x.Attribute("alias").Value, tree.Alias, + StringComparison.InvariantCultureIgnoreCase) && + string.Equals(x.Attribute("application").Value, tree.ApplicationAlias, + StringComparison.InvariantCultureIgnoreCase)); if (existingElement != null) { - existingElement.SetAttributeValue("initialize", tree.Initialize); - existingElement.SetAttributeValue("sortOrder", tree.Initialize); existingElement.SetAttributeValue("alias", tree.Alias); - existingElement.SetAttributeValue("application", tree.ApplicationAlias); - existingElement.SetAttributeValue("title", tree.Title); - existingElement.SetAttributeValue("iconClosed", tree.IconClosed); - existingElement.SetAttributeValue("iconOpen", tree.IconOpened); - existingElement.SetAttributeValue("type", tree.Type); } else { @@ -141,11 +137,7 @@ namespace Umbraco.Core.Services } } } - - return list; - - }, new TimeSpan(0, 10, 0)); } From 4372c9df40cce67074012a85d6c7e12feabd8b25 Mon Sep 17 00:00:00 2001 From: Claus Date: Sun, 24 Jan 2016 15:40:23 +0100 Subject: [PATCH 3/6] remove refs. --- src/Umbraco.Core/Services/ApplicationTreeService.cs | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/Umbraco.Core/Services/ApplicationTreeService.cs b/src/Umbraco.Core/Services/ApplicationTreeService.cs index a3ab673e86..f2c1c5e8f8 100644 --- a/src/Umbraco.Core/Services/ApplicationTreeService.cs +++ b/src/Umbraco.Core/Services/ApplicationTreeService.cs @@ -3,13 +3,11 @@ using System.Collections.Generic; using System.IO; using System.Linq; using System.Xml.Linq; -using System.Xml.XPath; using Umbraco.Core.Cache; using Umbraco.Core.Events; using Umbraco.Core.IO; using Umbraco.Core.Logging; using Umbraco.Core.Models; -using Umbraco.Core.Cache; using File = System.IO.File; namespace Umbraco.Core.Services From 7ac1c8ab6fac75d29b9ebf016debad887ee4252f Mon Sep 17 00:00:00 2001 From: Claus Date: Sun, 24 Jan 2016 15:43:43 +0100 Subject: [PATCH 4/6] forgot a few console.log's. --- .../src/common/services/navigation.service.js | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/Umbraco.Web.UI.Client/src/common/services/navigation.service.js b/src/Umbraco.Web.UI.Client/src/common/services/navigation.service.js index 1c495b1d18..9687e5c40d 100644 --- a/src/Umbraco.Web.UI.Client/src/common/services/navigation.service.js +++ b/src/Umbraco.Web.UI.Client/src/common/services/navigation.service.js @@ -215,8 +215,6 @@ function navigationService($rootScope, $routeParams, $log, $location, $q, $timeo //this reacts to tree items themselves being clicked //the tree directive should not contain any handling, simply just bubble events mainTreeEventHandler.bind("treeNodeSelect", function (ev, args) { - console.log('navigating-ev', ev); - console.log('navigating-args', args); var n = args.node; ev.stopPropagation(); ev.preventDefault(); From 1118d957731f24f2d8dc4ad80f7f8663fd6d209d Mon Sep 17 00:00:00 2001 From: Shannon Date: Mon, 25 Jan 2016 11:14:06 +0100 Subject: [PATCH 5/6] added a null check --- .../Services/ApplicationTreeService.cs | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/src/Umbraco.Core/Services/ApplicationTreeService.cs b/src/Umbraco.Core/Services/ApplicationTreeService.cs index f2c1c5e8f8..1491a59776 100644 --- a/src/Umbraco.Core/Services/ApplicationTreeService.cs +++ b/src/Umbraco.Core/Services/ApplicationTreeService.cs @@ -107,7 +107,20 @@ namespace Umbraco.Core.Services } else { - doc.Root.Add(new XElement("add", + if (tree.Title.IsNullOrWhiteSpace()) + { + doc.Root.Add(new XElement("add", + new XAttribute("initialize", tree.Initialize), + new XAttribute("sortOrder", tree.SortOrder), + new XAttribute("alias", tree.Alias), + new XAttribute("application", tree.ApplicationAlias), + new XAttribute("iconClosed", tree.IconClosed), + new XAttribute("iconOpen", tree.IconOpened), + new XAttribute("type", tree.Type))); + } + else + { + doc.Root.Add(new XElement("add", new XAttribute("initialize", tree.Initialize), new XAttribute("sortOrder", tree.SortOrder), new XAttribute("alias", tree.Alias), @@ -116,6 +129,8 @@ namespace Umbraco.Core.Services new XAttribute("iconClosed", tree.IconClosed), new XAttribute("iconOpen", tree.IconOpened), new XAttribute("type", tree.Type))); + } + } count++; } From 2e4941053cc4b4bee64a353079d4d839e7953abe Mon Sep 17 00:00:00 2001 From: Shannon Date: Mon, 25 Jan 2016 11:19:18 +0100 Subject: [PATCH 6/6] more null checks --- .../Services/ApplicationTreeService.cs | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/src/Umbraco.Core/Services/ApplicationTreeService.cs b/src/Umbraco.Core/Services/ApplicationTreeService.cs index 1491a59776..a0a5d8cb82 100644 --- a/src/Umbraco.Core/Services/ApplicationTreeService.cs +++ b/src/Umbraco.Core/Services/ApplicationTreeService.cs @@ -373,13 +373,15 @@ namespace Umbraco.Core.Services { list.Add(new ApplicationTree( addElement.Attribute("initialize") == null || Convert.ToBoolean(addElement.Attribute("initialize").Value), - addElement.Attribute("sortOrder") != null ? Convert.ToByte(addElement.Attribute("sortOrder").Value) : (byte)0, - addElement.Attribute("application").Value, - addElement.Attribute("alias").Value, - addElement.Attribute("title").Value, - addElement.Attribute("iconClosed").Value, - addElement.Attribute("iconOpen").Value, - addElement.Attribute("type").Value)); + addElement.Attribute("sortOrder") != null + ? Convert.ToByte(addElement.Attribute("sortOrder").Value) + : (byte)0, + (string)addElement.Attribute("application"), + (string)addElement.Attribute("alias"), + (string)addElement.Attribute("title"), + (string)addElement.Attribute("iconClosed"), + (string)addElement.Attribute("iconOpen"), + (string)addElement.Attribute("type"))); } }