From a9450f9ed9d00ecef9b33043898e2f8211dac824 Mon Sep 17 00:00:00 2001 From: Bjarke Berg Date: Fri, 22 Feb 2019 11:02:37 +0100 Subject: [PATCH 01/29] Fix NullReferenceException when using LocalDb, because `SqlServerSyntaxProvider.ServerVersion` can be `null` --- src/Umbraco.Web/Install/InstallHelper.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Umbraco.Web/Install/InstallHelper.cs b/src/Umbraco.Web/Install/InstallHelper.cs index effb46c9b7..42da49aa39 100644 --- a/src/Umbraco.Web/Install/InstallHelper.cs +++ b/src/Umbraco.Web/Install/InstallHelper.cs @@ -101,7 +101,7 @@ namespace Umbraco.Web.Install if (syntax is SqlCeSyntaxProvider) dbProvider = "SqlServerCE"; else if (syntax is SqlServerSyntaxProvider) - dbProvider = (syntax as SqlServerSyntaxProvider).ServerVersion.IsAzure ? "SqlAzure" : "SqlServer"; + dbProvider = (syntax as SqlServerSyntaxProvider).ServerVersion?.IsAzure == true ? "SqlAzure" : "SqlServer"; return dbProvider; } From 064f637006f2053e51f2ca8ed3ebd084b89642f3 Mon Sep 17 00:00:00 2001 From: Bjarke Berg Date: Fri, 22 Feb 2019 11:23:57 +0100 Subject: [PATCH 02/29] #4708 - Fix for YSOD when exiting preview with on invariant cultures --- .../src/preview/preview.controller.js | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/Umbraco.Web.UI.Client/src/preview/preview.controller.js b/src/Umbraco.Web.UI.Client/src/preview/preview.controller.js index 7d6584d2f1..4733c58556 100644 --- a/src/Umbraco.Web.UI.Client/src/preview/preview.controller.js +++ b/src/Umbraco.Web.UI.Client/src/preview/preview.controller.js @@ -113,7 +113,12 @@ var app = angular.module("umbraco.preview", ['umbraco.resources', 'umbraco.servi $scope.exitPreview = function () { var culture = $location.search().culture || getParameterByName("culture"); - var relativeUrl = "/" + $scope.pageId +'?culture='+ culture; + var relativeUrl = "/" + $scope.pageId; + + if(culture){ + relativeUrl +='?culture='+ culture; + } + window.top.location.href = "../preview/end?redir=" + encodeURIComponent(relativeUrl); }; From 02122f5e038eb895d715ec8e2b35ed49d600d751 Mon Sep 17 00:00:00 2001 From: Bjarke Berg Date: Fri, 22 Feb 2019 14:27:54 +0100 Subject: [PATCH 03/29] Revert "Fix NullReferenceException when using LocalDb, because `SqlServerSyntaxProvider.ServerVersion` can be `null`" This reverts commit a9450f9e. Root cause is fixed --- src/Umbraco.Web/Install/InstallHelper.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Umbraco.Web/Install/InstallHelper.cs b/src/Umbraco.Web/Install/InstallHelper.cs index 42da49aa39..effb46c9b7 100644 --- a/src/Umbraco.Web/Install/InstallHelper.cs +++ b/src/Umbraco.Web/Install/InstallHelper.cs @@ -101,7 +101,7 @@ namespace Umbraco.Web.Install if (syntax is SqlCeSyntaxProvider) dbProvider = "SqlServerCE"; else if (syntax is SqlServerSyntaxProvider) - dbProvider = (syntax as SqlServerSyntaxProvider).ServerVersion?.IsAzure == true ? "SqlAzure" : "SqlServer"; + dbProvider = (syntax as SqlServerSyntaxProvider).ServerVersion.IsAzure ? "SqlAzure" : "SqlServer"; return dbProvider; } From a43f8c4cbd779058324cdf74cc217f0fdc02e44b Mon Sep 17 00:00:00 2001 From: Bjarke Berg Date: Mon, 4 Mar 2019 14:31:45 +0100 Subject: [PATCH 04/29] Bugfix: https://github.com/umbraco/Umbraco-CMS/issues/4827 - Fixed MediaPickerValueConverter when config is Only Images --- .../MediaPickerValueConverter.cs | 58 +++++++++++++------ 1 file changed, 39 insertions(+), 19 deletions(-) diff --git a/src/Umbraco.Web/PropertyEditors/ValueConverters/MediaPickerValueConverter.cs b/src/Umbraco.Web/PropertyEditors/ValueConverters/MediaPickerValueConverter.cs index 802f42ed9e..fb3134c9a3 100644 --- a/src/Umbraco.Web/PropertyEditors/ValueConverters/MediaPickerValueConverter.cs +++ b/src/Umbraco.Web/PropertyEditors/ValueConverters/MediaPickerValueConverter.cs @@ -1,4 +1,5 @@ using System; +using System.Collections; using System.Collections.Generic; using System.Linq; using Umbraco.Core; @@ -14,11 +15,18 @@ namespace Umbraco.Web.PropertyEditors.ValueConverters [DefaultPropertyValueConverter] public class MediaPickerValueConverter : PropertyValueConverterBase { + // hard-coding "image" here but that's how it works at UI level too + private const string ImageTypeAlias = "image"; + + private readonly IPublishedModelFactory _publishedModelFactory; private readonly IPublishedSnapshotAccessor _publishedSnapshotAccessor; - public MediaPickerValueConverter(IPublishedSnapshotAccessor publishedSnapshotAccessor) + public MediaPickerValueConverter(IPublishedSnapshotAccessor publishedSnapshotAccessor, + IPublishedModelFactory publishedModelFactory) { - _publishedSnapshotAccessor = publishedSnapshotAccessor ?? throw new ArgumentNullException(nameof(publishedSnapshotAccessor)); + _publishedSnapshotAccessor = publishedSnapshotAccessor ?? + throw new ArgumentNullException(nameof(publishedSnapshotAccessor)); + _publishedModelFactory = publishedModelFactory; } public override bool IsConverter(PublishedPropertyType propertyType) @@ -31,15 +39,19 @@ namespace Umbraco.Web.PropertyEditors.ValueConverters var isMultiple = IsMultipleDataType(propertyType.DataType); var isOnlyImages = IsOnlyImagesDataType(propertyType.DataType); - // hard-coding "image" here but that's how it works at UI level too - return isMultiple - ? (isOnlyImages ? typeof(IEnumerable<>).MakeGenericType(ModelType.For("image")) : typeof(IEnumerable)) - : (isOnlyImages ? ModelType.For("image") : typeof(IPublishedContent)); + ? isOnlyImages + ? typeof(IEnumerable<>).MakeGenericType(ModelType.For(ImageTypeAlias)) + : typeof(IEnumerable) + : isOnlyImages + ? ModelType.For(ImageTypeAlias) + : typeof(IPublishedContent); } public override PropertyCacheLevel GetPropertyCacheLevel(PublishedPropertyType propertyType) - => PropertyCacheLevel.Snapshot; + { + return PropertyCacheLevel.Snapshot; + } private bool IsMultipleDataType(PublishedDataType dataType) { @@ -53,26 +65,31 @@ namespace Umbraco.Web.PropertyEditors.ValueConverters return config.OnlyImages; } - public override object ConvertSourceToIntermediate(IPublishedElement owner, PublishedPropertyType propertyType, object source, bool preview) + public override object ConvertSourceToIntermediate(IPublishedElement owner, PublishedPropertyType propertyType, + object source, bool preview) { if (source == null) return null; var nodeIds = source.ToString() - .Split(new[] { "," }, StringSplitOptions.RemoveEmptyEntries) + .Split(new[] {","}, StringSplitOptions.RemoveEmptyEntries) .Select(Udi.Parse) .ToArray(); return nodeIds; } - public override object ConvertIntermediateToObject(IPublishedElement owner, PublishedPropertyType propertyType, PropertyCacheLevel cacheLevel, object source, bool preview) + public override object ConvertIntermediateToObject(IPublishedElement owner, PublishedPropertyType propertyType, + PropertyCacheLevel cacheLevel, object source, bool preview) { - if (source == null) - { - return null; - } + var isMultiple = IsMultipleDataType(propertyType.DataType); + var isOnlyImages = IsOnlyImagesDataType(propertyType.DataType); + + var udis = (Udi[]) source; + var mediaItems = isOnlyImages + ? _publishedModelFactory.CreateModelList(ImageTypeAlias) + : new List(); + + if (source == null) return isMultiple ? mediaItems : null; - var udis = (Udi[])source; - var mediaItems = new List(); if (udis.Any()) { foreach (var udi in udis) @@ -84,12 +101,15 @@ namespace Umbraco.Web.PropertyEditors.ValueConverters mediaItems.Add(item); } - if (IsMultipleDataType(propertyType.DataType)) - return mediaItems; - return mediaItems.FirstOrDefault(); + return isMultiple ? mediaItems : FirstOrDefault(mediaItems); } return source; } + + private object FirstOrDefault(IList mediaItems) + { + return mediaItems.Count == 0 ? null : mediaItems[0]; + } } } From b406835c9c40d24c488352b16425c82896f616ee Mon Sep 17 00:00:00 2001 From: Bjarke Berg Date: Wed, 6 Mar 2019 10:08:15 +0100 Subject: [PATCH 05/29] Code styling --- .../ValueConverters/MediaPickerValueConverter.cs | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/src/Umbraco.Web/PropertyEditors/ValueConverters/MediaPickerValueConverter.cs b/src/Umbraco.Web/PropertyEditors/ValueConverters/MediaPickerValueConverter.cs index fb3134c9a3..0218867bb4 100644 --- a/src/Umbraco.Web/PropertyEditors/ValueConverters/MediaPickerValueConverter.cs +++ b/src/Umbraco.Web/PropertyEditors/ValueConverters/MediaPickerValueConverter.cs @@ -49,9 +49,7 @@ namespace Umbraco.Web.PropertyEditors.ValueConverters } public override PropertyCacheLevel GetPropertyCacheLevel(PublishedPropertyType propertyType) - { - return PropertyCacheLevel.Snapshot; - } + => PropertyCacheLevel.Snapshot; private bool IsMultipleDataType(PublishedDataType dataType) { @@ -71,7 +69,7 @@ namespace Umbraco.Web.PropertyEditors.ValueConverters if (source == null) return null; var nodeIds = source.ToString() - .Split(new[] {","}, StringSplitOptions.RemoveEmptyEntries) + .Split(new[] { "," }, StringSplitOptions.RemoveEmptyEntries) .Select(Udi.Parse) .ToArray(); return nodeIds; From 444497be7caf8bf1c305aab1e11365a909235f37 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Niels=20Lyngs=C3=B8?= Date: Wed, 6 Mar 2019 14:42:31 +0100 Subject: [PATCH 06/29] For Save & Publish overlay: + Publish multiple variants for new nodes. + Auto selects mandatory languages. + Auto selects languages that has changes. + Provides feedback if missing nodeName on variant that isn't open. + Highlights "mandatory language"-description if variant isn't selected. --- .../components/content/edit.controller.js | 31 ++++++- .../content/overlays/publish.controller.js | 90 +++++++++++++------ .../src/views/content/overlays/publish.html | 14 ++- .../Umbraco/config/lang/en_us.xml | 3 + 4 files changed, 104 insertions(+), 34 deletions(-) diff --git a/src/Umbraco.Web.UI.Client/src/common/directives/components/content/edit.controller.js b/src/Umbraco.Web.UI.Client/src/common/directives/components/content/edit.controller.js index e5b0dbf201..3d2b1ac124 100644 --- a/src/Umbraco.Web.UI.Client/src/common/directives/components/content/edit.controller.js +++ b/src/Umbraco.Web.UI.Client/src/common/directives/components/content/edit.controller.js @@ -331,8 +331,35 @@ // This is a helper method to reduce the amount of code repitition for actions: Save, Publish, SendToPublish function performSave(args) { - - + + // Check that all variants for publishing have a name. + if (args.action === "publish" || args.action === "sendToPublish") { + + if ($scope.content.variants) { + var iVariant; + for (var i = 0; i < $scope.content.variants.length; i++) { + iVariant = $scope.content.variants[i]; + + iVariant.notifications = [];// maybe not needed, need to investigate. + + if(iVariant.publish === true) { + if (iVariant.name == null) { + + localizationService.localize("publish_contentPublishedFailedByMissingName").then(function (value) { + iVariant.warnings = [{"message": value.replace("%0%", iVariant.language.name)}] + }); + + return $q(function(resolve, reject) { + reject(); + }); + } + } + } + } + + } + + //Used to check validility of nested form - coming from Content Apps mostly //Set them all to be invalid var fieldsToRollback = checkValidility(); diff --git a/src/Umbraco.Web.UI.Client/src/views/content/overlays/publish.controller.js b/src/Umbraco.Web.UI.Client/src/views/content/overlays/publish.controller.js index d6f6f67c55..7fc202e897 100644 --- a/src/Umbraco.Web.UI.Client/src/views/content/overlays/publish.controller.js +++ b/src/Umbraco.Web.UI.Client/src/views/content/overlays/publish.controller.js @@ -14,34 +14,51 @@ /** Returns true if publishing is possible based on if there are un-published mandatory languages */ function canPublish() { - var selected = []; + + var possible = false; for (var i = 0; i < vm.variants.length; i++) { var variant = vm.variants[i]; - - //if this variant will show up in the publish-able list - var publishable = dirtyVariantFilter(variant); - var published = !(variant.state === "NotCreated" || variant.state === "Draft"); - - if ((variant.language.isMandatory && !published) && (!publishable || !variant.publish)) { - //if a mandatory variant isn't published - //and it's not publishable or not selected to be published - //then we cannot continue - - // TODO: Show a message when this occurs + var state = canVariantPublish(variant); + if (state === true) { + possible = true; + } + if (state === false) { return false; } - - if (variant.publish) { - selected.push(variant.publish); - } } - return selected.length > 0; + return possible; + } + + /** Returns true if publishing is possible based on if the variant is a un-published mandatory language */ + function canVariantPublish(variant) { + + //if this variant will show up in the publish-able list + var publishable = dirtyVariantFilter(variant); + var published = !(variant.state === "NotCreated" || variant.state === "Draft"); + + // is this variant mandatory: + if (variant.language.isMandatory && !published && !variant.publish) { + //if a mandatory variant isn't published or set to be published + //then we cannot continue + + return false; + } + + // is this variant selected for publish: + if (variant.publish === true) { + return publishable; + } + + return null; } function changeSelection(variant) { + $scope.model.disableSubmitButton = !canPublish(); //need to set the Save state to true if publish is true variant.save = variant.publish; + + variant.willPublish = canVariantPublish(variant); } function dirtyVariantFilter(variant) { @@ -99,32 +116,50 @@ _.each(vm.variants, function (variant) { - if(variant.state !== "NotCreated"){ - vm.isNew = false; + if(variant.state === "NotCreated") { + vm.isNew = true; } - }); + } + ); _.each(vm.variants, function (variant) { + variant.compositeId = variant.language.culture + "_" + (variant.segment ? variant.segment : ""); variant.htmlId = "_content_variant_" + variant.compositeId; + + // reset to not be published + variant.publish = false; + variant.save = false; //check for pristine variants if (!vm.hasPristineVariants) { vm.hasPristineVariants = pristineVariantFilter(variant); } - - if(hasAnyData(variant)){ + + // If the variant havent been created jet. + if(variant.state === "NotCreated") { + // If the variant is mandatory, then set the variant to be published. + if (variant.language.isMandatory === true) { + variant.publish = true; + variant.save = true; + } + } + + variant.canPublish = dirtyVariantFilter(variant); + + // if we have data on this variant. + if(variant.canPublish && hasAnyData(variant)) { + // and if some varaints havent been saved before, or they dont have a publishing date set, then we set it for publishing. if(vm.isNew || variant.publishDate == null){ variant.publish = true; variant.save = true; } - }else{ - variant.publish = false; - variant.save = false; - variant.canSave = false; } - }); + + variant.willPublish = canVariantPublish(variant); + } + ); if (vm.variants.length !== 0) { //now sort it so that the current one is at the top @@ -153,7 +188,6 @@ localizationService.localize(labelKey).then(function (value) { vm.headline = value; - vm.loading = false; }); diff --git a/src/Umbraco.Web.UI.Client/src/views/content/overlays/publish.html b/src/Umbraco.Web.UI.Client/src/views/content/overlays/publish.html index fe626b8187..83de3a860a 100644 --- a/src/Umbraco.Web.UI.Client/src/views/content/overlays/publish.html +++ b/src/Umbraco.Web.UI.Client/src/views/content/overlays/publish.html @@ -10,7 +10,7 @@
-
+