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. 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; diff --git a/src/Umbraco.Tests/Routing/DomainsAndCulturesTests.cs b/src/Umbraco.Tests/Routing/DomainsAndCulturesTests.cs index 9139b28528..75327dcdfd 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,7 +336,6 @@ namespace Umbraco.Tests.Routing Assert.AreEqual(expectedCulture, frequest.Culture.Name); Assert.AreEqual(frequest.PublishedContent.Id, expectedNode); } - // domains such as "/en" are natively supported, and when instanciating // DomainAndUri for them, the host will come from the current request // @@ -375,7 +373,6 @@ namespace Umbraco.Tests.Routing 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(inputUrl, globalSettings:globalSettings.Object); var publishedRouter = CreatePublishedRouter(Container); var frequest = publishedRouter.CreateRequest(umbracoContext); @@ -392,43 +389,5 @@ namespace Umbraco.Tests.Routing Assert.IsTrue(result); 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); - } } } 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 758471061d..d44ef023ec 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) { //this is used to trigger the tree to start loading once everything is ready var treeInitPromise = $q.defer(); @@ -209,18 +209,47 @@ function NavigationController($scope, $rootScope, $location, $log, $q, $routePar $scope.showSearchResults = args.value; } + //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(); + } else { + $scope.languages = []; + init(); + } + + }); + } })); // 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 = []; + } + + }); }); })); @@ -359,7 +388,6 @@ function NavigationController($scope, $rootScope, $location, $log, $q, $routePar }); }); } - function nodeExpandedHandler(args) { //store the reference to the expanded node path if (args.node) { 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 +} 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, 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; +// } +// } +//}