Merge remote-tracking branch 'origin/temp8' into temp8-U4-11282

# Conflicts:
#	src/Umbraco.Tests/Routing/DomainsAndCulturesTests.cs
#	src/Umbraco.Web.UI.Client/src/controllers/navigation.controller.js
This commit is contained in:
Shannon
2018-05-10 18:55:39 +10:00
9 changed files with 161 additions and 151 deletions

View File

@@ -86,7 +86,7 @@
/// <summary>
/// alias for the packages tree
/// </summary>
public const string Packages = "packager";
public const string Packages = "packages";
/// <summary>
/// alias for the dictionary tree.

View File

@@ -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;

View File

@@ -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);
}
}
}

View File

@@ -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(

View File

@@ -7,6 +7,10 @@ function contentTypeHelper(contentTypeResource, dataTypeResource, $filter, $inje
var contentTypeHelperService = {
allowsVariation: function() {
return contentTypeResource.allowsVariation();
},
createIdArray: function(array) {
var newArray = [];

View File

@@ -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) {

View File

@@ -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;
}
}

View File

@@ -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<DocumentTypeDisplay, DocumentTypeSave, PropertyTypeBasic>(
contentTypeSave: contentTypeSave,

View File

@@ -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
{
/// <summary>
/// Helper method to create a root model for a tree
/// </summary>
/// <returns></returns>
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
// {
// /// <summary>
// /// Helper method to create a root model for a tree
// /// </summary>
// /// <returns></returns>
// 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<string>("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<string>("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<ActionNew>(Services.TextService.Localize(string.Format("actions/{0}", ActionNew.Instance.Alias)))
.ConvertLegacyMenuItem(null, Constants.Trees.Packages, queryStrings.GetValue<string>("application"));
}
else if (id == "created")
{
menu.Items.Add<ActionNew>(Services.TextService.Localize(string.Format("actions/{0}", ActionNew.Instance.Alias)))
.ConvertLegacyMenuItem(null, Constants.Trees.Packages, queryStrings.GetValue<string>("application"));
// // Root actions
// if (id == "-1")
// {
// menu.Items.Add<ActionNew>(Services.TextService.Localize(string.Format("actions/{0}", ActionNew.Instance.Alias)))
// .ConvertLegacyMenuItem(null, Constants.Trees.Packages, queryStrings.GetValue<string>("application"));
// }
// else if (id == "created")
// {
// menu.Items.Add<ActionNew>(Services.TextService.Localize(string.Format("actions/{0}", ActionNew.Instance.Alias)))
// .ConvertLegacyMenuItem(null, Constants.Trees.Packages, queryStrings.GetValue<string>("application"));
menu.Items.Add<RefreshNode, ActionRefresh>(
Services.TextService.Localize(string.Format("actions/{0}", ActionRefresh.Instance.Alias)), true);
}
else
{
//it's a package node
menu.Items.Add<ActionDelete>(Services.TextService.Localize("actions", ActionDelete.Instance.Alias));
}
// menu.Items.Add<RefreshNode, ActionRefresh>(
// Services.TextService.Localize(string.Format("actions/{0}", ActionRefresh.Instance.Alias)), true);
// }
// else
// {
// //it's a package node
// menu.Items.Add<ActionDelete>(Services.TextService.Localize("actions", ActionDelete.Instance.Alias));
// }
return menu;
}
}
}
// return menu;
// }
// }
//}