From f447294c0ba3d0c424b4cb0cf8a1db1925654785 Mon Sep 17 00:00:00 2001 From: Robert Date: Thu, 3 May 2018 10:18:08 +0200 Subject: [PATCH 1/8] Adds new end point that returns true/false if current document types allows variations, display language dropdown if current content types allow variations. --- .../common/resources/contenttype.resource.js | 9 +++++ .../services/contenttypehelper.service.js | 4 +++ .../src/controllers/navigation.controller.js | 36 ++++++++++++------- .../Editors/ContentTypeController.cs | 29 +++++++++------ 4 files changed, 55 insertions(+), 23 deletions(-) diff --git a/src/Umbraco.Web.UI.Client/src/common/resources/contenttype.resource.js b/src/Umbraco.Web.UI.Client/src/common/resources/contenttype.resource.js index 8bfcdfcc5a..2b0fd341d3 100644 --- a/src/Umbraco.Web.UI.Client/src/common/resources/contenttype.resource.js +++ b/src/Umbraco.Web.UI.Client/src/common/resources/contenttype.resource.js @@ -166,6 +166,15 @@ function contentTypeResource($q, $http, umbRequestHelper, umbDataFormatter) { 'Failed to retrieve all content types'); }, + allowsVariation: function() { + return umbRequestHelper.resourcePromise( + $http.get( + umbRequestHelper.getApiUrl( + "contentTypeApiBaseUrl", + "AllowsVariation")), + 'Failed to retrieve variant content types'); + }, + getScaffold: function (parentId) { return umbRequestHelper.resourcePromise( diff --git a/src/Umbraco.Web.UI.Client/src/common/services/contenttypehelper.service.js b/src/Umbraco.Web.UI.Client/src/common/services/contenttypehelper.service.js index 5c3e6eb4c8..034f2c5a3a 100644 --- a/src/Umbraco.Web.UI.Client/src/common/services/contenttypehelper.service.js +++ b/src/Umbraco.Web.UI.Client/src/common/services/contenttypehelper.service.js @@ -7,6 +7,10 @@ function contentTypeHelper(contentTypeResource, dataTypeResource, $filter, $inje var contentTypeHelperService = { + allowsVariation: function() { + return contentTypeResource.allowsVariation(); + }, + createIdArray: function(array) { var newArray = []; diff --git a/src/Umbraco.Web.UI.Client/src/controllers/navigation.controller.js b/src/Umbraco.Web.UI.Client/src/controllers/navigation.controller.js index 00458aa6b4..07fd546a25 100644 --- a/src/Umbraco.Web.UI.Client/src/controllers/navigation.controller.js +++ b/src/Umbraco.Web.UI.Client/src/controllers/navigation.controller.js @@ -9,7 +9,7 @@ * * @param {navigationService} navigationService A reference to the navigationService */ -function NavigationController($scope, $rootScope, $location, $log, $q, $routeParams, $timeout, treeService, appState, navigationService, keyboardService, dialogService, historyService, eventsService, sectionResource, angularHelper, languageResource) { +function NavigationController($scope, $rootScope, $location, $log, $q, $routeParams, $timeout, treeService, appState, navigationService, keyboardService, dialogService, historyService, eventsService, sectionResource, angularHelper, languageResource, contentTypeHelper) { $scope.treeApi = {}; @@ -201,11 +201,23 @@ function NavigationController($scope, $rootScope, $location, $log, $q, $routePar if (args.key === "showSearchResults") { $scope.showSearchResults = args.value; } + + $scope.authenticated = true; + + //load languages if doc types allow variations + if ($scope.currentSection === "content") { + contentTypeHelper.allowsVariation().then(function (b) { + if (b === "true") { + //load languages if there are more than 1 + loadLanguages(); + } + }); + } })); // Listen for language updates - evts.push(eventsService.on("editors.languages.languageDeleted", function(e, args) { - languageResource.getAll().then(function(languages) { + evts.push(eventsService.on("editors.languages.languageDeleted", function (e, args) { + languageResource.getAll().then(function (languages) { $scope.languages = languages; }); })); @@ -231,11 +243,12 @@ function NavigationController($scope, $rootScope, $location, $log, $q, $routePar })); //when the application is ready and the user is authorized setup the data - evts.push(eventsService.on("app.ready", function(evt, data) { - $scope.authenticated = true; - - // load languages - languageResource.getAll().then(function(languages) { + evts.push(eventsService.on("app.ready", function (evt, data) { + })); + + function loadLanguages() { + languageResource.getAll().then(function (languages) { + $scope.languages = languages; $scope.languages = languages; if ($scope.languages.length > 1) { @@ -250,7 +263,7 @@ function NavigationController($scope, $rootScope, $location, $log, $q, $routePar init(); }); - })); + } function init() { //select the current language if set in the query string @@ -281,7 +294,6 @@ function NavigationController($scope, $rootScope, $location, $log, $q, $routePar } } - function nodeExpandedHandler(args) { //store the reference to the expanded node path if (args.node) { @@ -289,7 +301,7 @@ function NavigationController($scope, $rootScope, $location, $log, $q, $routePar } } - $scope.selectLanguage = function(language) { + $scope.selectLanguage = function (language) { $location.search("mculture", language.culture); @@ -322,7 +334,7 @@ function NavigationController($scope, $rootScope, $location, $log, $q, $routePar angularHelper.executeSequentialPromises(promises); }); }); - + }; //this reacts to the options item in the tree diff --git a/src/Umbraco.Web/Editors/ContentTypeController.cs b/src/Umbraco.Web/Editors/ContentTypeController.cs index 5ffe68afaa..04065e82ce 100644 --- a/src/Umbraco.Web/Editors/ContentTypeController.cs +++ b/src/Umbraco.Web/Editors/ContentTypeController.cs @@ -14,6 +14,7 @@ using Umbraco.Web.WebApi; using Umbraco.Web.WebApi.Filters; using Umbraco.Core.Logging; using Umbraco.Web.Composing; +using ContentVariation = Umbraco.Core.Models.ContentVariation; namespace Umbraco.Web.Editors { @@ -34,6 +35,12 @@ namespace Umbraco.Web.Editors { return Services.ContentTypeService.Count(); } + [HttpGet] + public bool AllowsVariation() + { + var contentTypes = Services.ContentTypeService.GetAll(); + return contentTypes.Any(contentType => contentType.Variations.HasFlag(ContentVariation.CultureNeutral)); + } public DocumentTypeDisplay GetById(int id) { @@ -169,17 +176,17 @@ namespace Umbraco.Web.Editors } public DocumentTypeDisplay PostSave(DocumentTypeSave contentTypeSave) - { - //Before we send this model into this saving/mapping pipeline, we need to do some cleanup on variations. - //If the doc type does not allow content variations, we need to update all of it's property types to not allow this either - //else we may end up with ysods. I'm unsure if the service level handles this but we'll make sure it is updated here - if (!contentTypeSave.AllowCultureVariant) - { - foreach(var prop in contentTypeSave.Groups.SelectMany(x => x.Properties)) - { - prop.AllowCultureVariant = false; - } - } + { + //Before we send this model into this saving/mapping pipeline, we need to do some cleanup on variations. + //If the doc type does not allow content variations, we need to update all of it's property types to not allow this either + //else we may end up with ysods. I'm unsure if the service level handles this but we'll make sure it is updated here + if (!contentTypeSave.AllowCultureVariant) + { + foreach(var prop in contentTypeSave.Groups.SelectMany(x => x.Properties)) + { + prop.AllowCultureVariant = false; + } + } var savedCt = PerformPostSave( contentTypeSave: contentTypeSave, From b5ec7758338a29f1a4f92a91cd92bd0df6dc5b55 Mon Sep 17 00:00:00 2001 From: Robert Date: Thu, 3 May 2018 10:35:23 +0200 Subject: [PATCH 2/8] Removed duplicate code and fixed bug where dropdown would not go away when there were no document types that allowed variations --- .../src/controllers/navigation.controller.js | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/Umbraco.Web.UI.Client/src/controllers/navigation.controller.js b/src/Umbraco.Web.UI.Client/src/controllers/navigation.controller.js index 07fd546a25..926489ac2a 100644 --- a/src/Umbraco.Web.UI.Client/src/controllers/navigation.controller.js +++ b/src/Umbraco.Web.UI.Client/src/controllers/navigation.controller.js @@ -210,7 +210,11 @@ function NavigationController($scope, $rootScope, $location, $log, $q, $routePar if (b === "true") { //load languages if there are more than 1 loadLanguages(); + } else { + $scope.languages = []; + init(); } + }); } })); @@ -249,7 +253,6 @@ function NavigationController($scope, $rootScope, $location, $log, $q, $routePar function loadLanguages() { languageResource.getAll().then(function (languages) { $scope.languages = languages; - $scope.languages = languages; if ($scope.languages.length > 1) { var defaultLang = _.find($scope.languages, function (l) { From 8a9caad23d8a55eddb1d54a33359933b41203c20 Mon Sep 17 00:00:00 2001 From: Robert Date: Thu, 3 May 2018 13:14:19 +0200 Subject: [PATCH 3/8] Small fix to editors that had no config values defined. --- src/Umbraco.Core/PropertyEditors/ConfigurationEditor.cs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/Umbraco.Core/PropertyEditors/ConfigurationEditor.cs b/src/Umbraco.Core/PropertyEditors/ConfigurationEditor.cs index 58fde70467..e13419f0d6 100644 --- a/src/Umbraco.Core/PropertyEditors/ConfigurationEditor.cs +++ b/src/Umbraco.Core/PropertyEditors/ConfigurationEditor.cs @@ -73,7 +73,10 @@ namespace Umbraco.Core.PropertyEditors // but only keep entries that have a non-null/empty value // rest will fall back to default during ToConfigurationEditor() - var keys = editorValues.Where(x => x.Value == null || x.Value is string stringValue && string.IsNullOrWhiteSpace(stringValue)).Select(x => x.Key); + var keys = editorValues.Where(x => + x.Value == null || x.Value is string stringValue && string.IsNullOrWhiteSpace(stringValue)) + .Select(x => x.Key).ToList(); + foreach (var key in keys) editorValues.Remove(key); return editorValues; From 9ac7df82ad5913b973933751920ad964963ba2c6 Mon Sep 17 00:00:00 2001 From: Claus Date: Tue, 8 May 2018 08:46:48 +0200 Subject: [PATCH 4/8] fixing typo in packages tree. --- src/Umbraco.Core/Constants-Applications.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Umbraco.Core/Constants-Applications.cs b/src/Umbraco.Core/Constants-Applications.cs index 7d8476989a..b23efd6bb8 100644 --- a/src/Umbraco.Core/Constants-Applications.cs +++ b/src/Umbraco.Core/Constants-Applications.cs @@ -86,7 +86,7 @@ /// /// alias for the packages tree /// - public const string Packages = "packager"; + public const string Packages = "packages"; /// /// alias for the dictionary tree. From d1191c069304958eba4956b0da79167e64d68e68 Mon Sep 17 00:00:00 2001 From: Claus Date: Tue, 8 May 2018 08:49:09 +0200 Subject: [PATCH 5/8] temporarily removing the packages tree - known issue it's not working. --- .../Trees/PackagesTreeController.cs | 182 +++++++++--------- 1 file changed, 91 insertions(+), 91 deletions(-) diff --git a/src/Umbraco.Web/Trees/PackagesTreeController.cs b/src/Umbraco.Web/Trees/PackagesTreeController.cs index ce95cf4ee0..5553ad00b2 100644 --- a/src/Umbraco.Web/Trees/PackagesTreeController.cs +++ b/src/Umbraco.Web/Trees/PackagesTreeController.cs @@ -1,108 +1,108 @@ -using System; -using System.Linq; -using System.Net.Http.Formatting; -using Umbraco.Web.Models.Trees; -using Umbraco.Web.Mvc; -using Umbraco.Web.WebApi.Filters; -using umbraco; -using umbraco.cms.businesslogic.packager; -using Umbraco.Core.Services; -using Umbraco.Web._Legacy.Actions; -using Constants = Umbraco.Core.Constants; +//using System; +//using System.Linq; +//using System.Net.Http.Formatting; +//using Umbraco.Web.Models.Trees; +//using Umbraco.Web.Mvc; +//using Umbraco.Web.WebApi.Filters; +//using umbraco; +//using umbraco.cms.businesslogic.packager; +//using Umbraco.Core.Services; +//using Umbraco.Web._Legacy.Actions; +//using Constants = Umbraco.Core.Constants; -namespace Umbraco.Web.Trees -{ - [UmbracoTreeAuthorize(Constants.Trees.Packages)] - [Tree(Constants.Applications.Developer, Constants.Trees.Packages, null, sortOrder: 0)] - [PluginController("UmbracoTrees")] - [CoreTree] - public class PackagesTreeController : TreeController - { - /// - /// Helper method to create a root model for a tree - /// - /// - protected override TreeNode CreateRootNode(FormDataCollection queryStrings) - { - var root = base.CreateRootNode(queryStrings); +//namespace Umbraco.Web.Trees +//{ +// [UmbracoTreeAuthorize(Constants.Trees.Packages)] +// [Tree(Constants.Applications.Developer, Constants.Trees.Packages, null, sortOrder: 0)] +// [PluginController("UmbracoTrees")] +// [CoreTree] +// public class PackagesTreeController : TreeController +// { +// /// +// /// Helper method to create a root model for a tree +// /// +// /// +// protected override TreeNode CreateRootNode(FormDataCollection queryStrings) +// { +// var root = base.CreateRootNode(queryStrings); - //this will load in a custom UI instead of the dashboard for the root node - root.RoutePath = string.Format("{0}/{1}/{2}", Constants.Applications.Developer, Constants.Trees.Packages, "overview"); - root.Icon = "icon-box"; +// //this will load in a custom UI instead of the dashboard for the root node +// root.RoutePath = string.Format("{0}/{1}/{2}", Constants.Applications.Developer, Constants.Trees.Packages, "overview"); +// root.Icon = "icon-box"; - return root; - } +// return root; +// } - protected override TreeNodeCollection GetTreeNodes(string id, FormDataCollection queryStrings) - { - var nodes = new TreeNodeCollection(); +// protected override TreeNodeCollection GetTreeNodes(string id, FormDataCollection queryStrings) +// { +// var nodes = new TreeNodeCollection(); - var createdPackages = CreatedPackage.GetAllCreatedPackages(); +// var createdPackages = CreatedPackage.GetAllCreatedPackages(); - if (id == "created") - { - nodes.AddRange( - createdPackages - .OrderBy(entity => entity.Data.Name) - .Select(dt => - { - var node = CreateTreeNode(dt.Data.Id.ToString(), id, queryStrings, dt.Data.Name, "icon-inbox", false, - string.Format("/{0}/framed/{1}", - queryStrings.GetValue("application"), - Uri.EscapeDataString("developer/Packages/EditPackage.aspx?id=" + dt.Data.Id))); - return node; - })); - } - else - { - //must be root - var node = CreateTreeNode( - "created", - id, - queryStrings, - Services.TextService.Localize("treeHeaders/createdPackages"), - "icon-folder", - createdPackages.Count > 0, - string.Empty); +// if (id == "created") +// { +// nodes.AddRange( +// createdPackages +// .OrderBy(entity => entity.Data.Name) +// .Select(dt => +// { +// var node = CreateTreeNode(dt.Data.Id.ToString(), id, queryStrings, dt.Data.Name, "icon-inbox", false, +// string.Format("/{0}/framed/{1}", +// queryStrings.GetValue("application"), +// Uri.EscapeDataString("developer/Packages/EditPackage.aspx?id=" + dt.Data.Id))); +// return node; +// })); +// } +// else +// { +// //must be root +// var node = CreateTreeNode( +// "created", +// id, +// queryStrings, +// Services.TextService.Localize("treeHeaders/createdPackages"), +// "icon-folder", +// createdPackages.Count > 0, +// string.Empty); - //TODO: This isn't the best way to ensure a noop process for clicking a node but it works for now. - node.AdditionalData["jsClickCallback"] = "javascript:void(0);"; +// //TODO: This isn't the best way to ensure a noop process for clicking a node but it works for now. +// node.AdditionalData["jsClickCallback"] = "javascript:void(0);"; - nodes.Add(node); - } +// nodes.Add(node); +// } - return nodes; - } +// return nodes; +// } - protected override MenuItemCollection GetMenuForNode(string id, FormDataCollection queryStrings) - { - var menu = new MenuItemCollection(); +// protected override MenuItemCollection GetMenuForNode(string id, FormDataCollection queryStrings) +// { +// var menu = new MenuItemCollection(); - // Root actions - if (id == "-1") - { - menu.Items.Add(Services.TextService.Localize(string.Format("actions/{0}", ActionNew.Instance.Alias))) - .ConvertLegacyMenuItem(null, Constants.Trees.Packages, queryStrings.GetValue("application")); - } - else if (id == "created") - { - menu.Items.Add(Services.TextService.Localize(string.Format("actions/{0}", ActionNew.Instance.Alias))) - .ConvertLegacyMenuItem(null, Constants.Trees.Packages, queryStrings.GetValue("application")); +// // Root actions +// if (id == "-1") +// { +// menu.Items.Add(Services.TextService.Localize(string.Format("actions/{0}", ActionNew.Instance.Alias))) +// .ConvertLegacyMenuItem(null, Constants.Trees.Packages, queryStrings.GetValue("application")); +// } +// else if (id == "created") +// { +// menu.Items.Add(Services.TextService.Localize(string.Format("actions/{0}", ActionNew.Instance.Alias))) +// .ConvertLegacyMenuItem(null, Constants.Trees.Packages, queryStrings.GetValue("application")); - menu.Items.Add( - Services.TextService.Localize(string.Format("actions/{0}", ActionRefresh.Instance.Alias)), true); - } - else - { - //it's a package node - menu.Items.Add(Services.TextService.Localize("actions", ActionDelete.Instance.Alias)); - } +// menu.Items.Add( +// Services.TextService.Localize(string.Format("actions/{0}", ActionRefresh.Instance.Alias)), true); +// } +// else +// { +// //it's a package node +// menu.Items.Add(Services.TextService.Localize("actions", ActionDelete.Instance.Alias)); +// } - return menu; - } - } -} +// return menu; +// } +// } +//} From 216aaec7f2a8f5d86caf55959c9f3f1681817715 Mon Sep 17 00:00:00 2001 From: Robert Date: Tue, 8 May 2018 10:00:28 +0200 Subject: [PATCH 6/8] Removed unneeded test --- .../Routing/DomainsAndCulturesTests.cs | 42 ------------------- 1 file changed, 42 deletions(-) diff --git a/src/Umbraco.Tests/Routing/DomainsAndCulturesTests.cs b/src/Umbraco.Tests/Routing/DomainsAndCulturesTests.cs index 83b28ace25..a6f2b9b5ec 100644 --- a/src/Umbraco.Tests/Routing/DomainsAndCulturesTests.cs +++ b/src/Umbraco.Tests/Routing/DomainsAndCulturesTests.cs @@ -3,7 +3,6 @@ using Moq; using NUnit.Framework; using Umbraco.Core.Models; using Umbraco.Tests.TestHelpers; -using Umbraco.Tests.Testing.Objects.Accessors; using Umbraco.Web.Routing; namespace Umbraco.Tests.Routing @@ -337,46 +336,5 @@ namespace Umbraco.Tests.Routing Assert.AreEqual(expectedCulture, frequest.Culture.Name); Assert.AreEqual(frequest.PublishedContent.Id, expectedNode); } - - - - - [Test] - public void WithDefaultCulture() - { - SetupDomainServiceMock(new[] - { - new UmbracoDomain("localhost:9000/en") - { - Id = 1, - LanguageId = LangEngId, - RootContentId = 10011, - LanguageIsoCode = "en-US" - }, - new UmbracoDomain("localhost:9000/fr") - { - Id = 1, - LanguageId = LangFrId, - RootContentId = 10012, - LanguageIsoCode = "fr-FR" - } - }); - - var requestUrl = "http://localhost:9000/fr/1001-2-2"; - - var defaultCultureAccessor = (TestDefaultCultureAccessor) DefaultCultureAccessor; - defaultCultureAccessor.DefaultCulture = "en-US"; - - var globalSettings = Mock.Get(TestObjects.GetGlobalSettings()); //this will modify the IGlobalSettings instance stored in the container - globalSettings.Setup(x => x.HideTopLevelNodeFromPath).Returns(false); - SettingsForTests.ConfigureSettings(globalSettings.Object); - - var umbracoContext = GetUmbracoContext(requestUrl, globalSettings:globalSettings.Object); - var publishedRouter = CreatePublishedRouter(Container); - var publishedRequest = publishedRouter.CreateRequest(umbracoContext); - - var domain = publishedRouter.FindDomain(publishedRequest); - Assert.AreEqual("fr-FR", publishedRequest.Culture.Name); - } } } From 70e4ea55023488553055d1f5e18ddfa1a18707c1 Mon Sep 17 00:00:00 2001 From: Robert Date: Tue, 8 May 2018 10:46:09 +0200 Subject: [PATCH 7/8] Moved authenticated flag back to "app.ready" listener --- .../src/controllers/navigation.controller.js | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/Umbraco.Web.UI.Client/src/controllers/navigation.controller.js b/src/Umbraco.Web.UI.Client/src/controllers/navigation.controller.js index 926489ac2a..da0d26cd33 100644 --- a/src/Umbraco.Web.UI.Client/src/controllers/navigation.controller.js +++ b/src/Umbraco.Web.UI.Client/src/controllers/navigation.controller.js @@ -202,8 +202,6 @@ function NavigationController($scope, $rootScope, $location, $log, $q, $routePar $scope.showSearchResults = args.value; } - $scope.authenticated = true; - //load languages if doc types allow variations if ($scope.currentSection === "content") { contentTypeHelper.allowsVariation().then(function (b) { @@ -248,6 +246,7 @@ function NavigationController($scope, $rootScope, $location, $log, $q, $routePar //when the application is ready and the user is authorized setup the data evts.push(eventsService.on("app.ready", function (evt, data) { + $scope.authenticated = true; })); function loadLanguages() { From f3e509ad554484667853354c942759dafc73558b Mon Sep 17 00:00:00 2001 From: Robert Date: Tue, 8 May 2018 12:13:42 +0200 Subject: [PATCH 8/8] Removes vertical and horizontal scroll bars on content tree language picker, updates languageCreated and languageDeleted event listeners to check for variant doctypes before populating the language list --- .../src/controllers/navigation.controller.js | 20 +++++++++++++++++-- .../application/umb-language-picker.less | 4 ++-- 2 files changed, 20 insertions(+), 4 deletions(-) diff --git a/src/Umbraco.Web.UI.Client/src/controllers/navigation.controller.js b/src/Umbraco.Web.UI.Client/src/controllers/navigation.controller.js index da0d26cd33..f5be96304f 100644 --- a/src/Umbraco.Web.UI.Client/src/controllers/navigation.controller.js +++ b/src/Umbraco.Web.UI.Client/src/controllers/navigation.controller.js @@ -220,13 +220,29 @@ function NavigationController($scope, $rootScope, $location, $log, $q, $routePar // Listen for language updates evts.push(eventsService.on("editors.languages.languageDeleted", function (e, args) { languageResource.getAll().then(function (languages) { - $scope.languages = languages; + contentTypeHelper.allowsVariation().then(function (b) { + + if (b === "true") { + $scope.languages = languages; + } else { + $scope.languages = []; + } + + }); }); })); evts.push(eventsService.on("editors.languages.languageCreated", function(e, args) { languageResource.getAll().then(function(languages) { - $scope.languages = languages; + contentTypeHelper.allowsVariation().then(function (b) { + + if (b === "true") { + $scope.languages = languages; + } else { + $scope.languages = []; + } + + }); }); })); diff --git a/src/Umbraco.Web.UI.Client/src/less/components/application/umb-language-picker.less b/src/Umbraco.Web.UI.Client/src/less/components/application/umb-language-picker.less index 81eb3ab59d..5cf9ca21b3 100644 --- a/src/Umbraco.Web.UI.Client/src/less/components/application/umb-language-picker.less +++ b/src/Umbraco.Web.UI.Client/src/less/components/application/umb-language-picker.less @@ -31,7 +31,7 @@ position: absolute; border-radius: 0 0 3px 3px; max-height: 200px; - overflow: scroll; + overflow: auto; } .umb-language-picker__dropdown a { @@ -45,4 +45,4 @@ .umb-language-picker__dropdown a:focus { background: @gray-10; text-decoration: none; -} \ No newline at end of file +}