From 97d20baecb07dbac6436b915333540dbc44d3995 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Niels=20Lyngs=C3=B8?= Date: Wed, 20 Jan 2021 15:30:41 +0100 Subject: [PATCH 01/70] skipValidation for content save --- .../components/content/edit.controller.js | 22 ++++++++++++------- .../services/contenteditinghelper.service.js | 19 ++++++++++------ 2 files changed, 26 insertions(+), 15 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 f2dc0622c7..ac470642e7 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 @@ -271,7 +271,7 @@ * @param {any} app the active content app */ function createButtons(content) { - + var isBlueprint = content.isBlueprint; if ($scope.page.isNew && $location.path().search(/contentBlueprints/i) !== -1) { @@ -456,7 +456,8 @@ create: $scope.page.isNew, action: args.action, showNotifications: args.showNotifications, - softRedirect: true + softRedirect: true, + skipValidation: args.skipValidation }).then(function (data) { //success init(); @@ -468,7 +469,9 @@ eventsService.emit("content.saved", { content: $scope.content, action: args.action }); - resetNestedFieldValiation(fieldsToRollback); + if($scope.contentForm.$invalid !== true) { + resetNestedFieldValiation(fieldsToRollback); + } ensureDirtyIsSetIfAnyVariantIsDirty(); return $q.when(data); @@ -476,7 +479,9 @@ function (err) { syncTreeNode($scope.content, $scope.content.path); - resetNestedFieldValiation(fieldsToRollback); + if($scope.contentForm.$invalid !== true) { + resetNestedFieldValiation(fieldsToRollback); + } return $q.reject(err); }); @@ -729,9 +734,9 @@ clearNotifications($scope.content); // TODO: Add "..." to save button label if there are more than one variant to publish - currently it just adds the elipses if there's more than 1 variant if (hasVariants($scope.content)) { - //before we launch the dialog we want to execute all client side validations first - if (formHelper.submitForm({ scope: $scope, action: "openSaveDialog" })) { + //before we launch the dialog we want to execute all client side validations first + if (formHelper.submitForm({ scope: $scope, action: "openSaveDialog", skipValidation:true, keepServerValidation:true })) { var dialog = { parentScope: $scope, view: "views/content/overlays/save.html", @@ -778,7 +783,8 @@ $scope.page.saveButtonState = "busy"; return performSave({ saveMethod: $scope.saveMethod(), - action: "save" + action: "save", + skipValidation: true }).then(function () { $scope.page.saveButtonState = "success"; }, function (err) { @@ -981,7 +987,7 @@ $scope.appChanged = function (activeApp) { $scope.activeApp = activeApp; - + _.forEach($scope.content.apps, function (app) { app.active = false; if (app.alias === $scope.activeApp.alias) { diff --git a/src/Umbraco.Web.UI.Client/src/common/services/contenteditinghelper.service.js b/src/Umbraco.Web.UI.Client/src/common/services/contenteditinghelper.service.js index 6d41ea087d..fd0bd3efd9 100644 --- a/src/Umbraco.Web.UI.Client/src/common/services/contenteditinghelper.service.js +++ b/src/Umbraco.Web.UI.Client/src/common/services/contenteditinghelper.service.js @@ -84,7 +84,7 @@ function contentEditingHelper(fileManager, $q, $location, $routeParams, editorSt //when true, the url will change but it won't actually re-route //this is merely here for compatibility, if only the content/media/members used this service we'd prob be ok but tons of editors //use this service unfortunately and probably packages too. - args.softRedirect = false; + args.softRedirect = false; } @@ -93,7 +93,12 @@ function contentEditingHelper(fileManager, $q, $location, $routeParams, editorSt //we will use the default one for content if not specified var rebindCallback = args.rebindCallback === undefined ? self.reBindChangedProperties : args.rebindCallback; - if (formHelper.submitForm({ scope: args.scope, action: args.action })) { + var formSubmitOptions = { scope: args.scope, action: args.action }; + if(args.skipValidation === true) { + formSubmitOptions.skipValidation = true; + formSubmitOptions.keepServerValidation = true; + } + if (formHelper.submitForm(formSubmitOptions)) { return args.saveMethod(args.content, args.create, fileManager.getFiles(), args.showNotifications) .then(function (data) { @@ -298,7 +303,7 @@ function contentEditingHelper(fileManager, $q, $location, $routeParams, editorSt } // if publishing is allowed also allow schedule publish - // we add this manually becuase it doesn't have a permission so it wont + // we add this manually becuase it doesn't have a permission so it wont // get picked up by the loop through permissions if (_.contains(args.content.allowedActions, "U")) { buttons.subButtons.push(createButtonDefinition("SCHEDULE")); @@ -622,7 +627,7 @@ function contentEditingHelper(fileManager, $q, $location, $routeParams, editorSt if (!args.err) { throw "args.err cannot be null"; } - + //When the status is a 400 status with a custom header: X-Status-Reason: Validation failed, we have validation errors. //Otherwise the error is probably due to invalid data (i.e. someone mucking around with the ids or something). //Or, some strange server error @@ -640,7 +645,7 @@ function contentEditingHelper(fileManager, $q, $location, $routeParams, editorSt if (!this.redirectToCreatedContent(args.err.data.id, args.softRedirect) || args.softRedirect) { // If we are not redirecting it's because this is not newly created content, else in some cases we are - // soft-redirecting which means the URL will change but the route wont (i.e. creating content). + // soft-redirecting which means the URL will change but the route wont (i.e. creating content). // In this case we need to detect what properties have changed and re-bind them with the server data. if (args.rebindCallback && angular.isFunction(args.rebindCallback)) { @@ -687,7 +692,7 @@ function contentEditingHelper(fileManager, $q, $location, $routeParams, editorSt if (!this.redirectToCreatedContent(args.redirectId ? args.redirectId : args.savedContent.id, args.softRedirect) || args.softRedirect) { // If we are not redirecting it's because this is not newly created content, else in some cases we are - // soft-redirecting which means the URL will change but the route wont (i.e. creating content). + // soft-redirecting which means the URL will change but the route wont (i.e. creating content). // In this case we need to detect what properties have changed and re-bind them with the server data. if (args.rebindCallback && angular.isFunction(args.rebindCallback)) { @@ -723,7 +728,7 @@ function contentEditingHelper(fileManager, $q, $location, $routeParams, editorSt navigationService.setSoftRedirect(); } //change to new path - $location.path("/" + $routeParams.section + "/" + $routeParams.tree + "/" + $routeParams.method + "/" + id); + $location.path("/" + $routeParams.section + "/" + $routeParams.tree + "/" + $routeParams.method + "/" + id); //don't add a browser history for this $location.replace(); return true; From 3185a285d93a2835044b0cdc7b95301dd2929fa0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Niels=20Lyngs=C3=B8?= Date: Mon, 1 Feb 2021 11:56:51 +0100 Subject: [PATCH 02/70] Correcting merge --- .../common/directives/components/content/edit.controller.js | 5 +++-- 1 file changed, 3 insertions(+), 2 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 c3e23e4cfd..fb70143fa5 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 @@ -481,13 +481,14 @@ syncTreeNode($scope.content, $scope.content.path); + if($scope.contentForm.$invalid !== true) { + resetNestedFieldValiation(fieldsToRollback); + } if (err.status === 400 && err.data) { // content was saved but is invalid. eventsService.emit("content.saved", { content: $scope.content, action: args.action, valid: false }); } - resetNestedFieldValiation(fieldsToRollback); - return $q.reject(err); }); } From 26d11a83141abc5e4d94c24e733cdca768d1a6f1 Mon Sep 17 00:00:00 2001 From: ric <60885685+ricbrady@users.noreply.github.com> Date: Tue, 6 Apr 2021 14:44:49 +0200 Subject: [PATCH 03/70] Fixed copy preserving sort order (#10091) --- .../Services/Implement/ContentService.cs | 10 +++---- .../Services/ContentServiceTests.cs | 26 +++++++++++++++++++ 2 files changed, 31 insertions(+), 5 deletions(-) diff --git a/src/Umbraco.Core/Services/Implement/ContentService.cs b/src/Umbraco.Core/Services/Implement/ContentService.cs index e5363d0e2b..d8e99663ea 100644 --- a/src/Umbraco.Core/Services/Implement/ContentService.cs +++ b/src/Umbraco.Core/Services/Implement/ContentService.cs @@ -1415,7 +1415,7 @@ namespace Umbraco.Core.Services.Implement var result = CommitDocumentChangesInternal(scope, d, saveEventArgs, allLangs.Value, d.WriterId); if (result.Success == false) - Logger.Error(null, "Failed to publish document id={DocumentId}, reason={Reason}.", d.Id, result.Result); + Logger.Error(null, "Failed to publish document id={DocumentId}, reason={Reason}.", d.Id, result.Result); results.Add(result); } @@ -2201,7 +2201,7 @@ namespace Umbraco.Core.Services.Implement while (page * pageSize < total) { var descendants = GetPagedDescendants(content.Id, page++, pageSize, out total); - foreach (var descendant in descendants) + foreach (var descendant in descendants.OrderBy(x => x.Level).ThenBy(y => y.SortOrder)) { // if parent has not been copied, skip, else gets its copy id if (idmap.TryGetValue(descendant.ParentId, out parentId) == false) continue; @@ -2420,7 +2420,7 @@ namespace Umbraco.Core.Services.Implement if (report.FixedIssues.Count > 0) { //The event args needs a content item so we'll make a fake one with enough properties to not cause a null ref - var root = new Content("root", -1, new ContentType(-1)) {Id = -1, Key = Guid.Empty}; + var root = new Content("root", -1, new ContentType(-1)) { Id = -1, Key = Guid.Empty }; scope.Events.Dispatch(TreeChanged, this, new TreeChange.EventArgs(new TreeChange(root, TreeChangeTypes.RefreshAll))); } @@ -3169,7 +3169,7 @@ namespace Umbraco.Core.Services.Implement if (rollbackSaveResult.Success == false) { //Log the error/warning - Logger.Error("User '{UserId}' was unable to rollback content '{ContentId}' to version '{VersionId}'", userId, id, versionId); + Logger.Error("User '{UserId}' was unable to rollback content '{ContentId}' to version '{VersionId}'", userId, id, versionId); } else { @@ -3178,7 +3178,7 @@ namespace Umbraco.Core.Services.Implement scope.Events.Dispatch(RolledBack, this, rollbackEventArgs); //Logging & Audit message - Logger.Info("User '{UserId}' rolled back content '{ContentId}' to version '{VersionId}'", userId, id, versionId); + Logger.Info("User '{UserId}' rolled back content '{ContentId}' to version '{VersionId}'", userId, id, versionId); Audit(AuditType.RollBack, userId, id, $"Content '{content.Name}' was rolled back to version '{versionId}'"); } diff --git a/src/Umbraco.Tests/Services/ContentServiceTests.cs b/src/Umbraco.Tests/Services/ContentServiceTests.cs index 008c24fcbf..0faa4af316 100644 --- a/src/Umbraco.Tests/Services/ContentServiceTests.cs +++ b/src/Umbraco.Tests/Services/ContentServiceTests.cs @@ -2082,6 +2082,32 @@ namespace Umbraco.Tests.Services Assert.AreEqual("world", copiedTags[1].Text); } + [Test] + public void Copy_Recursive_Preserves_Sort_Order() + { + // Arrange + var contentService = ServiceContext.ContentService; + var temp = contentService.GetById(NodeDto.NodeIdSeed + 2); + Assert.AreEqual("Home", temp.Name); + Assert.AreEqual(3, contentService.CountChildren(temp.Id)); + var reversedChildren = contentService.GetPagedChildren(temp.Id, 0, 10, out var total1).Reverse().ToArray(); + contentService.Sort(reversedChildren); + + // Act + var copy = contentService.Copy(temp, temp.ParentId, false, true, Constants.Security.SuperUserId); + var content = contentService.GetById(NodeDto.NodeIdSeed + 2); + + // Assert + Assert.That(copy, Is.Not.Null); + Assert.That(copy.Id, Is.Not.EqualTo(content.Id)); + Assert.AreNotSame(content, copy); + Assert.AreEqual(3, contentService.CountChildren(copy.Id)); + + var copiedChildren = contentService.GetPagedChildren(copy.Id, 0, 10, out var total2).OrderBy(c => c.SortOrder).ToArray(); + Assert.AreEqual(reversedChildren.First().Name, copiedChildren.First().Name); + Assert.AreEqual(reversedChildren.Last().Name, copiedChildren.Last().Name); + } + [Test] public void Can_Rollback_Version_On_Content() { From e21cc6f97eb1d49e2f0060186b57680e4ef44a59 Mon Sep 17 00:00:00 2001 From: Rachel Breeze Date: Sat, 10 Apr 2021 01:34:18 +0100 Subject: [PATCH 04/70] Accessibility: Adding label fors and control ids for the macro picker (#10101) * Added support for screeen reader alerts on the embed so that assitive technology knows when a url retrieve has been succesfull. Added labels for the controls Preview reload only triggered if the values for height and width change * Added support for label fors for the macro picker and also gave the ,acro search box a title * Now displays a count of the matching macros returned. Please note the language file amends shared with #10100 * Removed src-only class for the display of the count of messages --- .../macropicker/macropicker.controller.js | 31 +++++++++++++++++-- .../macropicker/macropicker.html | 24 +++++++------- 2 files changed, 40 insertions(+), 15 deletions(-) diff --git a/src/Umbraco.Web.UI.Client/src/views/common/infiniteeditors/macropicker/macropicker.controller.js b/src/Umbraco.Web.UI.Client/src/views/common/infiniteeditors/macropicker/macropicker.controller.js index 40338f2dca..1701553efc 100644 --- a/src/Umbraco.Web.UI.Client/src/views/common/infiniteeditors/macropicker/macropicker.controller.js +++ b/src/Umbraco.Web.UI.Client/src/views/common/infiniteeditors/macropicker/macropicker.controller.js @@ -1,12 +1,13 @@ function MacroPickerController($scope, entityResource, macroResource, umbPropEditorHelper, macroService, formHelper, localizationService) { $scope.macros = []; + $scope.a11yInfo = ""; $scope.model.selectedMacro = null; $scope.model.macroParams = []; - + $scope.displayA11YMessageForFilter = displayA11YMessageForFilter; $scope.wizardStep = "macroSelect"; $scope.noMacroParams = false; - + $scope.model.searchTerm = ""; function onInit() { if (!$scope.model.title) { localizationService.localize("defaultdialogs_selectMacro").then(function (value) { @@ -49,6 +50,7 @@ function MacroPickerController($scope, entityResource, macroResource, umbPropEdi $scope.model.submit($scope.model); } else { $scope.wizardStep = 'macroSelect'; + displayA11yMessages($scope.macros); } } else { @@ -95,6 +97,28 @@ function MacroPickerController($scope, entityResource, macroResource, umbPropEdi }); } + function displayA11yMessages(macros) { + if ($scope.noMacroParams || !macros || macros.length === 0) + localizationService.localize("general_searchNoResult").then(function (value) { + $scope.a11yInfo = value; + }); + else if (macros) { + if (macros.length === 1) { + localizationService.localize("treeSearch_searchResult").then(function(value) { + $scope.a11yInfo = "1 " + value; + }); + } else { + localizationService.localize("treeSearch_searchResults").then(function (value) { + $scope.a11yInfo = macros.length + " " + value; + }); + } + } + } + + function displayA11YMessageForFilter() { + var macros = _.filter($scope.macros, v => v.name.toLowerCase().includes($scope.model.searchTerm.toLowerCase())); + displayA11yMessages(macros); + } //here we check to see if we've been passed a selected macro and if so we'll set the //editor to start with parameter editing if ($scope.model.dialogData && $scope.model.dialogData.macroData) { @@ -141,10 +165,11 @@ function MacroPickerController($scope, entityResource, macroResource, umbPropEdi //we don't have a pre-selected macro so ensure the correct step is set $scope.wizardStep = 'macroSelect'; } + displayA11yMessages($scope.macros); }); onInit(); - + } angular.module("umbraco").controller("Umbraco.Overlays.MacroPickerController", MacroPickerController); diff --git a/src/Umbraco.Web.UI.Client/src/views/common/infiniteeditors/macropicker/macropicker.html b/src/Umbraco.Web.UI.Client/src/views/common/infiniteeditors/macropicker/macropicker.html index 33d7a471a5..8bda49b328 100644 --- a/src/Umbraco.Web.UI.Client/src/views/common/infiniteeditors/macropicker/macropicker.html +++ b/src/Umbraco.Web.UI.Client/src/views/common/infiniteeditors/macropicker/macropicker.html @@ -16,18 +16,18 @@
- - + + - +

    -
  • +
+ position="center"> There are no macros available to insert @@ -53,7 +53,7 @@
  • - + From 3b6de9cb9ec3b2b510642379da00a6cea8cb4f3a Mon Sep 17 00:00:00 2001 From: Carole Rennie Logan Date: Fri, 9 Apr 2021 18:43:55 +0100 Subject: [PATCH 05/70] Updating typo --- src/Umbraco.Core/Constants-Security.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Umbraco.Core/Constants-Security.cs b/src/Umbraco.Core/Constants-Security.cs index f900288ef5..2b6244debb 100644 --- a/src/Umbraco.Core/Constants-Security.cs +++ b/src/Umbraco.Core/Constants-Security.cs @@ -25,7 +25,7 @@ namespace Umbraco.Core /// /// The name of the 'unknown' user. /// - public const string UnknownUserName = "SYTEM"; + public const string UnknownUserName = "SYSTEM"; public const string AdminGroupAlias = "admin"; public const string EditorGroupAlias = "editor"; From 4f49e57573ba0739fdbade18fee59465fa1aa5ea Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dennis=20=C3=96hman?= Date: Sun, 11 Apr 2021 16:40:13 +0200 Subject: [PATCH 06/70] Removed top-margin from switcher icon --- .../src/less/components/editor/umb-variant-switcher.less | 1 - 1 file changed, 1 deletion(-) diff --git a/src/Umbraco.Web.UI.Client/src/less/components/editor/umb-variant-switcher.less b/src/Umbraco.Web.UI.Client/src/less/components/editor/umb-variant-switcher.less index 9d2782f184..ce9286e5f5 100644 --- a/src/Umbraco.Web.UI.Client/src/less/components/editor/umb-variant-switcher.less +++ b/src/Umbraco.Web.UI.Client/src/less/components/editor/umb-variant-switcher.less @@ -69,7 +69,6 @@ button.umb-variant-switcher__toggle { .umb-variant-switcher__expand { color: @ui-action-discreet-type; - margin-top: 3px; margin-left: 5px; margin-right: -5px; transition: color 0.2s ease-in-out; From c8b6841ef16e40670a89ba8a84aa21b2d066e9a3 Mon Sep 17 00:00:00 2001 From: Jeavon Date: Tue, 13 Apr 2021 02:10:44 +0100 Subject: [PATCH 07/70] Allow KeepAlive controller Ping method to be requested by non local requests (#10126) * Allow KeepAlive controller Ping method to be requested by non local requests and accept head requests * removed unused references --- src/Umbraco.Web/Editors/KeepAliveController.cs | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/Umbraco.Web/Editors/KeepAliveController.cs b/src/Umbraco.Web/Editors/KeepAliveController.cs index 23815e1bbe..f29ee6c60a 100644 --- a/src/Umbraco.Web/Editors/KeepAliveController.cs +++ b/src/Umbraco.Web/Editors/KeepAliveController.cs @@ -1,14 +1,12 @@ using System.Runtime.Serialization; using System.Web.Http; -using Umbraco.Web.Mvc; using Umbraco.Web.WebApi; -using Umbraco.Web.WebApi.Filters; namespace Umbraco.Web.Editors { public class KeepAliveController : UmbracoApiController { - [OnlyLocalRequests] + [HttpHead] [HttpGet] public KeepAlivePingResult Ping() { From 57ed4698f01be40328698c991c88de4e8a495064 Mon Sep 17 00:00:00 2001 From: Sebastiaan Janssen Date: Mon, 19 Apr 2021 17:31:09 +0200 Subject: [PATCH 08/70] Revert "Revert "The Value() method for IPublishedContent was not working with the defaultValue parameter" (#9989)" This reverts commit 156c1c94161171f9592923f20de4e142c845469a. --- src/Umbraco.Web/PublishedContentExtensions.cs | 6 ++-- src/Umbraco.Web/PublishedPropertyExtension.cs | 33 ++++++------------- 2 files changed, 13 insertions(+), 26 deletions(-) diff --git a/src/Umbraco.Web/PublishedContentExtensions.cs b/src/Umbraco.Web/PublishedContentExtensions.cs index c851894149..6384b0f8d4 100644 --- a/src/Umbraco.Web/PublishedContentExtensions.cs +++ b/src/Umbraco.Web/PublishedContentExtensions.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Collections.Generic; using System.Data; using System.Linq; @@ -173,8 +173,8 @@ namespace Umbraco.Web return value; // else... if we have a property, at least let the converter return its own - // vision of 'no value' (could be an empty enumerable) - otherwise, default - return property == null ? default : property.Value(culture, segment, fallback, defaultValue); + // vision of 'no value' (could be an empty enumerable) - otherwise, defaultValue + return property == null ? defaultValue : property.Value(culture, segment, defaultValue: defaultValue); } #endregion diff --git a/src/Umbraco.Web/PublishedPropertyExtension.cs b/src/Umbraco.Web/PublishedPropertyExtension.cs index 6e8647db47..0c3aa57cc2 100644 --- a/src/Umbraco.Web/PublishedPropertyExtension.cs +++ b/src/Umbraco.Web/PublishedPropertyExtension.cs @@ -1,3 +1,4 @@ +using System.Collections.Generic; using Umbraco.Core; using Umbraco.Core.Composing; using Umbraco.Core.Models.PublishedContent; @@ -36,20 +37,13 @@ namespace Umbraco.Web // we have a value // try to cast or convert it var value = property.GetValue(culture, segment); - if (value is T valueAsT) - { - return valueAsT; - } - + if (value is T valueAsT) return valueAsT; var valueConverted = value.TryConvertTo(); - if (valueConverted) - { - return valueConverted.Result; - } + if (valueConverted) return valueConverted.Result; - // cannot cast nor convert the value, nothing we can return but 'default' + // cannot cast nor convert the value, nothing we can return but 'defaultValue' // note: we don't want to fallback in that case - would make little sense - return default; + return defaultValue; } // we don't have a value, try fallback @@ -63,22 +57,15 @@ namespace Umbraco.Web var noValue = property.GetValue(culture, segment); if (noValue == null) { - return default; - } - - if (noValue is T noValueAsT) - { - return noValueAsT; + return defaultValue; } + if (noValue is T noValueAsT) return noValueAsT; var noValueConverted = noValue.TryConvertTo(); - if (noValueConverted) - { - return noValueConverted.Result; - } + if (noValueConverted) return noValueConverted.Result; - // cannot cast noValue nor convert it, nothing we can return but 'default' - return default; + // cannot cast noValue nor convert it, nothing we can return but 'defaultValue' + return defaultValue; } #endregion From f1e4fec4c4ad0299a787d350ea32e6ff2d26cf4e Mon Sep 17 00:00:00 2001 From: Sebastiaan Janssen Date: Mon, 19 Apr 2021 17:31:53 +0200 Subject: [PATCH 09/70] Revert "The Value() method for IPublishedContent was not working with the defaultValue parameter (#9888)" This reverts commit 52b670973d562b86a89665dd4b1b23fba8ec3900. --- src/Umbraco.Web/PublishedContentExtensions.cs | 4 ++-- src/Umbraco.Web/PublishedPropertyExtension.cs | 15 ++++----------- 2 files changed, 6 insertions(+), 13 deletions(-) diff --git a/src/Umbraco.Web/PublishedContentExtensions.cs b/src/Umbraco.Web/PublishedContentExtensions.cs index 6384b0f8d4..b43717d418 100644 --- a/src/Umbraco.Web/PublishedContentExtensions.cs +++ b/src/Umbraco.Web/PublishedContentExtensions.cs @@ -173,8 +173,8 @@ namespace Umbraco.Web return value; // else... if we have a property, at least let the converter return its own - // vision of 'no value' (could be an empty enumerable) - otherwise, defaultValue - return property == null ? defaultValue : property.Value(culture, segment, defaultValue: defaultValue); + // vision of 'no value' (could be an empty enumerable) - otherwise, default + return property == null ? default : property.Value(culture, segment); } #endregion diff --git a/src/Umbraco.Web/PublishedPropertyExtension.cs b/src/Umbraco.Web/PublishedPropertyExtension.cs index 0c3aa57cc2..b431f24828 100644 --- a/src/Umbraco.Web/PublishedPropertyExtension.cs +++ b/src/Umbraco.Web/PublishedPropertyExtension.cs @@ -41,31 +41,24 @@ namespace Umbraco.Web var valueConverted = value.TryConvertTo(); if (valueConverted) return valueConverted.Result; - // cannot cast nor convert the value, nothing we can return but 'defaultValue' + // cannot cast nor convert the value, nothing we can return but 'default' // note: we don't want to fallback in that case - would make little sense - return defaultValue; + return default; } // we don't have a value, try fallback if (PublishedValueFallback.TryGetValue(property, culture, segment, fallback, defaultValue, out var fallbackValue)) - { return fallbackValue; - } // we don't have a value - neither direct nor fallback // give a chance to the converter to return something (eg empty enumerable) var noValue = property.GetValue(culture, segment); - if (noValue == null) - { - return defaultValue; - } if (noValue is T noValueAsT) return noValueAsT; - var noValueConverted = noValue.TryConvertTo(); if (noValueConverted) return noValueConverted.Result; - // cannot cast noValue nor convert it, nothing we can return but 'defaultValue' - return defaultValue; + // cannot cast noValue nor convert it, nothing we can return but 'default' + return default; } #endregion From a3e3e83a3df2f450106c41909cf92eb1300c5104 Mon Sep 17 00:00:00 2001 From: Sebastiaan Janssen Date: Mon, 19 Apr 2021 17:34:01 +0200 Subject: [PATCH 10/70] Bump version to 8.13.0 --- src/SolutionInfo.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/SolutionInfo.cs b/src/SolutionInfo.cs index 2a7386cb45..1009ec125b 100644 --- a/src/SolutionInfo.cs +++ b/src/SolutionInfo.cs @@ -19,4 +19,4 @@ using System.Resources; // these are FYI and changed automatically [assembly: AssemblyFileVersion("8.13.0")] -[assembly: AssemblyInformationalVersion("8.13.0-rc")] +[assembly: AssemblyInformationalVersion("8.13.0")] From 12cde0c571318847e5a23ec58093c09b22ad7af5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Niels=20Lyngs=C3=B8?= Date: Tue, 20 Apr 2021 11:10:07 +0200 Subject: [PATCH 11/70] Use warning style when saving --- .../components/content/edit.controller.js | 7 ++- .../validation/valformmanager.directive.js | 57 ++++++++++++++++++- .../services/contenteditinghelper.service.js | 18 ++++-- .../src/less/alerts.less | 16 ++++++ .../umb-editor-navigation-item.less | 23 +++++--- .../less/components/umb-nested-content.less | 6 +- .../src/less/components/umb-tabs.less | 7 +++ src/Umbraco.Web.UI.Client/src/less/forms.less | 10 ++++ .../src/less/variables.less | 4 +- .../labelblock/labelblock.editor.less | 6 ++ 10 files changed, 137 insertions(+), 17 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 da93450522..c7f56eeda6 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 @@ -788,7 +788,12 @@ }).then(function () { $scope.page.saveButtonState = "success"; }, function (err) { - $scope.page.saveButtonState = "error"; + // Because this is the "save"-action, then we actually save though there was a validation error, therefor we will show success and display the validation errors politely. + if(err && err.data && err.data.ModelState && Object.keys(err.data.ModelState).length > 0) { + $scope.page.saveButtonState = "success"; + } else { + $scope.page.saveButtonState = "error"; + } handleHttpException(err); }); } diff --git a/src/Umbraco.Web.UI.Client/src/common/directives/validation/valformmanager.directive.js b/src/Umbraco.Web.UI.Client/src/common/directives/validation/valformmanager.directive.js index 55878db2e9..be84d45075 100644 --- a/src/Umbraco.Web.UI.Client/src/common/directives/validation/valformmanager.directive.js +++ b/src/Umbraco.Web.UI.Client/src/common/directives/validation/valformmanager.directive.js @@ -15,6 +15,7 @@ function valFormManager(serverValidationManager, $rootScope, $timeout, $location, overlayService, eventsService, $routeParams, navigationService, editorService, localizationService, angularHelper) { var SHOW_VALIDATION_CLASS_NAME = "show-validation"; + var SHOW_VALIDATION_Type_CLASS_NAME = "show-validation-type-"; var SAVING_EVENT_NAME = "formSubmitting"; var SAVED_EVENT_NAME = "formSubmitted"; @@ -25,7 +26,7 @@ function valFormManager(serverValidationManager, $rootScope, $timeout, $location function ValFormManagerController($scope) { //This exposes an API for direct use with this directive - // We need this as a way to reference this directive in the scope chain. Since this directive isn't a component and + // We need this as a way to reference this directive in the scope chain. Since this directive isn't a component and // because it's an attribute instead of an element, we can't use controllerAs or anything like that. Plus since this is // an attribute an isolated scope doesn't work so it's a bit weird. By doing this we are able to lookup the parent valFormManager // in the scope hierarchy even if the DOM hierarchy doesn't match (i.e. in infinite editing) @@ -44,6 +45,8 @@ function valFormManager(serverValidationManager, $rootScope, $timeout, $location this.isShowingValidation = () => $scope.showValidation === true; + this.getValidationMessageType = () => $scope.valMsgType; + this.notify = notify; this.isValid = function () { @@ -94,6 +97,7 @@ function valFormManager(serverValidationManager, $rootScope, $timeout, $location var parentFormMgr = scope.parentFormMgr = getAncestorValFormManager(scope, ctrls, 1); var subView = ctrls.length > 1 ? ctrls[2] : null; var labels = {}; + var valMsgType = 2;// error var labelKeys = [ "prompt_unsavedChanges", @@ -109,6 +113,46 @@ function valFormManager(serverValidationManager, $rootScope, $timeout, $location labels.stayButton = values[3]; }); + var lastValidationMessageType = null; + function setValidationMessageType(type) { + + removeValidationMessageType(); + scope.valMsgType = type; + + // overall a copy of message types from notifications.service: + var postfix = ""; + switch(type) { + case 0: + //save + break; + case 1: + //info + postfix = "info"; + break; + case 2: + //error + postfix = "error"; + break; + case 3: + //success + postfix = "success"; + break; + case 4: + //warning + postfix = "warning"; + break; + } + var cssClass = SHOW_VALIDATION_Type_CLASS_NAME+postfix; + element.addClass(cssClass); + lastValidationMessageType = cssClass; + } + function removeValidationMessageType() { + if(lastValidationMessageType) { + element.removeClass(lastValidationMessageType); + lastValidationMessageType = null; + } + } + //watch the list of validation errors to notify the application of any validation changes // TODO: Wouldn't it be easier/faster to watch formCtrl.$invalid ? scope.$watch(() => angularHelper.countAllFormErrors(formCtrl), @@ -138,6 +182,8 @@ function valFormManager(serverValidationManager, $rootScope, $timeout, $location if (serverValidationManager.items.length > 0 || (parentFormMgr && parentFormMgr.isShowingValidation())) { element.addClass(SHOW_VALIDATION_CLASS_NAME); scope.showValidation = true; + var parentValMsgType = parentFormMgr ? parentFormMgr.getValidationMessageType() : 2; + setValidationMessageType(parentValMsgType || 2); notifySubView(); } @@ -145,8 +191,16 @@ function valFormManager(serverValidationManager, $rootScope, $timeout, $location //listen for the forms saving event unsubscribe.push(scope.$on(SAVING_EVENT_NAME, function (ev, args) { + + var messageType = 2;//error + switch (args.action) { + case "save": + messageType = 4;//warning + break; + } element.addClass(SHOW_VALIDATION_CLASS_NAME); scope.showValidation = true; + setValidationMessageType(messageType); notifySubView(); //set the flag so we can check to see if we should display the error. isSavingNewItem = $routeParams.create; @@ -156,6 +210,7 @@ function valFormManager(serverValidationManager, $rootScope, $timeout, $location unsubscribe.push(scope.$on(SAVED_EVENT_NAME, function (ev, args) { //remove validation class element.removeClass(SHOW_VALIDATION_CLASS_NAME); + removeValidationMessageType(); scope.showValidation = false; notifySubView(); })); diff --git a/src/Umbraco.Web.UI.Client/src/common/services/contenteditinghelper.service.js b/src/Umbraco.Web.UI.Client/src/common/services/contenteditinghelper.service.js index 8524b960c6..b7f765d8e0 100644 --- a/src/Umbraco.Web.UI.Client/src/common/services/contenteditinghelper.service.js +++ b/src/Umbraco.Web.UI.Client/src/common/services/contenteditinghelper.service.js @@ -32,7 +32,8 @@ function contentEditingHelper(fileManager, $q, $location, $routeParams, editorSt return true; } - function showNotificationsForModelsState(ms) { + function showNotificationsForModelsState(ms, messageType) { + messageType = messageType || 2; for (const [key, value] of Object.entries(ms)) { var errorMsg = value[0]; @@ -42,12 +43,14 @@ function contentEditingHelper(fileManager, $q, $location, $routeParams, editorSt var idsToErrors = serverValidationManager.parseComplexEditorError(errorMsg, ""); idsToErrors.forEach(x => { if (x.modelState) { - showNotificationsForModelsState(x.modelState); + showNotificationsForModelsState(x.modelState, messageType); } }); } else if (value[0]) { - notificationsService.error("Validation", value[0]); + //notificationsService.error("Validation", value[0]); + console.log({type:messageType, header:"Validation", message:value[0]}) + notificationsService.showNotification({type:messageType, header:"Validation", message:value[0]}) } } } @@ -124,6 +127,7 @@ function contentEditingHelper(fileManager, $q, $location, $routeParams, editorSt showNotifications: args.showNotifications, softRedirect: args.softRedirect, err: err, + action: args.action, rebindCallback: function () { // if the error contains data, we want to map that back as we want to continue editing this save. Especially important when the content is new as the returned data will contain ID etc. if(err.data) { @@ -639,9 +643,15 @@ function contentEditingHelper(fileManager, $q, $location, $routeParams, editorSt //wire up the server validation errs formHelper.handleServerValidation(args.err.data.ModelState); + var messageType = 2;//error + console.log(args) + if (args.action === "save") { + messageType = 4;//warning + } + //add model state errors to notifications if (args.showNotifications) { - showNotificationsForModelsState(args.err.data.ModelState); + showNotificationsForModelsState(args.err.data.ModelState, messageType); } if (!this.redirectToCreatedContent(args.err.data.id, args.softRedirect) || args.softRedirect) { diff --git a/src/Umbraco.Web.UI.Client/src/less/alerts.less b/src/Umbraco.Web.UI.Client/src/less/alerts.less index 3539e21064..ab0ab9aa13 100644 --- a/src/Umbraco.Web.UI.Client/src/less/alerts.less +++ b/src/Umbraco.Web.UI.Client/src/less/alerts.less @@ -54,6 +54,15 @@ border-color: @errorBorder; color: @errorText; } + +.alert-warning() { + background-color: @warningBackground; + border-color: @warningBorder; + color: @warningText; +} +.alert-warning { + .alert-warning() +} .alert-danger h4, .alert-error h4 { color: @errorText; @@ -110,6 +119,13 @@ padding: 6px 16px 6px 12px; margin-bottom: 6px; + .show-validation-type-warning & { + .alert-warning(); + &.alert-error::after { + border-top-color: @warningBackground; + } + } + &::after { content:''; position: absolute; diff --git a/src/Umbraco.Web.UI.Client/src/less/components/umb-editor-navigation-item.less b/src/Umbraco.Web.UI.Client/src/less/components/umb-editor-navigation-item.less index 5e9772fb26..5fd743aaf0 100644 --- a/src/Umbraco.Web.UI.Client/src/less/components/umb-editor-navigation-item.less +++ b/src/Umbraco.Web.UI.Client/src/less/components/umb-editor-navigation-item.less @@ -86,6 +86,16 @@ } } } + + .show-validation.show-validation-type-warning &.-has-error { + color: @yellow-d2; + &:hover { + color: @yellow-d2 !important; + } + &::before { + background-color: @yellow-d2; + } + } } &__action:active, @@ -122,14 +132,6 @@ line-height: 16px; display: block; - &.-type-alert { - background-color: @red; - } - - &.-type-warning { - background-color: @yellow-d2; - } - &:empty { height: 12px; min-width: 12px; @@ -137,6 +139,11 @@ &.--error-badge { display: none; font-weight: 900; + background-color: @red; + + .show-validation-type-warning & { + background-color: @yellow-d2; + } } } diff --git a/src/Umbraco.Web.UI.Client/src/less/components/umb-nested-content.less b/src/Umbraco.Web.UI.Client/src/less/components/umb-nested-content.less index bd787e2329..9dd40a4386 100644 --- a/src/Umbraco.Web.UI.Client/src/less/components/umb-nested-content.less +++ b/src/Umbraco.Web.UI.Client/src/less/components/umb-nested-content.less @@ -48,6 +48,10 @@ &.--error { border-color: @formErrorBorder !important; } + + .show-validation-type-warning &.--error { + border-color: @formWarningBorder !important; + } } .umb-nested-content__item.ui-sortable-placeholder { @@ -292,4 +296,4 @@ .umb-textarea, .umb-textstring { width:100%; } -} \ No newline at end of file +} diff --git a/src/Umbraco.Web.UI.Client/src/less/components/umb-tabs.less b/src/Umbraco.Web.UI.Client/src/less/components/umb-tabs.less index 15b317aa45..1b249f1c3a 100644 --- a/src/Umbraco.Web.UI.Client/src/less/components/umb-tabs.less +++ b/src/Umbraco.Web.UI.Client/src/less/components/umb-tabs.less @@ -86,6 +86,13 @@ background-color: @red !important; border-color: @errorBorder; } +.show-validation.show-validation-type-warning .umb-tab--error > .umb-tab-button, +.show-validation.show-validation-type-warning .umb-tab--error > .umb-tab-button:hover, +.show-validation.show-validation-type-warning .umb-tab--error > .umb-tab-button:focus { + color: @white !important; + background-color: @yellow-d2 !important; + border-color: @warningBorder; +} .show-validation .umb-tab--error .umb-tab-button:before { content: "\e25d"; diff --git a/src/Umbraco.Web.UI.Client/src/less/forms.less b/src/Umbraco.Web.UI.Client/src/less/forms.less index 3782fca695..60561f9acc 100644 --- a/src/Umbraco.Web.UI.Client/src/less/forms.less +++ b/src/Umbraco.Web.UI.Client/src/less/forms.less @@ -506,10 +506,20 @@ input[type="checkbox"][readonly] { .formFieldState(@formErrorText, @formErrorText, @formErrorBackground); } +// ValidationError as a warning +.show-validation.show-validation-type-warning.ng-invalid .control-group.error, +.show-validation.show-validation-type-warning.ng-invalid .umb-editor-header__name-wrapper { + .formFieldState(@formWarningText, @formWarningText, @formWarningBackground); +} + //val-highlight directive styling .highlight-error { color: @formErrorText !important; border-color: @red-l1 !important; + .show-validation-type-warning & { + color: @formWarningText !important; + border-color: @yellow-d2 !important; + } } // FORM ACTIONS diff --git a/src/Umbraco.Web.UI.Client/src/less/variables.less b/src/Umbraco.Web.UI.Client/src/less/variables.less index cab0745a42..90cf24cf2d 100644 --- a/src/Umbraco.Web.UI.Client/src/less/variables.less +++ b/src/Umbraco.Web.UI.Client/src/less/variables.less @@ -291,8 +291,8 @@ @btnSuccessBackground: @ui-btn-positive;// updated 2019 @btnSuccessBackgroundHighlight: @ui-btn-positive-hover;// updated 2019 -@btnWarningBackground: @orange; -@btnWarningBackgroundHighlight: lighten(@orange, 10%); +@btnWarningBackground: @yellow-d2; +@btnWarningBackgroundHighlight: lighten(@yellow-d2, 10%); @btnDangerBackground: @red; @btnDangerBackgroundHighlight: @red-l1; diff --git a/src/Umbraco.Web.UI.Client/src/views/propertyeditors/blocklist/blocklistentryeditors/labelblock/labelblock.editor.less b/src/Umbraco.Web.UI.Client/src/views/propertyeditors/blocklist/blocklistentryeditors/labelblock/labelblock.editor.less index 613a47b926..837fd3f564 100644 --- a/src/Umbraco.Web.UI.Client/src/views/propertyeditors/blocklist/blocklistentryeditors/labelblock/labelblock.editor.less +++ b/src/Umbraco.Web.UI.Client/src/views/propertyeditors/blocklist/blocklistentryeditors/labelblock/labelblock.editor.less @@ -42,6 +42,9 @@ ng-form.ng-invalid-val-server-match-content > .umb-block-list__block > .umb-block-list__block--content > div > & { color: @formErrorText; + .show-validation-type-warning & { + color: @formWarningText; + } } ng-form.ng-invalid-val-server-match-content > .umb-block-list__block:not(.--active) > .umb-block-list__block--content > div > & { > span { @@ -61,6 +64,9 @@ padding: 2px; line-height: 10px; background-color: @formErrorText; + .show-validation-type-warning & { + background-color: @formWarningText; + } font-weight: 900; animation-duration: 1.4s; From 021c0b82c185d82194360ed36f0d91984f0dd7e6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Niels=20Lyngs=C3=B8?= Date: Tue, 20 Apr 2021 11:35:40 +0200 Subject: [PATCH 12/70] final corrections --- .../components/content/edit.controller.js | 8 +++++++- src/Umbraco.Web.UI.Client/src/less/alerts.less | 1 + .../src/less/components/overlays.less | 3 +++ .../src/less/components/umb-list.less | 5 ++++- src/Umbraco.Web.UI.Client/src/less/variables.less | 2 +- .../src/views/content/overlays/save.html | 4 ++-- .../blocklist/umb-block-list-property-editor.less | 15 ++++++++++----- 7 files changed, 28 insertions(+), 10 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 61433c2b62..196c885b4e 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 @@ -765,7 +765,13 @@ }, function (err) { clearDirtyState($scope.content.variants); - model.submitButtonState = "error"; + //model.submitButtonState = "error"; + // Because this is the "save"-action, then we actually save though there was a validation error, therefor we will show success and display the validation errors politely. + if(err && err.data && err.data.ModelState && Object.keys(err.data.ModelState).length > 0) { + model.submitButtonState = "success"; + } else { + model.submitButtonState = "error"; + } //re-map the dialog model since we've re-bound the properties dialog.variants = $scope.content.variants; handleHttpException(err); diff --git a/src/Umbraco.Web.UI.Client/src/less/alerts.less b/src/Umbraco.Web.UI.Client/src/less/alerts.less index ab0ab9aa13..94dcef6f25 100644 --- a/src/Umbraco.Web.UI.Client/src/less/alerts.less +++ b/src/Umbraco.Web.UI.Client/src/less/alerts.less @@ -121,6 +121,7 @@ .show-validation-type-warning & { .alert-warning(); + font-weight: bold; &.alert-error::after { border-top-color: @warningBackground; } diff --git a/src/Umbraco.Web.UI.Client/src/less/components/overlays.less b/src/Umbraco.Web.UI.Client/src/less/components/overlays.less index 035bf02f91..12cce286d6 100644 --- a/src/Umbraco.Web.UI.Client/src/less/components/overlays.less +++ b/src/Umbraco.Web.UI.Client/src/less/components/overlays.less @@ -267,6 +267,9 @@ .umb-overlay .text-error { color: @formErrorText; } +.umb-overlay .text-warning { + color: @formWarningText; +} .umb-overlay .text-success { color: @formSuccessText; diff --git a/src/Umbraco.Web.UI.Client/src/less/components/umb-list.less b/src/Umbraco.Web.UI.Client/src/less/components/umb-list.less index 57ba73305a..c281f7f5ea 100644 --- a/src/Umbraco.Web.UI.Client/src/less/components/umb-list.less +++ b/src/Umbraco.Web.UI.Client/src/less/components/umb-list.less @@ -26,7 +26,10 @@ a.umb-list-item:focus { } .umb-list-item--error { - color: @red; + color: @formErrorText; +} +.umb-list-item--warning { + color: @formWarningText; } .umb-list-item:hover .umb-list-checkbox, diff --git a/src/Umbraco.Web.UI.Client/src/less/variables.less b/src/Umbraco.Web.UI.Client/src/less/variables.less index 90cf24cf2d..9d114b093e 100644 --- a/src/Umbraco.Web.UI.Client/src/less/variables.less +++ b/src/Umbraco.Web.UI.Client/src/less/variables.less @@ -480,7 +480,7 @@ @formWarningBorder: darken(spin(@warningBackground, -10), 3%); @formErrorText: @errorBackground; -@formErrorBackground: lighten(@errorBackground, 55%); +@formErrorBackground: @errorBackground; @formErrorBorder: @red; @formSuccessText: @successBackground; diff --git a/src/Umbraco.Web.UI.Client/src/views/content/overlays/save.html b/src/Umbraco.Web.UI.Client/src/views/content/overlays/save.html index fa9ab8c437..d414f30dbf 100644 --- a/src/Umbraco.Web.UI.Client/src/views/content/overlays/save.html +++ b/src/Umbraco.Web.UI.Client/src/views/content/overlays/save.html @@ -16,7 +16,7 @@
    -
    +
    - {{saveVariantSelectorForm.saveVariantSelector.errorMsg}} + {{saveVariantSelectorForm.saveVariantSelector.errorMsg}} diff --git a/src/Umbraco.Web.UI.Client/src/views/propertyeditors/blocklist/umb-block-list-property-editor.less b/src/Umbraco.Web.UI.Client/src/views/propertyeditors/blocklist/umb-block-list-property-editor.less index 019a772fdd..fbb7e1b32e 100644 --- a/src/Umbraco.Web.UI.Client/src/views/propertyeditors/blocklist/umb-block-list-property-editor.less +++ b/src/Umbraco.Web.UI.Client/src/views/propertyeditors/blocklist/umb-block-list-property-editor.less @@ -23,10 +23,6 @@ > .umb-block-list__block--actions { opacity: 0; transition: opacity 120ms; - - .--error { - color: @formErrorBorder !important; - } } &:hover, @@ -100,6 +96,12 @@ ng-form.ng-invalid-val-server-match-settings > .umb-block-list__block > .umb-blo &:hover { color: @ui-action-discreet-type-hover; } + &.--error { + color: @errorBackground; + .show-validation-type-warning & { + color: @warningBackground; + } + } > .__error-badge { position: absolute; top: -2px; @@ -113,7 +115,10 @@ ng-form.ng-invalid-val-server-match-settings > .umb-block-list__block > .umb-blo font-weight: bold; padding: 2px; line-height: 8px; - background-color: @red; + background-color: @errorBackground; + .show-validation-type-warning & { + background-color: @warningBackground; + } display: none; font-weight: 900; } From 0dfefb72cb90bb8f2e35a2a78ecbbe17396b6ef1 Mon Sep 17 00:00:00 2001 From: Arkadiusz Biel Date: Sat, 31 Oct 2020 22:09:39 +0000 Subject: [PATCH 13/70] use v8 branch as default for API Docs --- src/ApiDocs/docfx.json | 1 + 1 file changed, 1 insertion(+) diff --git a/src/ApiDocs/docfx.json b/src/ApiDocs/docfx.json index 76677d45d5..8283b351c4 100644 --- a/src/ApiDocs/docfx.json +++ b/src/ApiDocs/docfx.json @@ -50,6 +50,7 @@ ], "globalMetadata": { "_appTitle": "Umbraco c# Api docs", + "branch": "v8/contrib", "_enableSearch": true, "_disableContribution": false }, From c885831e02a8c2e4b312dec48945ca5d491130a6 Mon Sep 17 00:00:00 2001 From: Sebastiaan Janssen Date: Thu, 22 Apr 2021 16:34:11 +0200 Subject: [PATCH 14/70] Revert "use v8 branch as default for API Docs" This reverts commit 0dfefb72cb90bb8f2e35a2a78ecbbe17396b6ef1. --- src/ApiDocs/docfx.json | 1 - 1 file changed, 1 deletion(-) diff --git a/src/ApiDocs/docfx.json b/src/ApiDocs/docfx.json index 8283b351c4..76677d45d5 100644 --- a/src/ApiDocs/docfx.json +++ b/src/ApiDocs/docfx.json @@ -50,7 +50,6 @@ ], "globalMetadata": { "_appTitle": "Umbraco c# Api docs", - "branch": "v8/contrib", "_enableSearch": true, "_disableContribution": false }, From 4369747c720d2b5fa7e3c8b7c3617e3ba29a4421 Mon Sep 17 00:00:00 2001 From: Mads Rasmussen Date: Thu, 22 Apr 2021 16:55:18 +0200 Subject: [PATCH 15/70] skip client side validation --- .../components/content/edit.controller.js | 87 +++++++++---------- 1 file changed, 39 insertions(+), 48 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 196c885b4e..bce797d5c8 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 @@ -442,7 +442,6 @@ // This is a helper method to reduce the amount of code repitition for actions: Save, Publish, SendToPublish function performSave(args) { - //Used to check validility of nested form - coming from Content Apps mostly //Set them all to be invalid var fieldsToRollback = checkValidility(); @@ -476,8 +475,6 @@ return $q.when(data); }, function (err) { - - syncTreeNode($scope.content, $scope.content.path); if($scope.contentForm.$invalid !== true) { @@ -739,54 +736,48 @@ clearNotifications($scope.content); // TODO: Add "..." to save button label if there are more than one variant to publish - currently it just adds the elipses if there's more than 1 variant if (hasVariants($scope.content)) { - - //before we launch the dialog we want to execute all client side validations first - if (formHelper.submitForm({ scope: $scope, action: "openSaveDialog", skipValidation:true, keepServerValidation:true })) { - var dialog = { - parentScope: $scope, - view: "views/content/overlays/save.html", - variants: $scope.content.variants, //set a model property for the dialog - skipFormValidation: true, //when submitting the overlay form, skip any client side validation - submitButtonLabelKey: "buttons_save", - submit: function (model) { - model.submitButtonState = "busy"; + var dialog = { + parentScope: $scope, + view: "views/content/overlays/save.html", + variants: $scope.content.variants, //set a model property for the dialog + skipFormValidation: true, //when submitting the overlay form, skip any client side validation + submitButtonLabelKey: "buttons_save", + submit: function (model) { + model.submitButtonState = "busy"; + clearNotifications($scope.content); + //we need to return this promise so that the dialog can handle the result and wire up the validation response + return performSave({ + saveMethod: $scope.saveMethod(), + action: "save", + showNotifications: false, + skipValidation: true + }).then(function (data) { + //show all notifications manually here since we disabled showing them automatically in the save method + formHelper.showNotifications(data); clearNotifications($scope.content); - //we need to return this promise so that the dialog can handle the result and wire up the validation response - return performSave({ - saveMethod: $scope.saveMethod(), - action: "save", - showNotifications: false - }).then(function (data) { - //show all notifications manually here since we disabled showing them automatically in the save method - formHelper.showNotifications(data); - clearNotifications($scope.content); - overlayService.close(); - return $q.when(data); - }, - function (err) { - clearDirtyState($scope.content.variants); - //model.submitButtonState = "error"; - // Because this is the "save"-action, then we actually save though there was a validation error, therefor we will show success and display the validation errors politely. - if(err && err.data && err.data.ModelState && Object.keys(err.data.ModelState).length > 0) { - model.submitButtonState = "success"; - } else { - model.submitButtonState = "error"; - } - //re-map the dialog model since we've re-bound the properties - dialog.variants = $scope.content.variants; - handleHttpException(err); - }); - }, - close: function (oldModel) { overlayService.close(); - } - }; + return $q.when(data); + }, + function (err) { + clearDirtyState($scope.content.variants); + //model.submitButtonState = "error"; + // Because this is the "save"-action, then we actually save though there was a validation error, therefor we will show success and display the validation errors politely. + if(err && err.data && err.data.ModelState && Object.keys(err.data.ModelState).length > 0) { + model.submitButtonState = "success"; + } else { + model.submitButtonState = "error"; + } + //re-map the dialog model since we've re-bound the properties + dialog.variants = $scope.content.variants; + handleHttpException(err); + }); + }, + close: function (oldModel) { + overlayService.close(); + } + }; - overlayService.open(dialog); - } - else { - showValidationNotification(); - } + overlayService.open(dialog); } else { //ensure the flags are set From 22afe5e341372540357ed2380f125e6b1b9e2913 Mon Sep 17 00:00:00 2001 From: Shannon Date: Mon, 26 Apr 2021 15:40:46 +1000 Subject: [PATCH 16/70] Adds cold boot restart to load test proj --- src/Umbraco.TestData/LoadTestComponent.cs | 35 ++++++++++++++ src/Umbraco.TestData/LoadTestComposer.cs | 29 +++++++++++ src/Umbraco.TestData/LoadTestController.cs | 51 +++++--------------- src/Umbraco.TestData/Umbraco.TestData.csproj | 2 + 4 files changed, 77 insertions(+), 40 deletions(-) create mode 100644 src/Umbraco.TestData/LoadTestComponent.cs create mode 100644 src/Umbraco.TestData/LoadTestComposer.cs diff --git a/src/Umbraco.TestData/LoadTestComponent.cs b/src/Umbraco.TestData/LoadTestComponent.cs new file mode 100644 index 0000000000..97c006520d --- /dev/null +++ b/src/Umbraco.TestData/LoadTestComponent.cs @@ -0,0 +1,35 @@ +using System.Web.Mvc; +using System.Web.Routing; +using Umbraco.Core.Composing; +using System.Configuration; + +// see https://github.com/Shazwazza/UmbracoScripts/tree/master/src/LoadTesting + +namespace Umbraco.TestData +{ + public class LoadTestComponent : IComponent + { + public void Initialize() + { + if (ConfigurationManager.AppSettings["Umbraco.TestData.Enabled"] != "true") + return; + + + + RouteTable.Routes.MapRoute( + name: "LoadTest", + url: "LoadTest/{action}", + defaults: new + { + controller = "LoadTest", + action = "Index" + }, + namespaces: new[] { "Umbraco.TestData" } + ); + } + + public void Terminate() + { + } + } +} diff --git a/src/Umbraco.TestData/LoadTestComposer.cs b/src/Umbraco.TestData/LoadTestComposer.cs new file mode 100644 index 0000000000..2c5e404642 --- /dev/null +++ b/src/Umbraco.TestData/LoadTestComposer.cs @@ -0,0 +1,29 @@ +using Umbraco.Core.Composing; +using System.Configuration; +using Umbraco.Web.PublishedCache.NuCache; + +// see https://github.com/Shazwazza/UmbracoScripts/tree/master/src/LoadTesting + +namespace Umbraco.TestData +{ + public class LoadTestComposer : ComponentComposer, IUserComposer + { + public override void Compose(Composition composition) + { + base.Compose(composition); + + if (ConfigurationManager.AppSettings["Umbraco.TestData.Enabled"] != "true") + return; + + composition.Register(typeof(LoadTestController), Lifetime.Request); + + if (ConfigurationManager.AppSettings["Umbraco.TestData.IgnoreLocalDb"] == "true") + { + composition.Register(factory => new PublishedSnapshotServiceOptions + { + IgnoreLocalDb = true + }); + } + } + } +} diff --git a/src/Umbraco.TestData/LoadTestController.cs b/src/Umbraco.TestData/LoadTestController.cs index 97665dd084..8e1faf56d1 100644 --- a/src/Umbraco.TestData/LoadTestController.cs +++ b/src/Umbraco.TestData/LoadTestController.cs @@ -6,10 +6,9 @@ using Umbraco.Core.Services; using Umbraco.Core.Models; using System.Web; using System.Web.Hosting; -using System.Web.Routing; using System.Diagnostics; -using Umbraco.Core.Composing; -using System.Configuration; +using Umbraco.Core.IO; +using System.IO; // see https://github.com/Shazwazza/UmbracoScripts/tree/master/src/LoadTesting @@ -261,6 +260,15 @@ namespace Umbraco.TestData HttpRuntime.UnloadAppDomain(); } + public ActionResult ColdBootRestart() + { + Directory.Delete(IOHelper.MapPath("~/App_Data/TEMP/DistCache"), true); + + DoRestart(); + + return Content("Cold Boot Restarted."); + } + public ActionResult Restart() { DoRestart(); @@ -331,41 +339,4 @@ namespace Umbraco.TestData return t; } } - - public class TestComponent : IComponent - { - public void Initialize() - { - if (ConfigurationManager.AppSettings["Umbraco.TestData.Enabled"] != "true") - return; - - RouteTable.Routes.MapRoute( - name: "LoadTest", - url: "LoadTest/{action}", - defaults: new - { - controller = "LoadTest", - action = "Index" - }, - namespaces: new[] { "Umbraco.TestData" } - ); - } - - public void Terminate() - { - } - } - - public class TestComposer : ComponentComposer, IUserComposer - { - public override void Compose(Composition composition) - { - base.Compose(composition); - - if (ConfigurationManager.AppSettings["Umbraco.TestData.Enabled"] != "true") - return; - - composition.Register(typeof(LoadTestController), Lifetime.Request); - } - } } diff --git a/src/Umbraco.TestData/Umbraco.TestData.csproj b/src/Umbraco.TestData/Umbraco.TestData.csproj index a3753cc17b..113d209ef4 100644 --- a/src/Umbraco.TestData/Umbraco.TestData.csproj +++ b/src/Umbraco.TestData/Umbraco.TestData.csproj @@ -41,6 +41,8 @@ + + From 4ade2264d2da7ae38112a6aaad6b101c6f56c87e Mon Sep 17 00:00:00 2001 From: Anders Bjerner Date: Thu, 22 Apr 2021 19:25:59 +0200 Subject: [PATCH 17/70] Minor Danish translations --- src/Umbraco.Web.UI/Umbraco/config/lang/da.xml | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/Umbraco.Web.UI/Umbraco/config/lang/da.xml b/src/Umbraco.Web.UI/Umbraco/config/lang/da.xml index 39a6fee671..9e564635fa 100644 --- a/src/Umbraco.Web.UI/Umbraco/config/lang/da.xml +++ b/src/Umbraco.Web.UI/Umbraco/config/lang/da.xml @@ -804,12 +804,12 @@ Vis genveje Brug listevisning Tillad på rodniveau - Comment/Uncomment lines - Remove line - Copy Lines Up - Copy Lines Down - Move Lines Up - Move Lines Down + Lommentér/Udkommentér linjer + Slet linje + Kopiér linjer op + Kopiér linjer ned + Flyt linjer op + Flyt linjer ned Generelt Editor Skift tillad sprogvarianter From e7a3fd37ce9b00097a45825ed46da692023a94bc Mon Sep 17 00:00:00 2001 From: Sebastiaan Janssen Date: Tue, 27 Apr 2021 14:57:17 +0200 Subject: [PATCH 18/70] Revert "Fixed copy preserving sort order (#10091)" This reverts commit 26d11a83141abc5e4d94c24e733cdca768d1a6f1. --- .../Services/Implement/ContentService.cs | 10 +++---- .../Services/ContentServiceTests.cs | 26 ------------------- 2 files changed, 5 insertions(+), 31 deletions(-) diff --git a/src/Umbraco.Core/Services/Implement/ContentService.cs b/src/Umbraco.Core/Services/Implement/ContentService.cs index d8e99663ea..e5363d0e2b 100644 --- a/src/Umbraco.Core/Services/Implement/ContentService.cs +++ b/src/Umbraco.Core/Services/Implement/ContentService.cs @@ -1415,7 +1415,7 @@ namespace Umbraco.Core.Services.Implement var result = CommitDocumentChangesInternal(scope, d, saveEventArgs, allLangs.Value, d.WriterId); if (result.Success == false) - Logger.Error(null, "Failed to publish document id={DocumentId}, reason={Reason}.", d.Id, result.Result); + Logger.Error(null, "Failed to publish document id={DocumentId}, reason={Reason}.", d.Id, result.Result); results.Add(result); } @@ -2201,7 +2201,7 @@ namespace Umbraco.Core.Services.Implement while (page * pageSize < total) { var descendants = GetPagedDescendants(content.Id, page++, pageSize, out total); - foreach (var descendant in descendants.OrderBy(x => x.Level).ThenBy(y => y.SortOrder)) + foreach (var descendant in descendants) { // if parent has not been copied, skip, else gets its copy id if (idmap.TryGetValue(descendant.ParentId, out parentId) == false) continue; @@ -2420,7 +2420,7 @@ namespace Umbraco.Core.Services.Implement if (report.FixedIssues.Count > 0) { //The event args needs a content item so we'll make a fake one with enough properties to not cause a null ref - var root = new Content("root", -1, new ContentType(-1)) { Id = -1, Key = Guid.Empty }; + var root = new Content("root", -1, new ContentType(-1)) {Id = -1, Key = Guid.Empty}; scope.Events.Dispatch(TreeChanged, this, new TreeChange.EventArgs(new TreeChange(root, TreeChangeTypes.RefreshAll))); } @@ -3169,7 +3169,7 @@ namespace Umbraco.Core.Services.Implement if (rollbackSaveResult.Success == false) { //Log the error/warning - Logger.Error("User '{UserId}' was unable to rollback content '{ContentId}' to version '{VersionId}'", userId, id, versionId); + Logger.Error("User '{UserId}' was unable to rollback content '{ContentId}' to version '{VersionId}'", userId, id, versionId); } else { @@ -3178,7 +3178,7 @@ namespace Umbraco.Core.Services.Implement scope.Events.Dispatch(RolledBack, this, rollbackEventArgs); //Logging & Audit message - Logger.Info("User '{UserId}' rolled back content '{ContentId}' to version '{VersionId}'", userId, id, versionId); + Logger.Info("User '{UserId}' rolled back content '{ContentId}' to version '{VersionId}'", userId, id, versionId); Audit(AuditType.RollBack, userId, id, $"Content '{content.Name}' was rolled back to version '{versionId}'"); } diff --git a/src/Umbraco.Tests/Services/ContentServiceTests.cs b/src/Umbraco.Tests/Services/ContentServiceTests.cs index 0faa4af316..008c24fcbf 100644 --- a/src/Umbraco.Tests/Services/ContentServiceTests.cs +++ b/src/Umbraco.Tests/Services/ContentServiceTests.cs @@ -2082,32 +2082,6 @@ namespace Umbraco.Tests.Services Assert.AreEqual("world", copiedTags[1].Text); } - [Test] - public void Copy_Recursive_Preserves_Sort_Order() - { - // Arrange - var contentService = ServiceContext.ContentService; - var temp = contentService.GetById(NodeDto.NodeIdSeed + 2); - Assert.AreEqual("Home", temp.Name); - Assert.AreEqual(3, contentService.CountChildren(temp.Id)); - var reversedChildren = contentService.GetPagedChildren(temp.Id, 0, 10, out var total1).Reverse().ToArray(); - contentService.Sort(reversedChildren); - - // Act - var copy = contentService.Copy(temp, temp.ParentId, false, true, Constants.Security.SuperUserId); - var content = contentService.GetById(NodeDto.NodeIdSeed + 2); - - // Assert - Assert.That(copy, Is.Not.Null); - Assert.That(copy.Id, Is.Not.EqualTo(content.Id)); - Assert.AreNotSame(content, copy); - Assert.AreEqual(3, contentService.CountChildren(copy.Id)); - - var copiedChildren = contentService.GetPagedChildren(copy.Id, 0, 10, out var total2).OrderBy(c => c.SortOrder).ToArray(); - Assert.AreEqual(reversedChildren.First().Name, copiedChildren.First().Name); - Assert.AreEqual(reversedChildren.Last().Name, copiedChildren.Last().Name); - } - [Test] public void Can_Rollback_Version_On_Content() { From b783399c5cd730cfcbff3fdcedf2f7a4ab2eb25c Mon Sep 17 00:00:00 2001 From: Mike Chambers Date: Tue, 27 Apr 2021 13:56:31 +0100 Subject: [PATCH 19/70] Update ModelsBuilderComposer.cs issue #10186 typo in IsExternalModelsBuilderInstalled -> Umbraco.ModelsBuider --- .../Compose/ModelsBuilderComposer.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Umbraco.ModelsBuilder.Embedded/Compose/ModelsBuilderComposer.cs b/src/Umbraco.ModelsBuilder.Embedded/Compose/ModelsBuilderComposer.cs index 01010cca66..fee9b6f62e 100644 --- a/src/Umbraco.ModelsBuilder.Embedded/Compose/ModelsBuilderComposer.cs +++ b/src/Umbraco.ModelsBuilder.Embedded/Compose/ModelsBuilderComposer.cs @@ -47,7 +47,7 @@ namespace Umbraco.ModelsBuilder.Embedded.Compose { var assemblyNames = new[] { - "Umbraco.ModelsBuider", + "Umbraco.ModelsBuilder", "ModelsBuilder.Umbraco" }; From 349c5ac3ab56fe0cc6c0bb3abd0d6ad314fd2bf6 Mon Sep 17 00:00:00 2001 From: Bjarne Fyrstenborg Date: Sun, 21 Mar 2021 15:14:01 +0100 Subject: [PATCH 20/70] Fix issue with active style affected nested block list elements --- .../inlineblock/inlineblock.editor.less | 28 +++++++++++-------- .../umb-block-list-property-editor.html | 1 - .../blocklist/umbblocklistblock.component.js | 4 +-- 3 files changed, 18 insertions(+), 15 deletions(-) diff --git a/src/Umbraco.Web.UI.Client/src/views/propertyeditors/blocklist/blocklistentryeditors/inlineblock/inlineblock.editor.less b/src/Umbraco.Web.UI.Client/src/views/propertyeditors/blocklist/blocklistentryeditors/inlineblock/inlineblock.editor.less index 45a4c08598..12862d8f41 100644 --- a/src/Umbraco.Web.UI.Client/src/views/propertyeditors/blocklist/blocklistentryeditors/inlineblock/inlineblock.editor.less +++ b/src/Umbraco.Web.UI.Client/src/views/propertyeditors/blocklist/blocklistentryeditors/inlineblock/inlineblock.editor.less @@ -45,18 +45,6 @@ } } - .umb-block-list__block.--active & { - border-color: @gray-8; - box-shadow: 0 0 2px 0px rgba(0, 0, 0, 0.05); - - > button { - > .caret { - transform: rotate(0deg); - } - } - } - - ng-form.ng-invalid-val-server-match-content > .umb-block-list__block > .umb-block-list__block--content > div > & { > button { color: @formErrorText; @@ -104,6 +92,22 @@ } } +.umb-block-list__block.--active { + border-color: @gray-8; + box-shadow: 0 0 2px 0px rgba(0, 0, 0, 0.05); + + > .umb-block-list__block--content { + > .umb-block-list__block--view { + > .blockelement-inlineblock-editor { + > button { + > .caret { + transform: rotate(0deg); + } + } + } + } + } +} .blockelement-inlineblock-editor__inner { border-top: 1px solid @gray-8; diff --git a/src/Umbraco.Web.UI.Client/src/views/propertyeditors/blocklist/umb-block-list-property-editor.html b/src/Umbraco.Web.UI.Client/src/views/propertyeditors/blocklist/umb-block-list-property-editor.html index 9726daf5e6..38959da6ba 100644 --- a/src/Umbraco.Web.UI.Client/src/views/propertyeditors/blocklist/umb-block-list-property-editor.html +++ b/src/Umbraco.Web.UI.Client/src/views/propertyeditors/blocklist/umb-block-list-property-editor.html @@ -61,5 +61,4 @@ model="vm.blockTypePicker"> -
    diff --git a/src/Umbraco.Web.UI.Client/src/views/propertyeditors/blocklist/umbblocklistblock.component.js b/src/Umbraco.Web.UI.Client/src/views/propertyeditors/blocklist/umbblocklistblock.component.js index 285437b011..1027b82e51 100644 --- a/src/Umbraco.Web.UI.Client/src/views/propertyeditors/blocklist/umbblocklistblock.component.js +++ b/src/Umbraco.Web.UI.Client/src/views/propertyeditors/blocklist/umbblocklistblock.component.js @@ -59,12 +59,12 @@ -
    +
    `; $compile(shadowRoot)($scope); } else { - $element.append($compile('
    ')($scope)); + $element.append($compile('
    ')($scope)); } }; From 727be420ff0d7732c19efc395b9ab75ed65ab3b2 Mon Sep 17 00:00:00 2001 From: Bjarne Fyrstenborg Date: Tue, 30 Mar 2021 17:33:33 +0200 Subject: [PATCH 21/70] Use umb-icon component in listview dropdown --- .../src/views/propertyeditors/listview/listview.html | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/Umbraco.Web.UI.Client/src/views/propertyeditors/listview/listview.html b/src/Umbraco.Web.UI.Client/src/views/propertyeditors/listview/listview.html index 1f66d324df..dc226ec307 100644 --- a/src/Umbraco.Web.UI.Client/src/views/propertyeditors/listview/listview.html +++ b/src/Umbraco.Web.UI.Client/src/views/propertyeditors/listview/listview.html @@ -31,12 +31,12 @@ @@ -53,12 +53,12 @@ @@ -69,7 +69,7 @@
  • -
    +
    - {{currentSection.grid}} -
    @@ -74,7 +73,7 @@ @@ -85,7 +84,7 @@
      -
    • +
    • - + on-change="vm.selectRow(currentSection, row)"> - @@ -153,13 +152,13 @@ button-style="link" label-key="general_close" shortcut="esc" - action="close()"> + action="vm.close()"> + action="vm.submit()"> diff --git a/src/Umbraco.Web.UI.Client/src/views/propertyeditors/grid/dialogs/rowconfig.controller.js b/src/Umbraco.Web.UI.Client/src/views/propertyeditors/grid/dialogs/rowconfig.controller.js index 83a9fd5394..b36352a66b 100644 --- a/src/Umbraco.Web.UI.Client/src/views/propertyeditors/grid/dialogs/rowconfig.controller.js +++ b/src/Umbraco.Web.UI.Client/src/views/propertyeditors/grid/dialogs/rowconfig.controller.js @@ -2,10 +2,26 @@ function RowConfigController($scope, localizationService) { var vm = this; + vm.configureCell = configureCell; + vm.closeArea = closeArea; + vm.deleteArea = deleteArea; + vm.selectEditor = selectEditor; + vm.toggleAllowed = toggleAllowed; + vm.percentage = percentage; + vm.scaleUp = scaleUp; + vm.scaleDown = scaleDown; + vm.close = close; + vm.submit = submit; + vm.labels = {}; function init() { - + + $scope.currentRow = $scope.model.currentRow; + $scope.columns = $scope.model.columns; + $scope.editors = $scope.model.editors; + $scope.nameChanged = false; + var labelKeys = [ "grid_addRowConfiguration", "grid_allowAllEditors" @@ -25,12 +41,8 @@ function RowConfigController($scope, localizationService) { $scope.model.title = value; } } - - $scope.currentRow = $scope.model.currentRow; - $scope.columns = $scope.model.columns; - $scope.editors = $scope.model.editors; - $scope.scaleUp = function(section, max, overflow) { + function scaleUp(section, max, overflow) { var add = 1; if (overflow !== true) { add = (max > 1) ? 1 : max; @@ -39,19 +51,19 @@ function RowConfigController($scope, localizationService) { section.grid = section.grid + add; }; - $scope.scaleDown = function(section) { + function scaleDown(section) { var remove = (section.grid > 1) ? 1 : 0; section.grid = section.grid - remove; - }; + } - $scope.percentage = function(spans) { + function percentage(spans) { return ((spans / $scope.columns) * 100).toFixed(8); - }; + } /**************** area *****************/ - $scope.configureCell = function(cell, row) { + function configureCell(cell, row) { if ($scope.currentCell && $scope.currentCell === cell) { delete $scope.currentCell; } @@ -75,12 +87,13 @@ function RowConfigController($scope, localizationService) { $scope.editors.forEach(function (e) { e.allowed = cell.allowed.indexOf(e.alias) !== -1 }); - $scope.currentCell = cell; - $scope.currentCell.allowAll = cell.allowAll || !cell.allowed || !cell.allowed.length; - } - }; + cell.allowAll = cell.allowAll || !cell.allowed || !cell.allowed.length; - $scope.toggleAllowed = function (cell) { + $scope.currentCell = cell; + } + } + + function toggleAllowed(cell) { cell.allowAll = !cell.allowAll; if (cell.allowed) { @@ -89,21 +102,22 @@ function RowConfigController($scope, localizationService) { else { cell.allowed = []; } - }; + } - $scope.deleteArea = function (cell, row) { + function deleteArea(cell, row) { if ($scope.currentCell === cell) { $scope.currentCell = null; } var index = row.areas.indexOf(cell) row.areas.splice(index, 1); - }; + } - $scope.closeArea = function() { + // This doesn't seem to be used? + function closeArea() { $scope.currentCell = null; - }; + } - $scope.selectEditor = function (cell, editor) { + function selectEditor(cell, editor) { cell.allowed = cell.allowed || []; var index = cell.allowed.indexOf(editor.alias); @@ -115,22 +129,20 @@ function RowConfigController($scope, localizationService) { else { cell.allowed.splice(index, 1); } - }; + } - $scope.close = function () { + function close () { if ($scope.model.close) { $scope.model.close(); } - }; + } - $scope.submit = function () { + function submit() { if ($scope.model.submit) { $scope.model.submit($scope.currentRow); } - }; + } - $scope.nameChanged = false; - var originalName = $scope.currentRow.name; $scope.$watch("currentRow", function(row) { if (row) { @@ -141,6 +153,7 @@ function RowConfigController($scope, localizationService) { $scope.availableRowSpace = $scope.columns - total; + var originalName = $scope.currentRow.name; if (originalName) { if (originalName != row.name) { $scope.nameChanged = true; diff --git a/src/Umbraco.Web.UI.Client/src/views/propertyeditors/grid/dialogs/rowconfig.html b/src/Umbraco.Web.UI.Client/src/views/propertyeditors/grid/dialogs/rowconfig.html index 9d105e2629..5cf0676526 100644 --- a/src/Umbraco.Web.UI.Client/src/views/propertyeditors/grid/dialogs/rowconfig.html +++ b/src/Umbraco.Web.UI.Client/src/views/propertyeditors/grid/dialogs/rowconfig.html @@ -41,10 +41,10 @@
      {{currentCell.grid}} -
      @@ -84,7 +84,7 @@ - @@ -93,7 +93,7 @@ + on-change="vm.selectEditor(currentCell, editor)"> {{editor.name}} ({{editor.alias}}) @@ -132,13 +132,13 @@ button-style="link" label-key="general_close" shortcut="esc" - action="close()"> + action="vm.close()"> + action="vm.submit()"> From 68fdc80b6a1c3a1fde0d6112e565f7e64f963a1d Mon Sep 17 00:00:00 2001 From: Anders Bjerner Date: Fri, 7 May 2021 10:37:44 +0200 Subject: [PATCH 29/70] Added target="_blank" to "Update available" link --- src/Umbraco.Web.UI.Client/src/main.controller.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/Umbraco.Web.UI.Client/src/main.controller.js b/src/Umbraco.Web.UI.Client/src/main.controller.js index d21331f106..a5df6904e5 100644 --- a/src/Umbraco.Web.UI.Client/src/main.controller.js +++ b/src/Umbraco.Web.UI.Client/src/main.controller.js @@ -118,7 +118,8 @@ function MainController($scope, $location, appState, treeService, notificationsS message: "Click to download", sticky: true, type: "info", - url: update.url + url: update.url, + target: "_blank" }; notificationsService.add(notification); } From ed62f7d672e8e9f1438a4f31bb9546a4c3fb2dac Mon Sep 17 00:00:00 2001 From: patrickdemooij9 Date: Sun, 9 May 2021 11:42:29 +0200 Subject: [PATCH 30/70] Add "Insert Macro" as language key (#10164) * Add "Insert Macro" as language key * Remove "a" as it wasn't in the original * Formatting * add label in FR lanuage file --- .../grid/editors/macro.controller.js | 104 +++++++++--------- src/Umbraco.Web.UI/Umbraco/config/lang/en.xml | 1 + .../Umbraco/config/lang/en_us.xml | 3 +- src/Umbraco.Web.UI/Umbraco/config/lang/fr.xml | 1 + 4 files changed, 57 insertions(+), 52 deletions(-) diff --git a/src/Umbraco.Web.UI.Client/src/views/propertyeditors/grid/editors/macro.controller.js b/src/Umbraco.Web.UI.Client/src/views/propertyeditors/grid/editors/macro.controller.js index 5c1d729364..5e66684ac5 100644 --- a/src/Umbraco.Web.UI.Client/src/views/propertyeditors/grid/editors/macro.controller.js +++ b/src/Umbraco.Web.UI.Client/src/views/propertyeditors/grid/editors/macro.controller.js @@ -1,57 +1,59 @@ angular.module("umbraco") .controller("Umbraco.PropertyEditors.Grid.MacroController", - function ($scope, $timeout, editorService, macroResource, macroService, $routeParams) { + function ($scope, $timeout, editorService, macroResource, macroService, localizationService, $routeParams) { - $scope.title = "Click to insert macro"; - - $scope.setMacro = function(){ - - var dialogData = { - richTextEditor: true, - macroData: $scope.control.value || { - macroAlias: $scope.control.editor.config && $scope.control.editor.config.macroAlias - ? $scope.control.editor.config.macroAlias : "" - } - }; - - var macroPicker = { - dialogData: dialogData, - submit: function(model) { - var macroObject = macroService.collectValueData(model.selectedMacro, model.macroParams, dialogData.renderingEngine); - - $scope.control.value = { - macroAlias: macroObject.macroAlias, - macroParamsDictionary: macroObject.macroParamsDictionary - }; - - $scope.setPreview($scope.control.value ); - editorService.close(); - }, - close: function() { - editorService.close(); - } - } - editorService.macroPicker(macroPicker); - }; - - $scope.setPreview = function(macro){ - var contentId = $routeParams.id; - - macroResource.getMacroResultAsHtmlForEditor(macro.macroAlias, contentId, macro.macroParamsDictionary) - .then(function (htmlResult) { - $scope.title = macro.macroAlias; - if(htmlResult.trim().length > 0 && htmlResult.indexOf("Macro:") < 0){ - $scope.preview = htmlResult; - } + localizationService.localize("grid_clickToInsertMacro").then(function(label) { + $scope.title = label; }); - }; + $scope.setMacro = function () { - $timeout(function(){ - if($scope.control.$initializing){ - $scope.setMacro(); - }else if($scope.control.value){ - $scope.setPreview($scope.control.value); - } - }, 200); -}); + var dialogData = { + richTextEditor: true, + macroData: $scope.control.value || { + macroAlias: $scope.control.editor.config && $scope.control.editor.config.macroAlias + ? $scope.control.editor.config.macroAlias : "" + } + }; + + var macroPicker = { + dialogData: dialogData, + submit: function (model) { + var macroObject = macroService.collectValueData(model.selectedMacro, model.macroParams, dialogData.renderingEngine); + + $scope.control.value = { + macroAlias: macroObject.macroAlias, + macroParamsDictionary: macroObject.macroParamsDictionary + }; + + $scope.setPreview($scope.control.value); + editorService.close(); + }, + close: function () { + editorService.close(); + } + } + editorService.macroPicker(macroPicker); + }; + + $scope.setPreview = function (macro) { + var contentId = $routeParams.id; + + macroResource.getMacroResultAsHtmlForEditor(macro.macroAlias, contentId, macro.macroParamsDictionary) + .then(function (htmlResult) { + $scope.title = macro.macroAlias; + if (htmlResult.trim().length > 0 && htmlResult.indexOf("Macro:") < 0) { + $scope.preview = htmlResult; + } + }); + + }; + + $timeout(function () { + if ($scope.control.$initializing) { + $scope.setMacro(); + } else if ($scope.control.value) { + $scope.setPreview($scope.control.value); + } + }, 200); + }); diff --git a/src/Umbraco.Web.UI/Umbraco/config/lang/en.xml b/src/Umbraco.Web.UI/Umbraco/config/lang/en.xml index 5865d39a75..4c92c2b293 100644 --- a/src/Umbraco.Web.UI/Umbraco/config/lang/en.xml +++ b/src/Umbraco.Web.UI/Umbraco/config/lang/en.xml @@ -1619,6 +1619,7 @@ To manage your website, simply open the Umbraco backoffice and start adding cont This content is allowed here Click to embed Click to insert image + Click to insert macro Image caption... Write here... Grid Layouts diff --git a/src/Umbraco.Web.UI/Umbraco/config/lang/en_us.xml b/src/Umbraco.Web.UI/Umbraco/config/lang/en_us.xml index 102f04371d..8ca225c48c 100644 --- a/src/Umbraco.Web.UI/Umbraco/config/lang/en_us.xml +++ b/src/Umbraco.Web.UI/Umbraco/config/lang/en_us.xml @@ -1637,6 +1637,7 @@ To manage your website, simply open the Umbraco backoffice and start adding cont This content is allowed here Click to embed Click to insert image + Click to insert macro Image caption... Write here... Grid Layouts @@ -1663,7 +1664,7 @@ To manage your website, simply open the Umbraco backoffice and start adding cont Set as default Choose extra Choose default - are added + are added Warning You are deleting the row configuration diff --git a/src/Umbraco.Web.UI/Umbraco/config/lang/fr.xml b/src/Umbraco.Web.UI/Umbraco/config/lang/fr.xml index 69e2189c67..86684678c9 100644 --- a/src/Umbraco.Web.UI/Umbraco/config/lang/fr.xml +++ b/src/Umbraco.Web.UI/Umbraco/config/lang/fr.xml @@ -1576,6 +1576,7 @@ Pour gérer votre site, ouvrez simplement le backoffice Umbraco et commencez à Ce contenu est autorisé ici Cliquez pour intégrer Cliquez pour insérer une image + Cliquez pour insérer une macro Légende de l'image... Ecrivez ici... Mises en pages de la Grid From 8ff88f47de07fee4c270d4afe44f2e2e1d31d532 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 6 May 2021 17:33:07 +0000 Subject: [PATCH 31/70] Bump lodash from 4.17.19 to 4.17.21 in /src/Umbraco.Web.UI.Client Bumps [lodash](https://github.com/lodash/lodash) from 4.17.19 to 4.17.21. - [Release notes](https://github.com/lodash/lodash/releases) - [Commits](https://github.com/lodash/lodash/compare/4.17.19...4.17.21) Signed-off-by: dependabot[bot] --- src/Umbraco.Web.UI.Client/package-lock.json | 10 +++++----- src/Umbraco.Web.UI.Client/package.json | 2 +- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/Umbraco.Web.UI.Client/package-lock.json b/src/Umbraco.Web.UI.Client/package-lock.json index 1b44664fac..0e8f48084f 100644 --- a/src/Umbraco.Web.UI.Client/package-lock.json +++ b/src/Umbraco.Web.UI.Client/package-lock.json @@ -1,6 +1,6 @@ { - "requires": true, - "lockfileVersion": 1, + "requires": true, + "lockfileVersion": 1, "dependencies": { "@babel/code-frame": { "version": "7.5.5", @@ -8717,9 +8717,9 @@ } }, "lodash": { - "version": "4.17.19", - "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.19.tgz", - "integrity": "sha512-JNvd8XER9GQX0v2qJgsaN/mzFCNA5BRe/j8JN9d+tWyGLSodKQHKFicdwNYzWwI3wjRnaKPsGj1XkBjx/F96DQ==", + "version": "4.17.21", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", + "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==", "dev": true }, "lodash._basecopy": { diff --git a/src/Umbraco.Web.UI.Client/package.json b/src/Umbraco.Web.UI.Client/package.json index dd9ba51138..95f5bcef49 100644 --- a/src/Umbraco.Web.UI.Client/package.json +++ b/src/Umbraco.Web.UI.Client/package.json @@ -82,7 +82,7 @@ "karma-junit-reporter": "2.0.1", "karma-spec-reporter": "0.0.32", "less": "3.10.3", - "lodash": "4.17.19", + "lodash": "4.17.21", "marked": "^0.7.0", "merge-stream": "2.0.0", "run-sequence": "2.2.1" From 96d37a5e64c0aafdef9ede5ca9db367b169e7d02 Mon Sep 17 00:00:00 2001 From: Chad Date: Tue, 11 May 2021 16:32:27 +1200 Subject: [PATCH 32/70] Fix copy button inactive, nodeSelectHandler had too many args passed. (#10158) --- .../src/views/content/content.copy.controller.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Umbraco.Web.UI.Client/src/views/content/content.copy.controller.js b/src/Umbraco.Web.UI.Client/src/views/content/content.copy.controller.js index eac489ab08..01526bb907 100644 --- a/src/Umbraco.Web.UI.Client/src/views/content/content.copy.controller.js +++ b/src/Umbraco.Web.UI.Client/src/views/content/content.copy.controller.js @@ -143,7 +143,7 @@ angular.module("umbraco").controller("Umbraco.Editors.Content.CopyController", // Mini list view $scope.selectListViewNode = function (node) { node.selected = node.selected === true ? false : true; - nodeSelectHandler({}, { node: node }); + nodeSelectHandler({ node: node }); }; $scope.closeMiniListView = function () { From f5406b9b2f764c6c45f35b1ff91961e9a38d57e9 Mon Sep 17 00:00:00 2001 From: Shannon Date: Tue, 20 Apr 2021 15:55:01 +1000 Subject: [PATCH 33/70] Updates to Examine 1.2.0 and removes ExecutionContext workaround since it's part of Examine now. --- build/NuSpecs/UmbracoCms.Web.nuspec | 2 +- src/Umbraco.Examine/Umbraco.Examine.csproj | 2 +- src/Umbraco.Examine/UmbracoExamineIndex.cs | 19 +++---------------- src/Umbraco.Tests/Umbraco.Tests.csproj | 2 +- src/Umbraco.Web.UI/Umbraco.Web.UI.csproj | 2 +- src/Umbraco.Web/Umbraco.Web.csproj | 4 ++-- 6 files changed, 9 insertions(+), 22 deletions(-) diff --git a/build/NuSpecs/UmbracoCms.Web.nuspec b/build/NuSpecs/UmbracoCms.Web.nuspec index d8815bab63..b0758e6ae4 100644 --- a/build/NuSpecs/UmbracoCms.Web.nuspec +++ b/build/NuSpecs/UmbracoCms.Web.nuspec @@ -28,7 +28,7 @@ - + diff --git a/src/Umbraco.Examine/Umbraco.Examine.csproj b/src/Umbraco.Examine/Umbraco.Examine.csproj index 517edf354c..39fbe927d4 100644 --- a/src/Umbraco.Examine/Umbraco.Examine.csproj +++ b/src/Umbraco.Examine/Umbraco.Examine.csproj @@ -49,7 +49,7 @@ - + 1.0.0-beta2-19324-01 runtime; build; native; contentfiles; analyzers; buildtransitive diff --git a/src/Umbraco.Examine/UmbracoExamineIndex.cs b/src/Umbraco.Examine/UmbracoExamineIndex.cs index 511d78db92..c9ab2cd446 100644 --- a/src/Umbraco.Examine/UmbracoExamineIndex.cs +++ b/src/Umbraco.Examine/UmbracoExamineIndex.cs @@ -25,8 +25,7 @@ namespace Umbraco.Examine // wrapping all operations that end up calling base.SafelyProcessQueueItems in a safe call // context because they will fork a thread/task/whatever which should *not* capture our // call context (and the database it can contain)! - // TODO: FIX Examine to not flow the ExecutionContext so callers don't need to worry about this! - + /// /// Used to store the path of a content object /// @@ -99,13 +98,7 @@ namespace Umbraco.Examine { if (CanInitialize()) { - // Use SafeCallContext to prevent the current CallContext flow to child - // tasks executed in the base class so we don't leak Scopes. - // TODO: See notes at the top of this class - using (new SafeCallContext()) - { - base.PerformDeleteFromIndex(itemIds, onComplete); - } + base.PerformDeleteFromIndex(itemIds, onComplete); } } @@ -113,13 +106,7 @@ namespace Umbraco.Examine { if (CanInitialize()) { - // Use SafeCallContext to prevent the current CallContext flow to child - // tasks executed in the base class so we don't leak Scopes. - // TODO: See notes at the top of this class - using (new SafeCallContext()) - { - base.PerformIndexItems(values, onComplete); - } + base.PerformIndexItems(values, onComplete); } } diff --git a/src/Umbraco.Tests/Umbraco.Tests.csproj b/src/Umbraco.Tests/Umbraco.Tests.csproj index 9d4bc4294c..242040836b 100644 --- a/src/Umbraco.Tests/Umbraco.Tests.csproj +++ b/src/Umbraco.Tests/Umbraco.Tests.csproj @@ -79,7 +79,7 @@ - + 1.8.14 diff --git a/src/Umbraco.Web.UI/Umbraco.Web.UI.csproj b/src/Umbraco.Web.UI/Umbraco.Web.UI.csproj index 58baadcb35..707c773dc6 100644 --- a/src/Umbraco.Web.UI/Umbraco.Web.UI.csproj +++ b/src/Umbraco.Web.UI/Umbraco.Web.UI.csproj @@ -88,7 +88,7 @@ - + diff --git a/src/Umbraco.Web/Umbraco.Web.csproj b/src/Umbraco.Web/Umbraco.Web.csproj index a6cbefa825..ecf0e65b70 100644 --- a/src/Umbraco.Web/Umbraco.Web.csproj +++ b/src/Umbraco.Web/Umbraco.Web.csproj @@ -63,7 +63,7 @@ - + 2.7.0.100 @@ -1306,4 +1306,4 @@ - + \ No newline at end of file From 17e43a6b099eb9a2d893ab96463d893b92d843ab Mon Sep 17 00:00:00 2001 From: Bjarne Fyrstenborg Date: Fri, 2 Apr 2021 16:19:08 +0200 Subject: [PATCH 34/70] Update to noUiSlider v14.6.4 --- src/Umbraco.Web.UI.Client/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Umbraco.Web.UI.Client/package.json b/src/Umbraco.Web.UI.Client/package.json index 95f5bcef49..16d6ff980b 100644 --- a/src/Umbraco.Web.UI.Client/package.json +++ b/src/Umbraco.Web.UI.Client/package.json @@ -41,7 +41,7 @@ "lazyload-js": "1.0.0", "moment": "2.22.2", "ng-file-upload": "12.2.13", - "nouislider": "14.6.3", + "nouislider": "14.6.4", "npm": "^6.14.7", "signalr": "2.4.0", "spectrum-colorpicker2": "2.0.8", From 499d22aa20901d3dafc5bd3c8b096f43bc54df13 Mon Sep 17 00:00:00 2001 From: Patrick de Mooij Date: Mon, 8 Feb 2021 12:58:10 +0100 Subject: [PATCH 35/70] Move the SetWeight logic to WeightedCollectionBuilderBase so other collections can use it too --- .../WeightedCollectionBuilderBase.cs | 16 +++++++++++++ .../Composing/CollectionBuildersTests.cs | 13 +++++++++++ .../Dashboards/DashboardCollectionBuilder.cs | 23 +------------------ 3 files changed, 30 insertions(+), 22 deletions(-) diff --git a/src/Umbraco.Core/Composing/WeightedCollectionBuilderBase.cs b/src/Umbraco.Core/Composing/WeightedCollectionBuilderBase.cs index 88eb61de76..b333fa646d 100644 --- a/src/Umbraco.Core/Composing/WeightedCollectionBuilderBase.cs +++ b/src/Umbraco.Core/Composing/WeightedCollectionBuilderBase.cs @@ -16,6 +16,8 @@ namespace Umbraco.Core.Composing { protected abstract TBuilder This { get; } + private readonly Dictionary _customWeights = new Dictionary(); + /// /// Clears all types in the collection. /// @@ -107,6 +109,18 @@ namespace Umbraco.Core.Composing return This; } + /// + /// Changes the default weight of an item + /// + /// The type of item + /// The new weight + /// + public TBuilder SetWeight(int weight) where T : TItem + { + _customWeights[typeof(T)] = weight; + return This; + } + protected override IEnumerable GetRegisteringTypes(IEnumerable types) { var list = types.ToList(); @@ -118,6 +132,8 @@ namespace Umbraco.Core.Composing protected virtual int GetWeight(Type type) { + if (_customWeights.ContainsKey(type)) + return _customWeights[type]; var attr = type.GetCustomAttributes(typeof(WeightAttribute), false).OfType().SingleOrDefault(); return attr?.Weight ?? DefaultWeight; } diff --git a/src/Umbraco.Tests/Composing/CollectionBuildersTests.cs b/src/Umbraco.Tests/Composing/CollectionBuildersTests.cs index 1d8390e07e..87971360de 100644 --- a/src/Umbraco.Tests/Composing/CollectionBuildersTests.cs +++ b/src/Umbraco.Tests/Composing/CollectionBuildersTests.cs @@ -442,6 +442,19 @@ namespace Umbraco.Tests.Composing AssertCollection(col, typeof(Resolved2), typeof(Resolved1)); } + [Test] + public void WeightedBuilderSetWeight() + { + var builder = _composition.WithCollectionBuilder() + .Add() + .Add(); + builder.SetWeight(10); + + var factory = _composition.CreateFactory(); + var col = builder.CreateCollection(factory); + AssertCollection(col, typeof(Resolved1), typeof(Resolved2)); + } + #region Assertions private static void AssertCollection(IEnumerable col, params Type[] expected) diff --git a/src/Umbraco.Web/Dashboards/DashboardCollectionBuilder.cs b/src/Umbraco.Web/Dashboards/DashboardCollectionBuilder.cs index 1c05da8906..37697d848c 100644 --- a/src/Umbraco.Web/Dashboards/DashboardCollectionBuilder.cs +++ b/src/Umbraco.Web/Dashboards/DashboardCollectionBuilder.cs @@ -10,22 +10,8 @@ namespace Umbraco.Web.Dashboards { public class DashboardCollectionBuilder : WeightedCollectionBuilderBase { - private Dictionary _customWeights = new Dictionary(); - protected override DashboardCollectionBuilder This => this; - /// - /// Changes the default weight of a dashboard - /// - /// The type of dashboard - /// The new dashboard weight - /// - public DashboardCollectionBuilder SetWeight(int weight) where T : IDashboard - { - _customWeights[typeof(T)] = weight; - return this; - } - protected override IEnumerable CreateItems(IFactory factory) { // get the manifest parser just-in-time - injecting it in the ctor would mean that @@ -47,20 +33,13 @@ namespace Umbraco.Web.Dashboards private int GetWeight(IDashboard dashboard) { - var typeOfDashboard = dashboard.GetType(); - if(_customWeights.ContainsKey(typeOfDashboard)) - { - return _customWeights[typeOfDashboard]; - } - switch (dashboard) { case ManifestDashboard manifestDashboardDefinition: return manifestDashboardDefinition.Weight; default: - var weightAttribute = dashboard.GetType().GetCustomAttribute(false); - return weightAttribute?.Weight ?? DefaultWeight; + return GetWeight(dashboard.GetType()); } } } From 980d9ad5cfbfb60abd475473548ad46063ffea8e Mon Sep 17 00:00:00 2001 From: Adam Nelson Date: Wed, 12 May 2021 12:36:13 +1000 Subject: [PATCH 36/70] #10193 The listview search within a dialog (eg. minilistview) shows the loading indicator forever for zero results (#10202) * The listview search within a dialog (eg. minilistview) shows the loading indicator forever for zero results #10193 * Updated comment. * Another updated comment. Co-authored-by: Adam Nelson --- .../directives/components/umbminilistview.directive.js | 3 +++ .../src/views/components/umb-mini-list-view.html | 8 ++++---- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/src/Umbraco.Web.UI.Client/src/common/directives/components/umbminilistview.directive.js b/src/Umbraco.Web.UI.Client/src/common/directives/components/umbminilistview.directive.js index 783cd7f90a..f7b634a710 100644 --- a/src/Umbraco.Web.UI.Client/src/common/directives/components/umbminilistview.directive.js +++ b/src/Umbraco.Web.UI.Client/src/common/directives/components/umbminilistview.directive.js @@ -58,6 +58,9 @@ entityResource.getPagedChildren(miniListView.node.id, scope.entityType, miniListView.pagination) .then(function (data) { + if (!data.items) { + data.items = []; + } if (scope.onItemsLoaded) { scope.onItemsLoaded({items: data.items}); } diff --git a/src/Umbraco.Web.UI.Client/src/views/components/umb-mini-list-view.html b/src/Umbraco.Web.UI.Client/src/views/components/umb-mini-list-view.html index 6ec8b08da6..e2319f099d 100644 --- a/src/Umbraco.Web.UI.Client/src/views/components/umb-mini-list-view.html +++ b/src/Umbraco.Web.UI.Client/src/views/components/umb-mini-list-view.html @@ -74,14 +74,14 @@
      {{ child.name }}
      - -
      + +
      No items have been added Sorry, we can not find what you are looking for.
      - -
      + +
      From 474a76fd2b954fbc385a9080e1c316259297ff36 Mon Sep 17 00:00:00 2001 From: Chad Currie Date: Sat, 15 May 2021 20:23:24 +1200 Subject: [PATCH 37/70] Use ContainsKey for Dictionaries. O(1) --- src/Umbraco.Core/Models/Entities/BeingDirtyBase.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Umbraco.Core/Models/Entities/BeingDirtyBase.cs b/src/Umbraco.Core/Models/Entities/BeingDirtyBase.cs index a1f4bad9a1..65aafafbcd 100644 --- a/src/Umbraco.Core/Models/Entities/BeingDirtyBase.cs +++ b/src/Umbraco.Core/Models/Entities/BeingDirtyBase.cs @@ -29,7 +29,7 @@ namespace Umbraco.Core.Models.Entities /// public virtual bool IsPropertyDirty(string propertyName) { - return _currentChanges != null && _currentChanges.Any(x => x.Key == propertyName); + return _currentChanges != null && _currentChanges.ContainsKey(propertyName); } /// @@ -61,7 +61,7 @@ namespace Umbraco.Core.Models.Entities /// public virtual bool WasPropertyDirty(string propertyName) { - return _savedChanges != null && _savedChanges.Any(x => x.Key == propertyName); + return _savedChanges != null && _savedChanges.ContainsKey(propertyName); } /// From aaf5cd5faeed798f5b508d2c999405160e7fc6a5 Mon Sep 17 00:00:00 2001 From: Paul Seal Date: Fri, 14 May 2021 10:02:46 +0100 Subject: [PATCH 38/70] Added a link to 404 documentation I think it will be useful to include a link to the documentation on how to create a custom 404 --- src/Umbraco.Web/Routing/PublishedContentNotFoundHandler.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Umbraco.Web/Routing/PublishedContentNotFoundHandler.cs b/src/Umbraco.Web/Routing/PublishedContentNotFoundHandler.cs index 0045cf33dc..a6e4f4b450 100644 --- a/src/Umbraco.Web/Routing/PublishedContentNotFoundHandler.cs +++ b/src/Umbraco.Web/Routing/PublishedContentNotFoundHandler.cs @@ -42,7 +42,7 @@ namespace Umbraco.Web.Routing response.Write(""); if (string.IsNullOrWhiteSpace(_message) == false) response.Write("

      " + _message + "

      "); - response.Write("

      This page can be replaced with a custom 404. Check the documentation for \"custom 404\".

      "); + response.Write("

      This page can be replaced with a custom 404. Check the documentation for Custom 404 Error Pages.

      "); response.Write("

      This page is intentionally left ugly ;-)

      "); response.Write(""); } From cce3c49e78db32ecca916a0824783af6f4bca859 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 6 May 2021 20:34:33 +0000 Subject: [PATCH 39/70] Bump underscore from 1.9.1 to 1.12.1 in /src/Umbraco.Web.UI.Client Bumps [underscore](https://github.com/jashkenas/underscore) from 1.9.1 to 1.12.1. - [Release notes](https://github.com/jashkenas/underscore/releases) - [Commits](https://github.com/jashkenas/underscore/compare/1.9.1...1.12.1) Signed-off-by: dependabot[bot] --- src/Umbraco.Web.UI.Client/package-lock.json | 6 +++--- src/Umbraco.Web.UI.Client/package.json | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/Umbraco.Web.UI.Client/package-lock.json b/src/Umbraco.Web.UI.Client/package-lock.json index 0e8f48084f..3f53638fc6 100644 --- a/src/Umbraco.Web.UI.Client/package-lock.json +++ b/src/Umbraco.Web.UI.Client/package-lock.json @@ -15755,9 +15755,9 @@ "dev": true }, "underscore": { - "version": "1.9.1", - "resolved": "https://registry.npmjs.org/underscore/-/underscore-1.9.1.tgz", - "integrity": "sha1-BtzjSg5op7q8KbNluOdLiSUgOWE=" + "version": "1.12.1", + "resolved": "https://registry.npmjs.org/underscore/-/underscore-1.12.1.tgz", + "integrity": "sha512-hEQt0+ZLDVUMhebKxL4x1BTtDY7bavVofhZ9KZ4aI26X9SRaE+Y3m83XUL1UP2jn8ynjndwCCpEHdUG+9pP1Tw==" }, "undertaker": { "version": "1.2.1", diff --git a/src/Umbraco.Web.UI.Client/package.json b/src/Umbraco.Web.UI.Client/package.json index 16d6ff980b..6514f2f217 100644 --- a/src/Umbraco.Web.UI.Client/package.json +++ b/src/Umbraco.Web.UI.Client/package.json @@ -47,7 +47,7 @@ "spectrum-colorpicker2": "2.0.8", "tinymce": "4.9.11", "typeahead.js": "0.11.1", - "underscore": "1.9.1", + "underscore": "1.12.1", "wicg-inert": "^3.0.2" }, "devDependencies": { From df8b2d5580bf8589119b629ff5870122728cc96c Mon Sep 17 00:00:00 2001 From: Sebastiaan Janssen Date: Mon, 17 May 2021 10:50:25 +0200 Subject: [PATCH 40/70] Bump version to 8.14.0-rc --- src/SolutionInfo.cs | 4 ++-- src/Umbraco.Web.UI/Umbraco.Web.UI.csproj | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/SolutionInfo.cs b/src/SolutionInfo.cs index 2a7386cb45..91918498f9 100644 --- a/src/SolutionInfo.cs +++ b/src/SolutionInfo.cs @@ -18,5 +18,5 @@ using System.Resources; [assembly: AssemblyVersion("8.0.0")] // these are FYI and changed automatically -[assembly: AssemblyFileVersion("8.13.0")] -[assembly: AssemblyInformationalVersion("8.13.0-rc")] +[assembly: AssemblyFileVersion("8.14.0")] +[assembly: AssemblyInformationalVersion("8.14.0-rc")] diff --git a/src/Umbraco.Web.UI/Umbraco.Web.UI.csproj b/src/Umbraco.Web.UI/Umbraco.Web.UI.csproj index 707c773dc6..a887159256 100644 --- a/src/Umbraco.Web.UI/Umbraco.Web.UI.csproj +++ b/src/Umbraco.Web.UI/Umbraco.Web.UI.csproj @@ -348,9 +348,9 @@ False True - 8130 + 8140 / - http://localhost:8130 + http://localhost:8140 False False From e19a5989e9a9c77f1d35622fe70b0fe573df59c9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Niels=20Lyngs=C3=B8?= Date: Tue, 18 May 2021 11:08:00 +0200 Subject: [PATCH 41/70] #10274 Variant sorting should take into account that there might not be any language (#10278) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Variant sorting should take into account that there might not be any language available * fix languages Co-authored-by: Niels Lyngsø Co-authored-by: Mads Rasmussen --- .../services/contenteditinghelper.service.js | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/src/Umbraco.Web.UI.Client/src/common/services/contenteditinghelper.service.js b/src/Umbraco.Web.UI.Client/src/common/services/contenteditinghelper.service.js index bab665579c..67e466af35 100644 --- a/src/Umbraco.Web.UI.Client/src/common/services/contenteditinghelper.service.js +++ b/src/Umbraco.Web.UI.Client/src/common/services/contenteditinghelper.service.js @@ -789,10 +789,10 @@ function contentEditingHelper(fileManager, $q, $location, $routeParams, editorSt */ sortVariants: function (a, b) { const statesOrder = {'PublishedPendingChanges':1, 'Published': 1, 'Draft': 2, 'NotCreated': 3}; - const compareDefault = (a,b) => (!a.language.isDefault ? 1 : -1) - (!b.language.isDefault ? 1 : -1); + const compareDefault = (a,b) => (a.language && a.language.isDefault ? -1 : 1) - (b.language && b.language.isDefault ? -1 : 1); // Make sure mandatory variants goes on top, unless they are published, cause then they already goes to the top and then we want to mix them with other published variants. - const compareMandatory = (a,b) => (a.state === 'PublishedPendingChanges' || a.state === 'Published') ? 0 : (!a.language.isMandatory ? 1 : -1) - (!b.language.isMandatory ? 1 : -1); + const compareMandatory = (a,b) => (a.state === 'PublishedPendingChanges' || a.state === 'Published') ? 0 : (a.language && a.language.isMandatory ? -1 : 1) - (b.language && b.language.isMandatory ? -1 : 1); const compareState = (a, b) => (statesOrder[a.state] || 99) - (statesOrder[b.state] || 99); const compareName = (a, b) => a.displayName.localeCompare(b.displayName); @@ -813,17 +813,18 @@ function contentEditingHelper(fileManager, $q, $location, $routeParams, editorSt */ getSortedVariantsAndSegments: function (variantsAndSegments) { const sortedVariants = variantsAndSegments.filter(variant => !variant.segment).sort(this.sortVariants); - let segments = variantsAndSegments.filter(variant => variant.segment); + let variantsWithSegments = variantsAndSegments.filter(variant => variant.segment); let sortedAvailableVariants = []; sortedVariants.forEach((variant) => { - const sortedMatchedSegments = segments.filter(segment => segment.language.culture === variant.language.culture).sort(this.sortVariants); - segments = segments.filter(segment => segment.language.culture !== variant.language.culture); + const sortedMatchedSegments = variantsWithSegments.filter(segment => segment.language && variant.language && segment.language.culture === variant.language.culture).sort(this.sortVariants); + // remove variants for this culture + variantsWithSegments = variantsWithSegments.filter(segment => !segment.language || segment.language && variant.language && segment.language.culture !== variant.language.culture); sortedAvailableVariants = [...sortedAvailableVariants, ...[variant], ...sortedMatchedSegments]; }) - // if we have segments without a parent language variant we need to add the remaining segments to the array - sortedAvailableVariants = [...sortedAvailableVariants, ...segments.sort(this.sortVariants)]; + // if we have segments without a parent language variant we need to add the remaining variantsWithSegments to the array + sortedAvailableVariants = [...sortedAvailableVariants, ...variantsWithSegments.sort(this.sortVariants)]; return sortedAvailableVariants; } From 36c49b0a2592758e2f525588047fe3b89b976844 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Niels=20Lyngs=C3=B8?= Date: Tue, 18 May 2021 11:08:00 +0200 Subject: [PATCH 42/70] #10274 Variant sorting should take into account that there might not be any language (#10278) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Variant sorting should take into account that there might not be any language available * fix languages Co-authored-by: Niels Lyngsø Co-authored-by: Mads Rasmussen (cherry picked from commit e19a5989e9a9c77f1d35622fe70b0fe573df59c9) --- .../services/contenteditinghelper.service.js | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/src/Umbraco.Web.UI.Client/src/common/services/contenteditinghelper.service.js b/src/Umbraco.Web.UI.Client/src/common/services/contenteditinghelper.service.js index 8524b960c6..26f8dc86ea 100644 --- a/src/Umbraco.Web.UI.Client/src/common/services/contenteditinghelper.service.js +++ b/src/Umbraco.Web.UI.Client/src/common/services/contenteditinghelper.service.js @@ -775,10 +775,10 @@ function contentEditingHelper(fileManager, $q, $location, $routeParams, editorSt */ sortVariants: function (a, b) { const statesOrder = {'PublishedPendingChanges':1, 'Published': 1, 'Draft': 2, 'NotCreated': 3}; - const compareDefault = (a,b) => (!a.language.isDefault ? 1 : -1) - (!b.language.isDefault ? 1 : -1); + const compareDefault = (a,b) => (a.language && a.language.isDefault ? -1 : 1) - (b.language && b.language.isDefault ? -1 : 1); // Make sure mandatory variants goes on top, unless they are published, cause then they already goes to the top and then we want to mix them with other published variants. - const compareMandatory = (a,b) => (a.state === 'PublishedPendingChanges' || a.state === 'Published') ? 0 : (!a.language.isMandatory ? 1 : -1) - (!b.language.isMandatory ? 1 : -1); + const compareMandatory = (a,b) => (a.state === 'PublishedPendingChanges' || a.state === 'Published') ? 0 : (a.language && a.language.isMandatory ? -1 : 1) - (b.language && b.language.isMandatory ? -1 : 1); const compareState = (a, b) => (statesOrder[a.state] || 99) - (statesOrder[b.state] || 99); const compareName = (a, b) => a.displayName.localeCompare(b.displayName); @@ -799,17 +799,18 @@ function contentEditingHelper(fileManager, $q, $location, $routeParams, editorSt */ getSortedVariantsAndSegments: function (variantsAndSegments) { const sortedVariants = variantsAndSegments.filter(variant => !variant.segment).sort(this.sortVariants); - let segments = variantsAndSegments.filter(variant => variant.segment); + let variantsWithSegments = variantsAndSegments.filter(variant => variant.segment); let sortedAvailableVariants = []; sortedVariants.forEach((variant) => { - const sortedMatchedSegments = segments.filter(segment => segment.language.culture === variant.language.culture).sort(this.sortVariants); - segments = segments.filter(segment => segment.language.culture !== variant.language.culture); + const sortedMatchedSegments = variantsWithSegments.filter(segment => segment.language && variant.language && segment.language.culture === variant.language.culture).sort(this.sortVariants); + // remove variants for this culture + variantsWithSegments = variantsWithSegments.filter(segment => !segment.language || segment.language && variant.language && segment.language.culture !== variant.language.culture); sortedAvailableVariants = [...sortedAvailableVariants, ...[variant], ...sortedMatchedSegments]; }) - // if we have segments without a parent language variant we need to add the remaining segments to the array - sortedAvailableVariants = [...sortedAvailableVariants, ...segments.sort(this.sortVariants)]; + // if we have segments without a parent language variant we need to add the remaining variantsWithSegments to the array + sortedAvailableVariants = [...sortedAvailableVariants, ...variantsWithSegments.sort(this.sortVariants)]; return sortedAvailableVariants; } From 7c2f95613030b2e52f3ce66629916ef095ac3601 Mon Sep 17 00:00:00 2001 From: Mike Chambers Date: Tue, 27 Apr 2021 13:56:31 +0100 Subject: [PATCH 43/70] Update ModelsBuilderComposer.cs issue #10186 typo in IsExternalModelsBuilderInstalled -> Umbraco.ModelsBuider (cherry picked from commit b783399c5cd730cfcbff3fdcedf2f7a4ab2eb25c) --- .../Compose/ModelsBuilderComposer.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Umbraco.ModelsBuilder.Embedded/Compose/ModelsBuilderComposer.cs b/src/Umbraco.ModelsBuilder.Embedded/Compose/ModelsBuilderComposer.cs index 01010cca66..fee9b6f62e 100644 --- a/src/Umbraco.ModelsBuilder.Embedded/Compose/ModelsBuilderComposer.cs +++ b/src/Umbraco.ModelsBuilder.Embedded/Compose/ModelsBuilderComposer.cs @@ -47,7 +47,7 @@ namespace Umbraco.ModelsBuilder.Embedded.Compose { var assemblyNames = new[] { - "Umbraco.ModelsBuider", + "Umbraco.ModelsBuilder", "ModelsBuilder.Umbraco" }; From 9730a18c9b3bad19d9415af49e17977bda375ae8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Niels=20Lyngs=C3=B8?= Date: Wed, 19 May 2021 12:06:17 +0200 Subject: [PATCH 44/70] #10274 Variant sorting should take into account that there might not be any language (#10278) (#10284) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Niels Lyngsø Co-authored-by: Mads Rasmussen (cherry picked from commit 017b56eee1b45cdca44e14510e72dd675412b0b5) --- .../forms/umbfocuslock.directive.js | 69 ++++++++++--------- 1 file changed, 38 insertions(+), 31 deletions(-) diff --git a/src/Umbraco.Web.UI.Client/src/common/directives/components/forms/umbfocuslock.directive.js b/src/Umbraco.Web.UI.Client/src/common/directives/components/forms/umbfocuslock.directive.js index 03d376e36a..e1639dde26 100644 --- a/src/Umbraco.Web.UI.Client/src/common/directives/components/forms/umbfocuslock.directive.js +++ b/src/Umbraco.Web.UI.Client/src/common/directives/components/forms/umbfocuslock.directive.js @@ -40,7 +40,9 @@ function getDomNodes(){ infiniteEditorsWrapper = document.querySelector('.umb-editors'); - infiniteEditors = Array.from(infiniteEditorsWrapper.querySelectorAll('.umb-editor')); + if(infiniteEditorsWrapper) { + infiniteEditors = Array.from(infiniteEditorsWrapper.querySelectorAll('.umb-editor') || []); + } } function getFocusableElements(targetElm) { @@ -84,22 +86,24 @@ var defaultFocusedElement = getAutoFocusElement(focusableElements); var lastKnownElement; - // If an inifite editor is being closed then we reset the focus to the element that triggered the the overlay + // If an infinite editor is being closed then we reset the focus to the element that triggered the the overlay if(closingEditor){ - var lastItemIndex = $rootScope.lastKnownFocusableElements.length - 1; - var editorInfo = infiniteEditors[0].querySelector('.editor-info'); // If there is only one editor open, search for the "editor-info" inside it and set focus on it // This is relevant when a property editor has been selected and the editor where we selected it from // is closed taking us back to the first layer // Otherwise set it to the last element in the lastKnownFocusedElements array - if(infiniteEditors.length === 1 && editorInfo !== null){ - lastKnownElement = editorInfo; + if(infiniteEditors && infiniteEditors.length === 1){ + var editorInfo = infiniteEditors[0].querySelector('.editor-info'); + if(infiniteEditors && infiniteEditors.length === 1 && editorInfo !== null) { + lastKnownElement = editorInfo; - // Clear the array - clearLastKnownFocusedElements(); + // Clear the array + clearLastKnownFocusedElements(); + } } else { + var lastItemIndex = $rootScope.lastKnownFocusableElements.length - 1; lastKnownElement = $rootScope.lastKnownFocusableElements[lastItemIndex]; // Remove the last item from the array so we always set the correct lastKnowFocus for each layer @@ -149,20 +153,24 @@ } function cleanupEventHandlers() { - var activeEditor = infiniteEditors[infiniteEditors.length - 1]; - var inactiveEditors = infiniteEditors.filter(editor => editor !== activeEditor); + //if we're in infinite editing mode + if(infiniteEditors.length > 0) { + var activeEditor = infiniteEditors[infiniteEditors.length - 1]; + var inactiveEditors = infiniteEditors.filter(editor => editor !== activeEditor); - if(inactiveEditors.length > 0) { - for (var index = 0; index < inactiveEditors.length; index++) { - var inactiveEditor = inactiveEditors[index]; + if(inactiveEditors.length > 0) { + for (var index = 0; index < inactiveEditors.length; index++) { + var inactiveEditor = inactiveEditors[index]; - // Remove event handlers from inactive editors - inactiveEditor.removeEventListener('keydown', handleKeydown); + // Remove event handlers from inactive editors + inactiveEditor.removeEventListener('keydown', handleKeydown); + } + } + else { + // Why is this one only begin called if there is no other infinite editors, wouldn't it make sense always to clean this up? + // Remove event handlers from the active editor + activeEditor.removeEventListener('keydown', handleKeydown); } - } - else { - // Remove event handlers from the active editor - activeEditor.removeEventListener('keydown', handleKeydown); } } @@ -173,10 +181,7 @@ // Fetch the DOM nodes we need getDomNodes(); - // Cleanup event handlers if we're in infinite editing mode - if(infiniteEditors.length > 0){ - cleanupEventHandlers(); - } + cleanupEventHandlers(); getFocusableElements(targetElm); @@ -204,17 +209,19 @@ // Make sure to disconnect the observer so we potentially don't end up with having many active ones disconnectObserver = true; - // Pass the correct editor in order to find the focusable elements - var newTarget = infiniteEditors[infiniteEditors.length - 2]; + if(infiniteEditors && infiniteEditors.length > 1) { + // Pass the correct editor in order to find the focusable elements + var newTarget = infiniteEditors[infiniteEditors.length - 2]; - if(infiniteEditors.length > 1){ - // Setting closing till true will let us re-apply the last known focus to then opened layer that then becomes - // active - closingEditor = true; + if(infiniteEditors.length > 1) { + // Setting closing till true will let us re-apply the last known focus to then opened layer that then becomes + // active + closingEditor = true; - onInit(newTarget); + onInit(newTarget); - return; + return; + } } // Clear lastKnownFocusableElements From 3f596e27ccba6f30bd17779a94a41f9633d6f68e Mon Sep 17 00:00:00 2001 From: Sebastiaan Janssen Date: Wed, 19 May 2021 16:31:52 +0200 Subject: [PATCH 45/70] Bump version to 8.13.1 --- src/SolutionInfo.cs | 4 ++-- src/Umbraco.Web.UI/Umbraco.Web.UI.csproj | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/SolutionInfo.cs b/src/SolutionInfo.cs index 1009ec125b..451a4b0d77 100644 --- a/src/SolutionInfo.cs +++ b/src/SolutionInfo.cs @@ -18,5 +18,5 @@ using System.Resources; [assembly: AssemblyVersion("8.0.0")] // these are FYI and changed automatically -[assembly: AssemblyFileVersion("8.13.0")] -[assembly: AssemblyInformationalVersion("8.13.0")] +[assembly: AssemblyFileVersion("8.13.1")] +[assembly: AssemblyInformationalVersion("8.13.1")] diff --git a/src/Umbraco.Web.UI/Umbraco.Web.UI.csproj b/src/Umbraco.Web.UI/Umbraco.Web.UI.csproj index 58baadcb35..f69fdf7026 100644 --- a/src/Umbraco.Web.UI/Umbraco.Web.UI.csproj +++ b/src/Umbraco.Web.UI/Umbraco.Web.UI.csproj @@ -348,9 +348,9 @@ False True - 8130 + 8131 / - http://localhost:8130 + http://localhost:8131 False False From 9bf01741b64bdbd43ced0d6ed28d20c450e330e8 Mon Sep 17 00:00:00 2001 From: Sebastiaan Janssen Date: Thu, 20 May 2021 09:29:45 +0200 Subject: [PATCH 46/70] Fix invalid XML --- src/Umbraco.Web.UI/Umbraco/config/lang/da.xml | 1 - 1 file changed, 1 deletion(-) diff --git a/src/Umbraco.Web.UI/Umbraco/config/lang/da.xml b/src/Umbraco.Web.UI/Umbraco/config/lang/da.xml index 08448fa355..8e33f102c7 100644 --- a/src/Umbraco.Web.UI/Umbraco/config/lang/da.xml +++ b/src/Umbraco.Web.UI/Umbraco/config/lang/da.xml @@ -1907,7 +1907,6 @@ Mange hilsner fra Umbraco robotten Tilføj indhold Tilføj %0% Feltet %0% bruger editor %1% som ikke er supporteret for blokke. - Hvad er Indholdsskabeloner? From 71a1817a061983bbdb0d8ece856a634e4f028ff2 Mon Sep 17 00:00:00 2001 From: Andy Butland Date: Tue, 11 May 2021 17:28:11 +0200 Subject: [PATCH 47/70] Fixed issue with data types not being cleared in cache refresh operations. --- src/Umbraco.Web/Cache/DataTypeCacheRefresher.cs | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/Umbraco.Web/Cache/DataTypeCacheRefresher.cs b/src/Umbraco.Web/Cache/DataTypeCacheRefresher.cs index c9caf5aaa7..37d36fca45 100644 --- a/src/Umbraco.Web/Cache/DataTypeCacheRefresher.cs +++ b/src/Umbraco.Web/Cache/DataTypeCacheRefresher.cs @@ -3,6 +3,7 @@ using Umbraco.Core; using Umbraco.Core.Cache; using Umbraco.Core.Models; using Umbraco.Core.Models.PublishedContent; +using Umbraco.Core.Persistence.Repositories.Implement; using Umbraco.Core.PropertyEditors.ValueConverters; using Umbraco.Core.Services; using Umbraco.Web.PublishedCache; @@ -56,6 +57,11 @@ namespace Umbraco.Web.Cache foreach (var payload in payloads) { _idkMap.ClearCache(payload.Id); + + if (dataTypeCache.Success) + { + dataTypeCache.Result.Clear(RepositoryCacheKeys.GetKey(payload.Id)); + } } // TODO: not sure I like these? From 12328ba2f761b4c20b50df3dc83bb85b5f652cf6 Mon Sep 17 00:00:00 2001 From: Andy Butland Date: Tue, 11 May 2021 17:28:11 +0200 Subject: [PATCH 48/70] Fixed issue with data types not being cleared in cache refresh operations. (cherry picked from commit 71a1817a061983bbdb0d8ece856a634e4f028ff2) --- src/Umbraco.Web/Cache/DataTypeCacheRefresher.cs | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/Umbraco.Web/Cache/DataTypeCacheRefresher.cs b/src/Umbraco.Web/Cache/DataTypeCacheRefresher.cs index c9caf5aaa7..37d36fca45 100644 --- a/src/Umbraco.Web/Cache/DataTypeCacheRefresher.cs +++ b/src/Umbraco.Web/Cache/DataTypeCacheRefresher.cs @@ -3,6 +3,7 @@ using Umbraco.Core; using Umbraco.Core.Cache; using Umbraco.Core.Models; using Umbraco.Core.Models.PublishedContent; +using Umbraco.Core.Persistence.Repositories.Implement; using Umbraco.Core.PropertyEditors.ValueConverters; using Umbraco.Core.Services; using Umbraco.Web.PublishedCache; @@ -56,6 +57,11 @@ namespace Umbraco.Web.Cache foreach (var payload in payloads) { _idkMap.ClearCache(payload.Id); + + if (dataTypeCache.Success) + { + dataTypeCache.Result.Clear(RepositoryCacheKeys.GetKey(payload.Id)); + } } // TODO: not sure I like these? From 008480a17b652bc2c267ab2bfd68c4ae70162394 Mon Sep 17 00:00:00 2001 From: Sebastiaan Janssen Date: Fri, 21 May 2021 15:01:51 +0200 Subject: [PATCH 49/70] Can't use optimized version of this method call until 8.14 --- src/Umbraco.Web/Cache/DataTypeCacheRefresher.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Umbraco.Web/Cache/DataTypeCacheRefresher.cs b/src/Umbraco.Web/Cache/DataTypeCacheRefresher.cs index 37d36fca45..431f560400 100644 --- a/src/Umbraco.Web/Cache/DataTypeCacheRefresher.cs +++ b/src/Umbraco.Web/Cache/DataTypeCacheRefresher.cs @@ -60,7 +60,7 @@ namespace Umbraco.Web.Cache if (dataTypeCache.Success) { - dataTypeCache.Result.Clear(RepositoryCacheKeys.GetKey(payload.Id)); + dataTypeCache.Result.Clear(RepositoryCacheKeys.GetKey(payload.Id)); } } From ecdc687e39846908f44552d3c65de2dbc6cbafa4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Niels=20Lyngs=C3=B8?= Date: Tue, 25 May 2021 15:02:55 +0200 Subject: [PATCH 50/70] use label --- .../infiniteeditors/mediaentryeditor/mediaentryeditor.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Umbraco.Web.UI.Client/src/views/common/infiniteeditors/mediaentryeditor/mediaentryeditor.html b/src/Umbraco.Web.UI.Client/src/views/common/infiniteeditors/mediaentryeditor/mediaentryeditor.html index afa3451899..f4302551ab 100644 --- a/src/Umbraco.Web.UI.Client/src/views/common/infiniteeditors/mediaentryeditor/mediaentryeditor.html +++ b/src/Umbraco.Web.UI.Client/src/views/common/infiniteeditors/mediaentryeditor/mediaentryeditor.html @@ -35,7 +35,7 @@ width="{{crop.width}}" max-size="75"> - {{crop.alias}} + {{crop.label}}
      From a68a6b2ac29ea4eab94b92101c301ce60af979d8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Niels=20Lyngs=C3=B8?= Date: Tue, 25 May 2021 14:58:07 +0200 Subject: [PATCH 51/70] added windowResizeListener --- .../directives/components/imaging/umbimagecrop.directive.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Umbraco.Web.UI.Client/src/common/directives/components/imaging/umbimagecrop.directive.js b/src/Umbraco.Web.UI.Client/src/common/directives/components/imaging/umbimagecrop.directive.js index 744e4280db..60ba71d7a5 100644 --- a/src/Umbraco.Web.UI.Client/src/common/directives/components/imaging/umbimagecrop.directive.js +++ b/src/Umbraco.Web.UI.Client/src/common/directives/components/imaging/umbimagecrop.directive.js @@ -26,7 +26,7 @@ angular.module("umbraco.directives") forceUpdate: '@?' }, - link: function (scope, element, attrs) { + link: function (scope, element, attrs, windowResizeListener) { var unsubscribe = []; let sliderRef = null; From 630fa6a98906fa005d8eb796255594e97e6d2058 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Niels=20Lyngs=C3=B8?= Date: Tue, 25 May 2021 14:57:19 +0200 Subject: [PATCH 52/70] dont remove outline --- .../src/less/components/umb-range-slider.less | 1 - 1 file changed, 1 deletion(-) diff --git a/src/Umbraco.Web.UI.Client/src/less/components/umb-range-slider.less b/src/Umbraco.Web.UI.Client/src/less/components/umb-range-slider.less index cc5c17ba70..6c1980a6e4 100644 --- a/src/Umbraco.Web.UI.Client/src/less/components/umb-range-slider.less +++ b/src/Umbraco.Web.UI.Client/src/less/components/umb-range-slider.less @@ -19,7 +19,6 @@ padding: 2px 6px; } .umb-range-slider .noUi-handle { - outline: none; cursor: grab; border-radius: 100px; border: none; From 0a9c1c7c8ebc899525ac5b0333be39704419ded9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Niels=20Lyngs=C3=B8?= Date: Wed, 26 May 2021 13:08:25 +0200 Subject: [PATCH 53/70] Complex validation for RTE property editor (#10328) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Niels Lyngsø --- .../services/contenteditinghelper.service.js | 2 -- .../src/common/services/tinymce.service.js | 36 ++++++++++++------- .../propertyeditors/rte/rte.controller.js | 36 +++++++++---------- .../src/views/propertyeditors/rte/rte.html | 10 +++--- 4 files changed, 48 insertions(+), 36 deletions(-) diff --git a/src/Umbraco.Web.UI.Client/src/common/services/contenteditinghelper.service.js b/src/Umbraco.Web.UI.Client/src/common/services/contenteditinghelper.service.js index 67e466af35..faa0d2a3c0 100644 --- a/src/Umbraco.Web.UI.Client/src/common/services/contenteditinghelper.service.js +++ b/src/Umbraco.Web.UI.Client/src/common/services/contenteditinghelper.service.js @@ -48,8 +48,6 @@ function contentEditingHelper(fileManager, $q, $location, $routeParams, editorSt }); } else if (value[0]) { - //notificationsService.error("Validation", value[0]); - console.log({type:messageType, header:"Validation", message:value[0]}) notificationsService.showNotification({type:messageType, header:"Validation", message:value[0]}) } } diff --git a/src/Umbraco.Web.UI.Client/src/common/services/tinymce.service.js b/src/Umbraco.Web.UI.Client/src/common/services/tinymce.service.js index 1d7154288f..9b5d240776 100644 --- a/src/Umbraco.Web.UI.Client/src/common/services/tinymce.service.js +++ b/src/Umbraco.Web.UI.Client/src/common/services/tinymce.service.js @@ -436,7 +436,7 @@ function tinyMceService($rootScope, $q, imageHelper, $locale, $http, $timeout, s // We are not ready to limit the pasted elements further than default, we will return to this feature. ( TODO: Make this feature an option. ) // We keep spans here, cause removing spans here also removes b-tags inside of them, instead we strip them out later. (TODO: move this definition to the config file... ) var validPasteElements = "-strong/b,-em/i,-u,-span,-p,-ol,-ul,-li,-p/div,-a[href|name],sub,sup,strike,br,del,table[width],tr,td[colspan|rowspan|width],th[colspan|rowspan|width],thead,tfoot,tbody,img[src|alt|width|height],ul,ol,li,hr,pre,dl,dt,figure,figcaption,wbr" - + // add elements from user configurated styleFormats to our list of validPasteElements. // (This means that we only allow H3-element if its configured as a styleFormat on this specific propertyEditor.) var style, i = 0; @@ -605,7 +605,7 @@ function tinyMceService($rootScope, $q, imageHelper, $locale, $http, $timeout, s 'contenteditable': false }, embed.preview); - + // Only replace if activeElement is an Embed element. if (activeElement && activeElement.nodeName.toUpperCase() === "DIV" && activeElement.classList.contains("embeditem")){ activeElement.replaceWith(wrapper); // directly replaces the html node @@ -733,9 +733,9 @@ function tinyMceService($rootScope, $q, imageHelper, $locale, $http, $timeout, s id: "__mcenew", "data-udi": img.udi }; - + editor.selection.setContent(editor.dom.createHTML('img', data)); - + // Using settimeout to wait for a DoM-render, so we can find the new element by ID. $timeout(function () { @@ -756,7 +756,7 @@ function tinyMceService($rootScope, $q, imageHelper, $locale, $http, $timeout, s } }); - + } } }, @@ -1396,11 +1396,26 @@ function tinyMceService($rootScope, $q, imageHelper, $locale, $http, $timeout, s function syncContent() { + if(args.model.value === args.editor.getContent()) { + return; + } + //stop watching before we update the value stopWatch(); angularHelper.safeApply($rootScope, function () { args.model.value = args.editor.getContent(); + + //make the form dirty manually so that the track changes works, setting our model doesn't trigger + // the angular bits because tinymce replaces the textarea. + if (args.currentForm) { + args.currentForm.$setDirty(); + } + // With complex validation we need to set a input field to dirty, not the form. but we will keep the old code for backwards compatibility. + if (args.currentFormInput) { + args.currentFormInput.$setDirty(); + } }); + //re-watch the value startWatch(); } @@ -1425,7 +1440,7 @@ function tinyMceService($rootScope, $q, imageHelper, $locale, $http, $timeout, s // Upload BLOB images (dragged/pasted ones) // find src attribute where value starts with `blob:` - // search is case-insensitive and allows single or double quotes + // search is case-insensitive and allows single or double quotes if(content.search(/src=["']blob:.*?["']/gi) !== -1){ args.editor.uploadImages(function(data) { // Once all images have been uploaded @@ -1491,6 +1506,9 @@ function tinyMceService($rootScope, $q, imageHelper, $locale, $http, $timeout, s args.editor.on('Change', function (e) { syncContent(); }); + args.editor.on('Keyup', function (e) { + syncContent(); + }); //when we leave the editor (maybe) args.editor.on('blur', function (e) { @@ -1508,12 +1526,6 @@ function tinyMceService($rootScope, $q, imageHelper, $locale, $http, $timeout, s args.editor.on('Dirty', function (e) { syncContent(); // Set model.value to the RTE's content - - //make the form dirty manually so that the track changes works, setting our model doesn't trigger - // the angular bits because tinymce replaces the textarea. - if (args.currentForm) { - args.currentForm.$setDirty(); - } }); let self = this; diff --git a/src/Umbraco.Web.UI.Client/src/views/propertyeditors/rte/rte.controller.js b/src/Umbraco.Web.UI.Client/src/views/propertyeditors/rte/rte.controller.js index 74a70118eb..9faa012a4d 100644 --- a/src/Umbraco.Web.UI.Client/src/views/propertyeditors/rte/rte.controller.js +++ b/src/Umbraco.Web.UI.Client/src/views/propertyeditors/rte/rte.controller.js @@ -5,12 +5,12 @@ angular.module("umbraco") // TODO: A lot of the code below should be shared between the grid rte and the normal rte $scope.isLoading = true; - + //To id the html textarea we need to use the datetime ticks because we can have multiple rte's per a single property alias // because now we have to support having 2x (maybe more at some stage) content editors being displayed at once. This is because // we have this mini content editor panel that can be launched with MNTP. $scope.textAreaHtmlId = $scope.model.alias + "_" + String.CreateGuid(); - + var editorConfig = $scope.model.config ? $scope.model.config.editor : null; if (!editorConfig || Utilities.isString(editorConfig)) { editorConfig = tinyMceService.defaultPrevalues(); @@ -28,14 +28,14 @@ angular.module("umbraco") $scope.containerOverflow = editorConfig.mode === "distraction-free" ? (height ? "auto" : "inherit") : "inherit"; var promises = []; - + // we need to make sure that the element is initialized before we can init TinyMCE, because we find the placeholder by ID, so it needs to be appended to document before. var initPromise = $q((resolve, reject) => { this.$onInit = resolve; }); - + promises.push(initPromise); - + //queue file loading tinyMceAssets.forEach(function (tinyJsAsset) { promises.push(assetsService.loadJs(tinyJsAsset, $scope)); @@ -50,50 +50,50 @@ angular.module("umbraco") toolbar: editorConfig.toolbar, mode: editorConfig.mode })); - + //wait for queue to end $q.all(promises).then(function (result) { - + var standardConfig = result[promises.length - 1]; - + if (height !== null) { standardConfig.plugins.splice(standardConfig.plugins.indexOf("autoresize"), 1); } - + //create a baseline Config to extend upon var baseLineConfigObj = { maxImageSize: editorConfig.maxImageSize, width: width, height: height }; - + baseLineConfigObj.setup = function (editor) { - + //set the reference tinyMceEditor = editor; - + tinyMceEditor.on('init', function (e) { $timeout(function () { $scope.isLoading = false; }); }); - + //initialize the standard editor functionality for Umbraco tinyMceService.initializeEditor({ editor: editor, model: $scope.model, - currentForm: angularHelper.getCurrentForm($scope) + currentFormInput: $scope.rteForm.modelValue }); - + }; - + angular.extend(baseLineConfigObj, standardConfig); - + // We need to wait for DOM to have rendered before we can find the element by ID. $timeout(function () { tinymce.init(baseLineConfigObj); }, 150); - + //listen for formSubmitting event (the result is callback used to remove the event subscription) var unsubscribe = $scope.$on("formSubmitting", function () { if (tinyMceEditor !== undefined && tinyMceEditor != null && !$scope.isLoading) { diff --git a/src/Umbraco.Web.UI.Client/src/views/propertyeditors/rte/rte.html b/src/Umbraco.Web.UI.Client/src/views/propertyeditors/rte/rte.html index d0b5823f74..21e9065d92 100644 --- a/src/Umbraco.Web.UI.Client/src/views/propertyeditors/rte/rte.html +++ b/src/Umbraco.Web.UI.Client/src/views/propertyeditors/rte/rte.html @@ -1,8 +1,10 @@
      -
      - -
      -
      + +
      + +
      +
      +
      From 1ac44542f6542a916537d0605881e1e7e3fe9b84 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Niels=20Lyngs=C3=B8?= Date: Wed, 26 May 2021 13:08:25 +0200 Subject: [PATCH 54/70] Complex validation for RTE property editor (#10328) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Niels Lyngsø (cherry picked from commit 0a9c1c7c8ebc899525ac5b0333be39704419ded9) # Conflicts: # src/Umbraco.Web.UI.Client/src/common/services/contenteditinghelper.service.js --- .../src/common/services/tinymce.service.js | 36 ++++++++++++------- .../propertyeditors/rte/rte.controller.js | 36 +++++++++---------- .../src/views/propertyeditors/rte/rte.html | 10 +++--- 3 files changed, 48 insertions(+), 34 deletions(-) diff --git a/src/Umbraco.Web.UI.Client/src/common/services/tinymce.service.js b/src/Umbraco.Web.UI.Client/src/common/services/tinymce.service.js index 1d7154288f..9b5d240776 100644 --- a/src/Umbraco.Web.UI.Client/src/common/services/tinymce.service.js +++ b/src/Umbraco.Web.UI.Client/src/common/services/tinymce.service.js @@ -436,7 +436,7 @@ function tinyMceService($rootScope, $q, imageHelper, $locale, $http, $timeout, s // We are not ready to limit the pasted elements further than default, we will return to this feature. ( TODO: Make this feature an option. ) // We keep spans here, cause removing spans here also removes b-tags inside of them, instead we strip them out later. (TODO: move this definition to the config file... ) var validPasteElements = "-strong/b,-em/i,-u,-span,-p,-ol,-ul,-li,-p/div,-a[href|name],sub,sup,strike,br,del,table[width],tr,td[colspan|rowspan|width],th[colspan|rowspan|width],thead,tfoot,tbody,img[src|alt|width|height],ul,ol,li,hr,pre,dl,dt,figure,figcaption,wbr" - + // add elements from user configurated styleFormats to our list of validPasteElements. // (This means that we only allow H3-element if its configured as a styleFormat on this specific propertyEditor.) var style, i = 0; @@ -605,7 +605,7 @@ function tinyMceService($rootScope, $q, imageHelper, $locale, $http, $timeout, s 'contenteditable': false }, embed.preview); - + // Only replace if activeElement is an Embed element. if (activeElement && activeElement.nodeName.toUpperCase() === "DIV" && activeElement.classList.contains("embeditem")){ activeElement.replaceWith(wrapper); // directly replaces the html node @@ -733,9 +733,9 @@ function tinyMceService($rootScope, $q, imageHelper, $locale, $http, $timeout, s id: "__mcenew", "data-udi": img.udi }; - + editor.selection.setContent(editor.dom.createHTML('img', data)); - + // Using settimeout to wait for a DoM-render, so we can find the new element by ID. $timeout(function () { @@ -756,7 +756,7 @@ function tinyMceService($rootScope, $q, imageHelper, $locale, $http, $timeout, s } }); - + } } }, @@ -1396,11 +1396,26 @@ function tinyMceService($rootScope, $q, imageHelper, $locale, $http, $timeout, s function syncContent() { + if(args.model.value === args.editor.getContent()) { + return; + } + //stop watching before we update the value stopWatch(); angularHelper.safeApply($rootScope, function () { args.model.value = args.editor.getContent(); + + //make the form dirty manually so that the track changes works, setting our model doesn't trigger + // the angular bits because tinymce replaces the textarea. + if (args.currentForm) { + args.currentForm.$setDirty(); + } + // With complex validation we need to set a input field to dirty, not the form. but we will keep the old code for backwards compatibility. + if (args.currentFormInput) { + args.currentFormInput.$setDirty(); + } }); + //re-watch the value startWatch(); } @@ -1425,7 +1440,7 @@ function tinyMceService($rootScope, $q, imageHelper, $locale, $http, $timeout, s // Upload BLOB images (dragged/pasted ones) // find src attribute where value starts with `blob:` - // search is case-insensitive and allows single or double quotes + // search is case-insensitive and allows single or double quotes if(content.search(/src=["']blob:.*?["']/gi) !== -1){ args.editor.uploadImages(function(data) { // Once all images have been uploaded @@ -1491,6 +1506,9 @@ function tinyMceService($rootScope, $q, imageHelper, $locale, $http, $timeout, s args.editor.on('Change', function (e) { syncContent(); }); + args.editor.on('Keyup', function (e) { + syncContent(); + }); //when we leave the editor (maybe) args.editor.on('blur', function (e) { @@ -1508,12 +1526,6 @@ function tinyMceService($rootScope, $q, imageHelper, $locale, $http, $timeout, s args.editor.on('Dirty', function (e) { syncContent(); // Set model.value to the RTE's content - - //make the form dirty manually so that the track changes works, setting our model doesn't trigger - // the angular bits because tinymce replaces the textarea. - if (args.currentForm) { - args.currentForm.$setDirty(); - } }); let self = this; diff --git a/src/Umbraco.Web.UI.Client/src/views/propertyeditors/rte/rte.controller.js b/src/Umbraco.Web.UI.Client/src/views/propertyeditors/rte/rte.controller.js index 74a70118eb..9faa012a4d 100644 --- a/src/Umbraco.Web.UI.Client/src/views/propertyeditors/rte/rte.controller.js +++ b/src/Umbraco.Web.UI.Client/src/views/propertyeditors/rte/rte.controller.js @@ -5,12 +5,12 @@ angular.module("umbraco") // TODO: A lot of the code below should be shared between the grid rte and the normal rte $scope.isLoading = true; - + //To id the html textarea we need to use the datetime ticks because we can have multiple rte's per a single property alias // because now we have to support having 2x (maybe more at some stage) content editors being displayed at once. This is because // we have this mini content editor panel that can be launched with MNTP. $scope.textAreaHtmlId = $scope.model.alias + "_" + String.CreateGuid(); - + var editorConfig = $scope.model.config ? $scope.model.config.editor : null; if (!editorConfig || Utilities.isString(editorConfig)) { editorConfig = tinyMceService.defaultPrevalues(); @@ -28,14 +28,14 @@ angular.module("umbraco") $scope.containerOverflow = editorConfig.mode === "distraction-free" ? (height ? "auto" : "inherit") : "inherit"; var promises = []; - + // we need to make sure that the element is initialized before we can init TinyMCE, because we find the placeholder by ID, so it needs to be appended to document before. var initPromise = $q((resolve, reject) => { this.$onInit = resolve; }); - + promises.push(initPromise); - + //queue file loading tinyMceAssets.forEach(function (tinyJsAsset) { promises.push(assetsService.loadJs(tinyJsAsset, $scope)); @@ -50,50 +50,50 @@ angular.module("umbraco") toolbar: editorConfig.toolbar, mode: editorConfig.mode })); - + //wait for queue to end $q.all(promises).then(function (result) { - + var standardConfig = result[promises.length - 1]; - + if (height !== null) { standardConfig.plugins.splice(standardConfig.plugins.indexOf("autoresize"), 1); } - + //create a baseline Config to extend upon var baseLineConfigObj = { maxImageSize: editorConfig.maxImageSize, width: width, height: height }; - + baseLineConfigObj.setup = function (editor) { - + //set the reference tinyMceEditor = editor; - + tinyMceEditor.on('init', function (e) { $timeout(function () { $scope.isLoading = false; }); }); - + //initialize the standard editor functionality for Umbraco tinyMceService.initializeEditor({ editor: editor, model: $scope.model, - currentForm: angularHelper.getCurrentForm($scope) + currentFormInput: $scope.rteForm.modelValue }); - + }; - + angular.extend(baseLineConfigObj, standardConfig); - + // We need to wait for DOM to have rendered before we can find the element by ID. $timeout(function () { tinymce.init(baseLineConfigObj); }, 150); - + //listen for formSubmitting event (the result is callback used to remove the event subscription) var unsubscribe = $scope.$on("formSubmitting", function () { if (tinyMceEditor !== undefined && tinyMceEditor != null && !$scope.isLoading) { diff --git a/src/Umbraco.Web.UI.Client/src/views/propertyeditors/rte/rte.html b/src/Umbraco.Web.UI.Client/src/views/propertyeditors/rte/rte.html index d0b5823f74..21e9065d92 100644 --- a/src/Umbraco.Web.UI.Client/src/views/propertyeditors/rte/rte.html +++ b/src/Umbraco.Web.UI.Client/src/views/propertyeditors/rte/rte.html @@ -1,8 +1,10 @@
      -
      - -
      -
      + +
      + +
      +
      +
      From 008e76c08f72a2e009e3518f13c2896b3677d7e7 Mon Sep 17 00:00:00 2001 From: Mads Rasmussen Date: Wed, 26 May 2021 11:42:06 +0200 Subject: [PATCH 55/70] fixes #10297 8.14-RC - A few areas where focus lock doesn't work properly --- .../components/editor/umbeditors.directive.js | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/src/Umbraco.Web.UI.Client/src/common/directives/components/editor/umbeditors.directive.js b/src/Umbraco.Web.UI.Client/src/common/directives/components/editor/umbeditors.directive.js index 231ee4e866..590f9627ab 100644 --- a/src/Umbraco.Web.UI.Client/src/common/directives/components/editor/umbeditors.directive.js +++ b/src/Umbraco.Web.UI.Client/src/common/directives/components/editor/umbeditors.directive.js @@ -12,6 +12,11 @@ var isLeftColumnAbove = false; scope.editors = []; + /* we need to keep a count of open editors because the length of the editors array is first changed when animations are done + we do this because some infinite editors close more than one editor at the time and we get the wrong count from editors.length + because of the animation */ + let editorCount = 0; + function addEditor(editor) { editor.inFront = true; editor.moveRight = true; @@ -51,13 +56,16 @@ updateEditors(-1); - if(scope.editors.length === 1){ + if(scope.editors.length === 1) { if(isLeftColumnAbove){ $('#leftcolumn').addClass(aboveBackDropCssClass); } isLeftColumnAbove = false; + } + // when the last editor is closed remove the focus lock + if (editorCount === 0) { // Remove the inert attribute from the #mainwrapper focusLockService.removeInertAttribute(); } @@ -105,16 +113,19 @@ } evts.push(eventsService.on("appState.editors.open", function (name, args) { + editorCount = editorCount + 1; addEditor(args.editor); })); evts.push(eventsService.on("appState.editors.close", function (name, args) { // remove the closed editor if (args && args.editor) { + editorCount = editorCount - 1; removeEditor(args.editor); } // close all editors if (args && !args.editor && args.editors.length === 0) { + editorCount = 0; scope.editors = []; } })); From 9ef806d4e9544173b185c4702644ae7233eca5b5 Mon Sep 17 00:00:00 2001 From: Warren Buckley Date: Wed, 26 May 2021 15:13:25 +0100 Subject: [PATCH 56/70] Rename Media Picker 3 and make current Media Picker Obsolete (#10332) --- .../Migrations/Install/DatabaseDataCreator.cs | 15 +++++++-------- src/Umbraco.Tests/Services/ContentServiceTests.cs | 2 +- .../TestHelpers/Entities/MockedContent.cs | 2 +- .../TestHelpers/Entities/MockedContentTypes.cs | 2 +- .../PropertyEditors/MediaPicker3PropertyEditor.cs | 2 +- .../PropertyEditors/MediaPickerPropertyEditor.cs | 6 ++++-- 6 files changed, 15 insertions(+), 14 deletions(-) diff --git a/src/Umbraco.Core/Migrations/Install/DatabaseDataCreator.cs b/src/Umbraco.Core/Migrations/Install/DatabaseDataCreator.cs index 264733e5b9..6a56141491 100644 --- a/src/Umbraco.Core/Migrations/Install/DatabaseDataCreator.cs +++ b/src/Umbraco.Core/Migrations/Install/DatabaseDataCreator.cs @@ -141,14 +141,14 @@ namespace Umbraco.Core.Migrations.Install //New UDI pickers with newer Ids _database.Insert(Constants.DatabaseSchema.Tables.Node, "id", false, new NodeDto { NodeId = 1046, Trashed = false, ParentId = -1, UserId = -1, Level = 1, Path = "-1,1046", SortOrder = 2, UniqueId = new Guid("FD1E0DA5-5606-4862-B679-5D0CF3A52A59"), Text = "Content Picker", NodeObjectType = Constants.ObjectTypes.DataType, CreateDate = DateTime.Now }); _database.Insert(Constants.DatabaseSchema.Tables.Node, "id", false, new NodeDto { NodeId = 1047, Trashed = false, ParentId = -1, UserId = -1, Level = 1, Path = "-1,1047", SortOrder = 2, UniqueId = new Guid("1EA2E01F-EBD8-4CE1-8D71-6B1149E63548"), Text = "Member Picker", NodeObjectType = Constants.ObjectTypes.DataType, CreateDate = DateTime.Now }); - _database.Insert(Constants.DatabaseSchema.Tables.Node, "id", false, new NodeDto { NodeId = 1048, Trashed = false, ParentId = -1, UserId = -1, Level = 1, Path = "-1,1048", SortOrder = 2, UniqueId = new Guid("135D60E0-64D9-49ED-AB08-893C9BA44AE5"), Text = "Media Picker (old)", NodeObjectType = Constants.ObjectTypes.DataType, CreateDate = DateTime.Now }); - _database.Insert(Constants.DatabaseSchema.Tables.Node, "id", false, new NodeDto { NodeId = 1049, Trashed = false, ParentId = -1, UserId = -1, Level = 1, Path = "-1,1049", SortOrder = 2, UniqueId = new Guid("9DBBCBBB-2327-434A-B355-AF1B84E5010A"), Text = "Multiple Media Picker (old)", NodeObjectType = Constants.ObjectTypes.DataType, CreateDate = DateTime.Now }); + _database.Insert(Constants.DatabaseSchema.Tables.Node, "id", false, new NodeDto { NodeId = 1048, Trashed = false, ParentId = -1, UserId = -1, Level = 1, Path = "-1,1048", SortOrder = 2, UniqueId = new Guid("135D60E0-64D9-49ED-AB08-893C9BA44AE5"), Text = "(Obsolete) Media Picker", NodeObjectType = Constants.ObjectTypes.DataType, CreateDate = DateTime.Now }); + _database.Insert(Constants.DatabaseSchema.Tables.Node, "id", false, new NodeDto { NodeId = 1049, Trashed = false, ParentId = -1, UserId = -1, Level = 1, Path = "-1,1049", SortOrder = 2, UniqueId = new Guid("9DBBCBBB-2327-434A-B355-AF1B84E5010A"), Text = "(Obsolete) Multiple Media Picker", NodeObjectType = Constants.ObjectTypes.DataType, CreateDate = DateTime.Now }); _database.Insert(Constants.DatabaseSchema.Tables.Node, "id", false, new NodeDto { NodeId = 1050, Trashed = false, ParentId = -1, UserId = -1, Level = 1, Path = "-1,1050", SortOrder = 2, UniqueId = new Guid("B4E3535A-1753-47E2-8568-602CF8CFEE6F"), Text = "Multi URL Picker", NodeObjectType = Constants.ObjectTypes.DataType, CreateDate = DateTime.Now }); - _database.Insert(Constants.DatabaseSchema.Tables.Node, "id", false, new NodeDto { NodeId = 1051, Trashed = false, ParentId = -1, UserId = -1, Level = 1, Path = "-1,1051", SortOrder = 2, UniqueId = Constants.DataTypes.Guids.MediaPicker3Guid, Text = "Media Picker 3", NodeObjectType = Constants.ObjectTypes.DataType, CreateDate = DateTime.Now }); - _database.Insert(Constants.DatabaseSchema.Tables.Node, "id", false, new NodeDto { NodeId = 1052, Trashed = false, ParentId = -1, UserId = -1, Level = 1, Path = "-1,1052", SortOrder = 2, UniqueId = Constants.DataTypes.Guids.MediaPicker3MultipleGuid, Text = "Multiple Media Picker 3", NodeObjectType = Constants.ObjectTypes.DataType, CreateDate = DateTime.Now }); - _database.Insert(Constants.DatabaseSchema.Tables.Node, "id", false, new NodeDto { NodeId = 1053, Trashed = false, ParentId = -1, UserId = -1, Level = 1, Path = "-1,1053", SortOrder = 2, UniqueId = Constants.DataTypes.Guids.MediaPicker3SingleImageGuid, Text = "Image Media Picker 3", NodeObjectType = Constants.ObjectTypes.DataType, CreateDate = DateTime.Now }); - _database.Insert(Constants.DatabaseSchema.Tables.Node, "id", false, new NodeDto { NodeId = 1054, Trashed = false, ParentId = -1, UserId = -1, Level = 1, Path = "-1,1054", SortOrder = 2, UniqueId = Constants.DataTypes.Guids.MediaPicker3MultipleImagesGuid, Text = "Multiple Image Media Picker 3", NodeObjectType = Constants.ObjectTypes.DataType, CreateDate = DateTime.Now }); + _database.Insert(Constants.DatabaseSchema.Tables.Node, "id", false, new NodeDto { NodeId = 1051, Trashed = false, ParentId = -1, UserId = -1, Level = 1, Path = "-1,1051", SortOrder = 2, UniqueId = Constants.DataTypes.Guids.MediaPicker3Guid, Text = "Media Picker", NodeObjectType = Constants.ObjectTypes.DataType, CreateDate = DateTime.Now }); + _database.Insert(Constants.DatabaseSchema.Tables.Node, "id", false, new NodeDto { NodeId = 1052, Trashed = false, ParentId = -1, UserId = -1, Level = 1, Path = "-1,1052", SortOrder = 2, UniqueId = Constants.DataTypes.Guids.MediaPicker3MultipleGuid, Text = "Multiple Media Picker", NodeObjectType = Constants.ObjectTypes.DataType, CreateDate = DateTime.Now }); + _database.Insert(Constants.DatabaseSchema.Tables.Node, "id", false, new NodeDto { NodeId = 1053, Trashed = false, ParentId = -1, UserId = -1, Level = 1, Path = "-1,1053", SortOrder = 2, UniqueId = Constants.DataTypes.Guids.MediaPicker3SingleImageGuid, Text = "Image Media Picker", NodeObjectType = Constants.ObjectTypes.DataType, CreateDate = DateTime.Now }); + _database.Insert(Constants.DatabaseSchema.Tables.Node, "id", false, new NodeDto { NodeId = 1054, Trashed = false, ParentId = -1, UserId = -1, Level = 1, Path = "-1,1054", SortOrder = 2, UniqueId = Constants.DataTypes.Guids.MediaPicker3MultipleImagesGuid, Text = "Multiple Image Media Picker", NodeObjectType = Constants.ObjectTypes.DataType, CreateDate = DateTime.Now }); } @@ -350,8 +350,7 @@ namespace Umbraco.Core.Migrations.Install _database.Insert(Constants.DatabaseSchema.Tables.DataType, "pk", false, new DataTypeDto { NodeId = 1046, EditorAlias = Constants.PropertyEditors.Aliases.ContentPicker, DbType = "Nvarchar" }); _database.Insert(Constants.DatabaseSchema.Tables.DataType, "pk", false, new DataTypeDto { NodeId = 1047, EditorAlias = Constants.PropertyEditors.Aliases.MemberPicker, DbType = "Nvarchar" }); _database.Insert(Constants.DatabaseSchema.Tables.DataType, "pk", false, new DataTypeDto { NodeId = 1048, EditorAlias = Constants.PropertyEditors.Aliases.MediaPicker, DbType = "Ntext" }); - _database.Insert(Constants.DatabaseSchema.Tables.DataType, "pk", false, new DataTypeDto { NodeId = 1049, EditorAlias = Constants.PropertyEditors.Aliases.MediaPicker, DbType = "Ntext", - Configuration = "{\"multiPicker\":1}" }); + _database.Insert(Constants.DatabaseSchema.Tables.DataType, "pk", false, new DataTypeDto { NodeId = 1049, EditorAlias = Constants.PropertyEditors.Aliases.MediaPicker, DbType = "Ntext", Configuration = "{\"multiPicker\":1}" }); _database.Insert(Constants.DatabaseSchema.Tables.DataType, "pk", false, new DataTypeDto { NodeId = 1050, EditorAlias = Constants.PropertyEditors.Aliases.MultiUrlPicker, DbType = "Ntext" }); _database.Insert(Constants.DatabaseSchema.Tables.DataType, "pk", false, new DataTypeDto diff --git a/src/Umbraco.Tests/Services/ContentServiceTests.cs b/src/Umbraco.Tests/Services/ContentServiceTests.cs index 008c24fcbf..d9a90b74d8 100644 --- a/src/Umbraco.Tests/Services/ContentServiceTests.cs +++ b/src/Umbraco.Tests/Services/ContentServiceTests.cs @@ -2470,7 +2470,7 @@ namespace Umbraco.Tests.Services Assert.That(sut.GetValue("ddl"), Is.EqualTo("1234")); Assert.That(sut.GetValue("chklist"), Is.EqualTo("randomc")); Assert.That(sut.GetValue("contentPicker"), Is.EqualTo(Udi.Create(Constants.UdiEntityType.Document, new Guid("74ECA1D4-934E-436A-A7C7-36CC16D4095C")))); - Assert.That(sut.GetValue("mediaPicker"), Is.EqualTo(Udi.Create(Constants.UdiEntityType.Media, new Guid("44CB39C8-01E5-45EB-9CF8-E70AAF2D1691")))); + Assert.That(sut.GetValue("mediapicker3"), Is.EqualTo("[{\"key\": \"8f78ce9e-8fe0-4500-a52d-4c4f35566ba9\",\"mediaKey\": \"44CB39C8-01E5-45EB-9CF8-E70AAF2D1691\",\"crops\": [],\"focalPoint\": {\"left\": 0.5,\"top\": 0.5}}]")); Assert.That(sut.GetValue("memberPicker"), Is.EqualTo(Udi.Create(Constants.UdiEntityType.Member, new Guid("9A50A448-59C0-4D42-8F93-4F1D55B0F47D")))); Assert.That(sut.GetValue("multiUrlPicker"), Is.EqualTo("[{\"name\":\"https://test.com\",\"url\":\"https://test.com\"}]")); Assert.That(sut.GetValue("tags"), Is.EqualTo("this,is,tags")); diff --git a/src/Umbraco.Tests/TestHelpers/Entities/MockedContent.cs b/src/Umbraco.Tests/TestHelpers/Entities/MockedContent.cs index 19a57d7775..d8902d2d62 100644 --- a/src/Umbraco.Tests/TestHelpers/Entities/MockedContent.cs +++ b/src/Umbraco.Tests/TestHelpers/Entities/MockedContent.cs @@ -130,7 +130,7 @@ namespace Umbraco.Tests.TestHelpers.Entities content.SetValue("ddl", "1234"); content.SetValue("chklist", "randomc"); content.SetValue("contentPicker", Udi.Create(Constants.UdiEntityType.Document, new Guid("74ECA1D4-934E-436A-A7C7-36CC16D4095C")).ToString()); - content.SetValue("mediaPicker", Udi.Create(Constants.UdiEntityType.Media, new Guid("44CB39C8-01E5-45EB-9CF8-E70AAF2D1691")).ToString()); + content.SetValue("mediaPicker3", "[{\"key\": \"8f78ce9e-8fe0-4500-a52d-4c4f35566ba9\",\"mediaKey\": \"44CB39C8-01E5-45EB-9CF8-E70AAF2D1691\",\"crops\": [],\"focalPoint\": {\"left\": 0.5,\"top\": 0.5}}]"); content.SetValue("memberPicker", Udi.Create(Constants.UdiEntityType.Member, new Guid("9A50A448-59C0-4D42-8F93-4F1D55B0F47D")).ToString()); content.SetValue("multiUrlPicker", "[{\"name\":\"https://test.com\",\"url\":\"https://test.com\"}]"); content.SetValue("tags", "this,is,tags"); diff --git a/src/Umbraco.Tests/TestHelpers/Entities/MockedContentTypes.cs b/src/Umbraco.Tests/TestHelpers/Entities/MockedContentTypes.cs index 1b85787fee..9271486f2b 100644 --- a/src/Umbraco.Tests/TestHelpers/Entities/MockedContentTypes.cs +++ b/src/Umbraco.Tests/TestHelpers/Entities/MockedContentTypes.cs @@ -368,7 +368,7 @@ namespace Umbraco.Tests.TestHelpers.Entities contentCollection.Add(new PropertyType(Constants.PropertyEditors.Aliases.DropDownListFlexible, ValueStorageType.Integer) { Alias = "ddl", Name = "Dropdown List", Mandatory = false, SortOrder = 14, DataTypeId = -42 }); contentCollection.Add(new PropertyType(Constants.PropertyEditors.Aliases.CheckBoxList, ValueStorageType.Nvarchar) { Alias = "chklist", Name = "Checkbox List", Mandatory = false, SortOrder = 15, DataTypeId = -43 }); contentCollection.Add(new PropertyType(Constants.PropertyEditors.Aliases.ContentPicker, ValueStorageType.Integer) { Alias = "contentPicker", Name = "Content Picker", Mandatory = false, SortOrder = 16, DataTypeId = 1046 }); - contentCollection.Add(new PropertyType(Constants.PropertyEditors.Aliases.MediaPicker, ValueStorageType.Integer) { Alias = "mediaPicker", Name = "Media Picker", Mandatory = false, SortOrder = 17, DataTypeId = 1048 }); + contentCollection.Add(new PropertyType(Constants.PropertyEditors.Aliases.MediaPicker3, ValueStorageType.Integer) { Alias = "mediapicker3", Name = "Media Picker", Mandatory = false, SortOrder = 17, DataTypeId = 1051 }); contentCollection.Add(new PropertyType(Constants.PropertyEditors.Aliases.MemberPicker, ValueStorageType.Integer) { Alias = "memberPicker", Name = "Member Picker", Mandatory = false, SortOrder = 18, DataTypeId = 1047 }); contentCollection.Add(new PropertyType(Constants.PropertyEditors.Aliases.MultiUrlPicker, ValueStorageType.Nvarchar) { Alias = "multiUrlPicker", Name = "Multi URL Picker", Mandatory = false, SortOrder = 21, DataTypeId = 1050 }); contentCollection.Add(new PropertyType(Constants.PropertyEditors.Aliases.Tags, ValueStorageType.Ntext) { Alias = "tags", Name = "Tags", Mandatory = false, SortOrder = 22, DataTypeId = 1041 }); diff --git a/src/Umbraco.Web/PropertyEditors/MediaPicker3PropertyEditor.cs b/src/Umbraco.Web/PropertyEditors/MediaPicker3PropertyEditor.cs index 526b4830c8..4ce376f543 100644 --- a/src/Umbraco.Web/PropertyEditors/MediaPicker3PropertyEditor.cs +++ b/src/Umbraco.Web/PropertyEditors/MediaPicker3PropertyEditor.cs @@ -14,7 +14,7 @@ namespace Umbraco.Web.PropertyEditors [DataEditor( Constants.PropertyEditors.Aliases.MediaPicker3, EditorType.PropertyValue, - "Media Picker v3", + "Media Picker", "mediapicker3", ValueType = ValueTypes.Json, Group = Constants.PropertyEditors.Groups.Media, diff --git a/src/Umbraco.Web/PropertyEditors/MediaPickerPropertyEditor.cs b/src/Umbraco.Web/PropertyEditors/MediaPickerPropertyEditor.cs index 493fc96f76..499737f3b7 100644 --- a/src/Umbraco.Web/PropertyEditors/MediaPickerPropertyEditor.cs +++ b/src/Umbraco.Web/PropertyEditors/MediaPickerPropertyEditor.cs @@ -8,15 +8,17 @@ namespace Umbraco.Web.PropertyEditors { /// /// Represents a media picker property editor. + /// Marked as Deprecated as best to use the NEW Media Picker aka MediaPicker3 /// [DataEditor( Constants.PropertyEditors.Aliases.MediaPicker, EditorType.PropertyValue | EditorType.MacroParameter, - "Media Picker", + "(Obsolete) Media Picker", "mediapicker", ValueType = ValueTypes.Text, Group = Constants.PropertyEditors.Groups.Media, - Icon = Constants.Icons.MediaImage)] + Icon = Constants.Icons.MediaImage, + IsDeprecated = true)] public class MediaPickerPropertyEditor : DataEditor { From a845d2bffd76434e9af42b83ce820298cfe49f16 Mon Sep 17 00:00:00 2001 From: Sebastiaan Janssen Date: Wed, 26 May 2021 16:18:10 +0200 Subject: [PATCH 57/70] Shows a warning for people tempted to switch to the new media picker --- .../src/views/prevalueeditors/obsoletemediapickernotice.html | 1 + src/Umbraco.Web/PropertyEditors/MediaPickerConfiguration.cs | 3 +++ 2 files changed, 4 insertions(+) create mode 100644 src/Umbraco.Web.UI.Client/src/views/prevalueeditors/obsoletemediapickernotice.html diff --git a/src/Umbraco.Web.UI.Client/src/views/prevalueeditors/obsoletemediapickernotice.html b/src/Umbraco.Web.UI.Client/src/views/prevalueeditors/obsoletemediapickernotice.html new file mode 100644 index 0000000000..cc861dcb4b --- /dev/null +++ b/src/Umbraco.Web.UI.Client/src/views/prevalueeditors/obsoletemediapickernotice.html @@ -0,0 +1 @@ +

      Important: switching from the (Obsolete) Media Picker to Media Picker will mean all data (references to previously selected media items) will be deleted and no longer available.

      \ No newline at end of file diff --git a/src/Umbraco.Web/PropertyEditors/MediaPickerConfiguration.cs b/src/Umbraco.Web/PropertyEditors/MediaPickerConfiguration.cs index b8b9476184..7266be9c26 100644 --- a/src/Umbraco.Web/PropertyEditors/MediaPickerConfiguration.cs +++ b/src/Umbraco.Web/PropertyEditors/MediaPickerConfiguration.cs @@ -8,6 +8,9 @@ namespace Umbraco.Web.PropertyEditors /// public class MediaPickerConfiguration : IIgnoreUserStartNodesConfig { + [ConfigurationField("notice", "You can NOT change the property editor", "obsoletemediapickernotice")] + public bool Notice { get; set; } + [ConfigurationField("multiPicker", "Pick multiple items", "boolean")] public bool Multiple { get; set; } From d81fac9753591415fd8418fdcdb89d5445957888 Mon Sep 17 00:00:00 2001 From: Sebastiaan Janssen Date: Thu, 27 May 2021 10:42:13 +0200 Subject: [PATCH 58/70] Bump version to 8.14.0 --- src/SolutionInfo.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/SolutionInfo.cs b/src/SolutionInfo.cs index 91918498f9..3619dc1371 100644 --- a/src/SolutionInfo.cs +++ b/src/SolutionInfo.cs @@ -19,4 +19,4 @@ using System.Resources; // these are FYI and changed automatically [assembly: AssemblyFileVersion("8.14.0")] -[assembly: AssemblyInformationalVersion("8.14.0-rc")] +[assembly: AssemblyInformationalVersion("8.14.0")] From fc417e8ed811cf30c140c040ef07eecd9130c7ce Mon Sep 17 00:00:00 2001 From: Sebastiaan Janssen Date: Mon, 31 May 2021 09:18:12 +0200 Subject: [PATCH 59/70] Bump version to 8.11.3 --- src/SolutionInfo.cs | 4 ++-- src/Umbraco.Web.UI/Umbraco.Web.UI.csproj | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/SolutionInfo.cs b/src/SolutionInfo.cs index ca9d596415..e4becddab0 100644 --- a/src/SolutionInfo.cs +++ b/src/SolutionInfo.cs @@ -18,5 +18,5 @@ using System.Resources; [assembly: AssemblyVersion("8.0.0")] // these are FYI and changed automatically -[assembly: AssemblyFileVersion("8.11.2")] -[assembly: AssemblyInformationalVersion("8.11.2")] +[assembly: AssemblyFileVersion("8.11.3")] +[assembly: AssemblyInformationalVersion("8.11.3")] diff --git a/src/Umbraco.Web.UI/Umbraco.Web.UI.csproj b/src/Umbraco.Web.UI/Umbraco.Web.UI.csproj index 366a852a96..3b7286c293 100644 --- a/src/Umbraco.Web.UI/Umbraco.Web.UI.csproj +++ b/src/Umbraco.Web.UI/Umbraco.Web.UI.csproj @@ -347,9 +347,9 @@ False True - 8112 + 8113 / - http://localhost:8112 + http://localhost:8113 False False From 042e296d8f596f784c9c18333d507e45f02ff9d6 Mon Sep 17 00:00:00 2001 From: Sebastiaan Janssen Date: Mon, 31 May 2021 09:21:44 +0200 Subject: [PATCH 60/70] Bump version to 8.12.3 --- src/SolutionInfo.cs | 4 ++-- src/Umbraco.Web.UI/Umbraco.Web.UI.csproj | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/SolutionInfo.cs b/src/SolutionInfo.cs index 4162f47da6..cf8bde8057 100644 --- a/src/SolutionInfo.cs +++ b/src/SolutionInfo.cs @@ -18,5 +18,5 @@ using System.Resources; [assembly: AssemblyVersion("8.0.0")] // these are FYI and changed automatically -[assembly: AssemblyFileVersion("8.12.2")] -[assembly: AssemblyInformationalVersion("8.12.2")] +[assembly: AssemblyFileVersion("8.12.3")] +[assembly: AssemblyInformationalVersion("8.12.3")] diff --git a/src/Umbraco.Web.UI/Umbraco.Web.UI.csproj b/src/Umbraco.Web.UI/Umbraco.Web.UI.csproj index 2ad23e1b73..0454ba6c12 100644 --- a/src/Umbraco.Web.UI/Umbraco.Web.UI.csproj +++ b/src/Umbraco.Web.UI/Umbraco.Web.UI.csproj @@ -347,9 +347,9 @@ False True - 8122 + 8123 / - http://localhost:8122 + http://localhost:8123 False False From c01b2c58073a5af2d5431721211c3399396d2a05 Mon Sep 17 00:00:00 2001 From: Andy Butland Date: Tue, 8 Jun 2021 07:51:08 +0200 Subject: [PATCH 61/70] Removed the "Umbraco Pro" category. --- .../src/views/packages/views/repo.controller.js | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/Umbraco.Web.UI.Client/src/views/packages/views/repo.controller.js b/src/Umbraco.Web.UI.Client/src/views/packages/views/repo.controller.js index 4a2a3f29a7..90cfc9d2f7 100644 --- a/src/Umbraco.Web.UI.Client/src/views/packages/views/repo.controller.js +++ b/src/Umbraco.Web.UI.Client/src/views/packages/views/repo.controller.js @@ -1,7 +1,7 @@ (function () { "use strict"; - function PackagesRepoController($scope, $route, $location, $timeout, ourPackageRepositoryResource, $q, packageResource, localStorageService, localizationService) { + function PackagesRepoController($scope, $timeout, ourPackageRepositoryResource, $q, packageResource, localStorageService, localizationService) { var vm = this; @@ -75,7 +75,9 @@ $q.all([ ourPackageRepositoryResource.getCategories() .then(function (cats) { - vm.categories = cats; + vm.categories = cats.filter(function (cat) { + return cat.name !== "Umbraco Pro"; + }); }), ourPackageRepositoryResource.getPopular(8) .then(function (pack) { From 97bc301bf8943c96119a5c762e79ce4359ed0673 Mon Sep 17 00:00:00 2001 From: Andy Butland Date: Tue, 8 Jun 2021 10:08:27 +0200 Subject: [PATCH 62/70] Adds the "works on Cloud" indicator to the package list and details screen in the back-office. --- .../src/less/components/umb-packages.less | 10 ++++++++++ .../src/views/packages/views/repo.html | 16 ++++++++++++++++ src/Umbraco.Web.UI/Umbraco/config/lang/en.xml | 1 + src/Umbraco.Web.UI/Umbraco/config/lang/en_us.xml | 1 + 4 files changed, 28 insertions(+) diff --git a/src/Umbraco.Web.UI.Client/src/less/components/umb-packages.less b/src/Umbraco.Web.UI.Client/src/less/components/umb-packages.less index 0045bed140..f660da8f8b 100644 --- a/src/Umbraco.Web.UI.Client/src/less/components/umb-packages.less +++ b/src/Umbraco.Web.UI.Client/src/less/components/umb-packages.less @@ -157,6 +157,16 @@ color: @red !important; } +.umb-package-link .umb-package-cloud { + margin-top: 8px; + font-size: 11px; + height: 11px; // ensures vertical space is taken up even if "works on cloud" isn't visible +} + +.umb-package-link .umb-package-cloud .icon-cloud { + color: #2eadaf !important; +} + // Version .umb-package-version { display: inline-flex; diff --git a/src/Umbraco.Web.UI.Client/src/views/packages/views/repo.html b/src/Umbraco.Web.UI.Client/src/views/packages/views/repo.html index 42b538f9ad..e92bd73535 100644 --- a/src/Umbraco.Web.UI.Client/src/views/packages/views/repo.html +++ b/src/Umbraco.Web.UI.Client/src/views/packages/views/repo.html @@ -62,6 +62,12 @@ {{package.likes}}
      +
      +
      + + Certified to work on Umbraco Cloud +
      +
    @@ -101,6 +107,12 @@ {{ package.likes }} +
    +
    + + Certified to work on Umbraco Cloud +
    +
    @@ -269,6 +281,10 @@
    {{vm.package.likes}}
    +
    +
    Certified to work on Umbraco CLoud
    +
    + diff --git a/src/Umbraco.Web.UI/Umbraco/config/lang/en.xml b/src/Umbraco.Web.UI/Umbraco/config/lang/en.xml index c76747c5a0..3ecafd1d67 100644 --- a/src/Umbraco.Web.UI/Umbraco/config/lang/en.xml +++ b/src/Umbraco.Web.UI/Umbraco/config/lang/en.xml @@ -1288,6 +1288,7 @@ To manage your website, simply open the Umbraco backoffice and start adding cont All done, your browser will now refresh, please wait... Please click 'Finish' to complete installation and reload the page. Uploading package... + Certified to work on Umbraco Cloud Paste with full formatting (Not recommended) diff --git a/src/Umbraco.Web.UI/Umbraco/config/lang/en_us.xml b/src/Umbraco.Web.UI/Umbraco/config/lang/en_us.xml index ba7586dde2..ec56665a9c 100644 --- a/src/Umbraco.Web.UI/Umbraco/config/lang/en_us.xml +++ b/src/Umbraco.Web.UI/Umbraco/config/lang/en_us.xml @@ -1294,6 +1294,7 @@ To manage your website, simply open the Umbraco backoffice and start adding cont All done, your browser will now refresh, please wait... Please click 'Finish' to complete installation and reload the page. Uploading package... + Certified to work on Umbraco Cloud Paste with full formatting (Not recommended) From dfae0adf3d5b6d4b2d3ffffed5711c1f7b1c7a20 Mon Sep 17 00:00:00 2001 From: Andy Butland Date: Tue, 8 Jun 2021 11:50:16 +0200 Subject: [PATCH 63/70] Amended phrase for Cloud confirmed packages from "certified" to "verified". --- src/Umbraco.Web.UI.Client/src/views/packages/views/repo.html | 4 ++-- src/Umbraco.Web.UI/Umbraco/config/lang/en.xml | 2 +- src/Umbraco.Web.UI/Umbraco/config/lang/en_us.xml | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/Umbraco.Web.UI.Client/src/views/packages/views/repo.html b/src/Umbraco.Web.UI.Client/src/views/packages/views/repo.html index e92bd73535..c59d2ee3e2 100644 --- a/src/Umbraco.Web.UI.Client/src/views/packages/views/repo.html +++ b/src/Umbraco.Web.UI.Client/src/views/packages/views/repo.html @@ -110,7 +110,7 @@
    - Certified to work on Umbraco Cloud + Verified to work on Umbraco Cloud
    @@ -282,7 +282,7 @@
    -
    Certified to work on Umbraco CLoud
    +
    Verified to work on Umbraco CLoud
    diff --git a/src/Umbraco.Web.UI/Umbraco/config/lang/en.xml b/src/Umbraco.Web.UI/Umbraco/config/lang/en.xml index 3ecafd1d67..727ca31dab 100644 --- a/src/Umbraco.Web.UI/Umbraco/config/lang/en.xml +++ b/src/Umbraco.Web.UI/Umbraco/config/lang/en.xml @@ -1288,7 +1288,7 @@ To manage your website, simply open the Umbraco backoffice and start adding cont All done, your browser will now refresh, please wait... Please click 'Finish' to complete installation and reload the page. Uploading package... - Certified to work on Umbraco Cloud + Verified to work on Umbraco Cloud Paste with full formatting (Not recommended) diff --git a/src/Umbraco.Web.UI/Umbraco/config/lang/en_us.xml b/src/Umbraco.Web.UI/Umbraco/config/lang/en_us.xml index ec56665a9c..4fc6fb7cdb 100644 --- a/src/Umbraco.Web.UI/Umbraco/config/lang/en_us.xml +++ b/src/Umbraco.Web.UI/Umbraco/config/lang/en_us.xml @@ -1294,7 +1294,7 @@ To manage your website, simply open the Umbraco backoffice and start adding cont All done, your browser will now refresh, please wait... Please click 'Finish' to complete installation and reload the page. Uploading package... - Certified to work on Umbraco Cloud + Verified to work on Umbraco Cloud Paste with full formatting (Not recommended) From 87eb224e5c5b6d036eefb0b4e32d3dd332464832 Mon Sep 17 00:00:00 2001 From: Andy Butland Date: Tue, 8 Jun 2021 11:55:58 +0200 Subject: [PATCH 64/70] Updated package listing to use umb-icon directive. --- .../src/views/packages/views/repo.html | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/src/Umbraco.Web.UI.Client/src/views/packages/views/repo.html b/src/Umbraco.Web.UI.Client/src/views/packages/views/repo.html index c59d2ee3e2..c29a914763 100644 --- a/src/Umbraco.Web.UI.Client/src/views/packages/views/repo.html +++ b/src/Umbraco.Web.UI.Client/src/views/packages/views/repo.html @@ -54,17 +54,17 @@
    - + {{package.downloads}} - + {{package.likes}}
    - + Certified to work on Umbraco Cloud
    @@ -99,17 +99,17 @@
    - - {{ package.downloads }} + + {{package.downloads}} - - {{ package.likes }} + + {{package.likes}}
    - + Verified to work on Umbraco Cloud
    From b5dad01fdcad3d769de89fd5df33928376c802f8 Mon Sep 17 00:00:00 2001 From: Andy Butland Date: Tue, 8 Jun 2021 12:09:55 +0200 Subject: [PATCH 65/70] Update localisation alias to match default phrase. --- src/Umbraco.Web.UI.Client/src/views/packages/views/repo.html | 4 ++-- src/Umbraco.Web.UI/Umbraco/config/lang/en.xml | 2 +- src/Umbraco.Web.UI/Umbraco/config/lang/en_us.xml | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/Umbraco.Web.UI.Client/src/views/packages/views/repo.html b/src/Umbraco.Web.UI.Client/src/views/packages/views/repo.html index c29a914763..18fd7c55f5 100644 --- a/src/Umbraco.Web.UI.Client/src/views/packages/views/repo.html +++ b/src/Umbraco.Web.UI.Client/src/views/packages/views/repo.html @@ -65,7 +65,7 @@
    - Certified to work on Umbraco Cloud + Certified to work on Umbraco Cloud
    @@ -110,7 +110,7 @@
    - Verified to work on Umbraco Cloud + Verified to work on Umbraco Cloud
    diff --git a/src/Umbraco.Web.UI/Umbraco/config/lang/en.xml b/src/Umbraco.Web.UI/Umbraco/config/lang/en.xml index 727ca31dab..6c684d2413 100644 --- a/src/Umbraco.Web.UI/Umbraco/config/lang/en.xml +++ b/src/Umbraco.Web.UI/Umbraco/config/lang/en.xml @@ -1288,7 +1288,7 @@ To manage your website, simply open the Umbraco backoffice and start adding cont All done, your browser will now refresh, please wait... Please click 'Finish' to complete installation and reload the page. Uploading package... - Verified to work on Umbraco Cloud + Verified to work on Umbraco Cloud Paste with full formatting (Not recommended) diff --git a/src/Umbraco.Web.UI/Umbraco/config/lang/en_us.xml b/src/Umbraco.Web.UI/Umbraco/config/lang/en_us.xml index 4fc6fb7cdb..f56024dacd 100644 --- a/src/Umbraco.Web.UI/Umbraco/config/lang/en_us.xml +++ b/src/Umbraco.Web.UI/Umbraco/config/lang/en_us.xml @@ -1294,7 +1294,7 @@ To manage your website, simply open the Umbraco backoffice and start adding cont All done, your browser will now refresh, please wait... Please click 'Finish' to complete installation and reload the page. Uploading package... - Verified to work on Umbraco Cloud + Verified to work on Umbraco Cloud Paste with full formatting (Not recommended) From e70c3628513ca720c4b4098f60a0a3a43df399f2 Mon Sep 17 00:00:00 2001 From: Warren Buckley Date: Mon, 14 Jun 2021 12:20:06 +0100 Subject: [PATCH 66/70] Run `npm update caniuse-lite` --- src/Umbraco.Web.UI.Client/package-lock.json | 205 +++++--------------- src/Umbraco.Web.UI.Client/package.json | 4 +- 2 files changed, 55 insertions(+), 154 deletions(-) diff --git a/src/Umbraco.Web.UI.Client/package-lock.json b/src/Umbraco.Web.UI.Client/package-lock.json index 3f53638fc6..b2d811df89 100644 --- a/src/Umbraco.Web.UI.Client/package-lock.json +++ b/src/Umbraco.Web.UI.Client/package-lock.json @@ -1836,8 +1836,7 @@ "version": "1.3.1", "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.3.1.tgz", "integrity": "sha512-mLQ4i2QO1ytvGWFWmcngKO//JXAQueZvwEKtjgQFM4jIK0kU+ytMfplL8j+n5mspOfjHwoAg+9yhb7BwAHm36g==", - "dev": true, - "optional": true + "dev": true }, "base64id": { "version": "1.0.0", @@ -2084,7 +2083,6 @@ "resolved": "https://registry.npmjs.org/p-timeout/-/p-timeout-2.0.1.tgz", "integrity": "sha512-88em58dDVB/KzPEx1X0N3LwFfYZPyDc4B6eF38M1rk9VTZMbxXXgjugz8mmwpS9Ox4BDZ+t6t3QP5+/gazweIA==", "dev": true, - "optional": true, "requires": { "p-finally": "^1.0.0" } @@ -2126,7 +2124,6 @@ "resolved": "https://registry.npmjs.org/bl/-/bl-1.2.2.tgz", "integrity": "sha1-oWCRFxcQPAdBDO9j71Gzl8Alr5w=", "dev": true, - "optional": true, "requires": { "readable-stream": "^2.3.5", "safe-buffer": "^5.1.1" @@ -2136,15 +2133,13 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=", - "dev": true, - "optional": true + "dev": true }, "readable-stream": { "version": "2.3.6", "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz", "integrity": "sha1-sRwn2IuP8fvgcGQ8+UsMea4bCq8=", "dev": true, - "optional": true, "requires": { "core-util-is": "~1.0.0", "inherits": "~2.0.3", @@ -2160,7 +2155,6 @@ "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", "integrity": "sha1-nPFhG6YmhdcDCunkujQUnDrwP8g=", "dev": true, - "optional": true, "requires": { "safe-buffer": "~5.1.0" } @@ -2301,7 +2295,6 @@ "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.4.3.tgz", "integrity": "sha512-zvj65TkFeIt3i6aj5bIvJDzjjQQGs4o/sNoezg1F1kYap9Nu2jcUdpwzRSJTHMMzG0H7bZkn4rNQpImhuxWX2A==", "dev": true, - "optional": true, "requires": { "base64-js": "^1.0.2", "ieee754": "^1.1.4" @@ -2327,8 +2320,7 @@ "version": "0.2.13", "resolved": "https://registry.npmjs.org/buffer-crc32/-/buffer-crc32-0.2.13.tgz", "integrity": "sha1-DTM+PwDqxQqhRUq9MO+MKl2ackI=", - "dev": true, - "optional": true + "dev": true }, "buffer-equal": { "version": "1.0.0", @@ -2503,9 +2495,9 @@ } }, "caniuse-lite": { - "version": "1.0.30001168", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001168.tgz", - "integrity": "sha512-P2zmX7swIXKu+GMMR01TWa4csIKELTNnZKc+f1CjebmZJQtTAEXmpQSoKVJVVcvPGAA0TEYTOUp3VehavZSFPQ==", + "version": "1.0.30001237", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001237.tgz", + "integrity": "sha512-pDHgRndit6p1NR2GhzMbQ6CkRrp4VKuSsqbcLeOQppYPKOYkKT/6ZvZDvKJUqcmtyWIAHuZq3SVS2vc1egCZzw==", "dev": true }, "caseless": { @@ -2519,7 +2511,6 @@ "resolved": "https://registry.npmjs.org/caw/-/caw-2.0.1.tgz", "integrity": "sha512-Cg8/ZSBEa8ZVY9HspcGUYaK63d/bN7rqS3CYCzEGUxuYv6UlmcjzDUz2fCFFHyTvUW5Pk0I+3hkA3iXlIj6guA==", "dev": true, - "optional": true, "requires": { "get-proxy": "^2.0.0", "isurl": "^1.0.0-alpha5", @@ -2953,7 +2944,6 @@ "resolved": "https://registry.npmjs.org/commander/-/commander-2.8.1.tgz", "integrity": "sha1-Br42f+v9oMMwqh4qBy09yXYkJdQ=", "dev": true, - "optional": true, "requires": { "graceful-readlink": ">= 1.0.0" } @@ -3048,7 +3038,6 @@ "resolved": "https://registry.npmjs.org/config-chain/-/config-chain-1.1.12.tgz", "integrity": "sha512-a1eOIcu8+7lUInge4Rpf/n4Krkf3Dd9lqhljRzII1/Zno/kRtUWnznPO3jOKBmTEktkt3fkxisUcivoj0ebzoA==", "dev": true, - "optional": true, "requires": { "ini": "^1.3.4", "proto-list": "~1.2.1" @@ -3104,7 +3093,6 @@ "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.3.tgz", "integrity": "sha512-ExO0774ikEObIAEV9kDo50o+79VCUdEB6n6lzKgGwupcVeRlhrj3qGAfwq8G6uBJjkqLrhT0qEYFcWng8z1z0g==", "dev": true, - "optional": true, "requires": { "safe-buffer": "5.1.2" } @@ -3548,7 +3536,6 @@ "resolved": "https://registry.npmjs.org/decompress/-/decompress-4.2.0.tgz", "integrity": "sha1-eu3YVCflqS2s/lVnSnxQXpbQH50=", "dev": true, - "optional": true, "requires": { "decompress-tar": "^4.0.0", "decompress-tarbz2": "^4.0.0", @@ -3565,7 +3552,6 @@ "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-1.3.0.tgz", "integrity": "sha512-2w31R7SJtieJJnQtGc7RVL2StM2vGYVfqUOvUDxH6bC6aJTxPxTF0GnIgCyu7tjockiUWAYQRbxa7vKn34s5sQ==", "dev": true, - "optional": true, "requires": { "pify": "^3.0.0" }, @@ -3574,8 +3560,7 @@ "version": "3.0.0", "resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz", "integrity": "sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY=", - "dev": true, - "optional": true + "dev": true } } } @@ -3586,7 +3571,6 @@ "resolved": "https://registry.npmjs.org/decompress-response/-/decompress-response-3.3.0.tgz", "integrity": "sha1-gKTdMjdIOEv6JICDYirt7Jgq3/M=", "dev": true, - "optional": true, "requires": { "mimic-response": "^1.0.0" } @@ -3596,7 +3580,6 @@ "resolved": "https://registry.npmjs.org/decompress-tar/-/decompress-tar-4.1.1.tgz", "integrity": "sha512-JdJMaCrGpB5fESVyxwpCx4Jdj2AagLmv3y58Qy4GE6HMVjWz1FeVQk1Ct4Kye7PftcdOo/7U7UKzYBJgqnGeUQ==", "dev": true, - "optional": true, "requires": { "file-type": "^5.2.0", "is-stream": "^1.1.0", @@ -3607,8 +3590,7 @@ "version": "5.2.0", "resolved": "https://registry.npmjs.org/file-type/-/file-type-5.2.0.tgz", "integrity": "sha1-LdvqfHP/42No365J3DOMBYwritY=", - "dev": true, - "optional": true + "dev": true } } }, @@ -3617,7 +3599,6 @@ "resolved": "https://registry.npmjs.org/decompress-tarbz2/-/decompress-tarbz2-4.1.1.tgz", "integrity": "sha512-s88xLzf1r81ICXLAVQVzaN6ZmX4A6U4z2nMbOwobxkLoIIfjVMBg7TeguTUXkKeXni795B6y5rnvDw7rxhAq9A==", "dev": true, - "optional": true, "requires": { "decompress-tar": "^4.1.0", "file-type": "^6.1.0", @@ -3630,8 +3611,7 @@ "version": "6.2.0", "resolved": "https://registry.npmjs.org/file-type/-/file-type-6.2.0.tgz", "integrity": "sha512-YPcTBDV+2Tm0VqjybVd32MHdlEGAtuxS3VAYsumFokDSMG+ROT5wawGlnHDoz7bfMcMDt9hxuXvXwoKUx2fkOg==", - "dev": true, - "optional": true + "dev": true } } }, @@ -3640,7 +3620,6 @@ "resolved": "https://registry.npmjs.org/decompress-targz/-/decompress-targz-4.1.1.tgz", "integrity": "sha512-4z81Znfr6chWnRDNfFNqLwPvm4db3WuZkqV+UgXQzSngG3CEKdBkw5jrv3axjjL96glyiiKjsxJG3X6WBZwX3w==", "dev": true, - "optional": true, "requires": { "decompress-tar": "^4.1.1", "file-type": "^5.2.0", @@ -3651,8 +3630,7 @@ "version": "5.2.0", "resolved": "https://registry.npmjs.org/file-type/-/file-type-5.2.0.tgz", "integrity": "sha1-LdvqfHP/42No365J3DOMBYwritY=", - "dev": true, - "optional": true + "dev": true } } }, @@ -3661,7 +3639,6 @@ "resolved": "https://registry.npmjs.org/decompress-unzip/-/decompress-unzip-4.0.1.tgz", "integrity": "sha1-3qrM39FK6vhVePczroIQ+bSEj2k=", "dev": true, - "optional": true, "requires": { "file-type": "^3.8.0", "get-stream": "^2.2.0", @@ -3673,15 +3650,13 @@ "version": "3.9.0", "resolved": "https://registry.npmjs.org/file-type/-/file-type-3.9.0.tgz", "integrity": "sha1-JXoHg4TR24CHvESdEH1SpSZyuek=", - "dev": true, - "optional": true + "dev": true }, "get-stream": { "version": "2.3.1", "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-2.3.1.tgz", "integrity": "sha1-Xzj5PzRgCWZu4BUKBUFn+Rvdld4=", "dev": true, - "optional": true, "requires": { "object-assign": "^4.0.1", "pinkie-promise": "^2.0.0" @@ -3691,8 +3666,7 @@ "version": "4.1.1", "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=", - "dev": true, - "optional": true + "dev": true } } }, @@ -3974,8 +3948,7 @@ "version": "3.0.0", "resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz", "integrity": "sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY=", - "dev": true, - "optional": true + "dev": true } } }, @@ -3992,8 +3965,7 @@ "version": "0.1.4", "resolved": "https://registry.npmjs.org/duplexer3/-/duplexer3-0.1.4.tgz", "integrity": "sha1-7gHdHKwO08vH/b6jfcCo8c4ALOI=", - "dev": true, - "optional": true + "dev": true }, "duplexify": { "version": "3.7.1", @@ -4596,7 +4568,6 @@ "resolved": "https://registry.npmjs.org/execa/-/execa-0.7.0.tgz", "integrity": "sha1-lEvs00zEHuMqY6n68nrVpl/Fl3c=", "dev": true, - "optional": true, "requires": { "cross-spawn": "^5.0.1", "get-stream": "^3.0.0", @@ -4612,7 +4583,6 @@ "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-5.1.0.tgz", "integrity": "sha1-6L0O/uWPz/b4+UUQoKVUu/ojVEk=", "dev": true, - "optional": true, "requires": { "lru-cache": "^4.0.1", "shebang-command": "^1.2.0", @@ -4752,7 +4722,6 @@ "resolved": "https://registry.npmjs.org/ext-list/-/ext-list-2.2.2.tgz", "integrity": "sha512-u+SQgsubraE6zItfVA0tBuCBhfU9ogSRnsvygI7wht9TS510oLkBRXBsqopeUG/GBOIQyKZO9wjTqIu/sf5zFA==", "dev": true, - "optional": true, "requires": { "mime-db": "^1.28.0" } @@ -4762,7 +4731,6 @@ "resolved": "https://registry.npmjs.org/ext-name/-/ext-name-5.0.0.tgz", "integrity": "sha512-yblEwXAbGv1VQDmow7s38W77hzAgJAO50ztBLMcUyUBfxv1HC+LGwtiEN+Co6LtlqT/5uwVOxsD4TNIilWhwdQ==", "dev": true, - "optional": true, "requires": { "ext-list": "^2.0.0", "sort-keys-length": "^1.0.0" @@ -4997,7 +4965,6 @@ "resolved": "https://registry.npmjs.org/fd-slicer/-/fd-slicer-1.1.0.tgz", "integrity": "sha1-JcfInLH5B3+IkbvmHY85Dq4lbx4=", "dev": true, - "optional": true, "requires": { "pend": "~1.2.0" } @@ -5036,15 +5003,13 @@ "version": "2.0.0", "resolved": "https://registry.npmjs.org/filename-reserved-regex/-/filename-reserved-regex-2.0.0.tgz", "integrity": "sha1-q/c9+rc10EVECr/qLZHzieu/oik=", - "dev": true, - "optional": true + "dev": true }, "filenamify": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/filenamify/-/filenamify-2.1.0.tgz", "integrity": "sha512-ICw7NTT6RsDp2rnYKVd8Fu4cr6ITzGy3+u4vUujPkabyaz+03F24NWEX7fs5fp+kBonlaqPH8fAO2NM+SXt/JA==", "dev": true, - "optional": true, "requires": { "filename-reserved-regex": "^2.0.0", "strip-outer": "^1.0.0", @@ -5405,8 +5370,7 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/fs-constants/-/fs-constants-1.0.0.tgz", "integrity": "sha1-a+Dem+mYzhavivwkSXue6bfM2a0=", - "dev": true, - "optional": true + "dev": true }, "fs-mkdirp-stream": { "version": "1.0.0", @@ -5453,8 +5417,7 @@ "ansi-regex": { "version": "2.1.1", "bundled": true, - "dev": true, - "optional": true + "dev": true }, "aproba": { "version": "1.2.0", @@ -5475,14 +5438,12 @@ "balanced-match": { "version": "1.0.0", "bundled": true, - "dev": true, - "optional": true + "dev": true }, "brace-expansion": { "version": "1.1.11", "bundled": true, "dev": true, - "optional": true, "requires": { "balanced-match": "^1.0.0", "concat-map": "0.0.1" @@ -5497,20 +5458,17 @@ "code-point-at": { "version": "1.1.0", "bundled": true, - "dev": true, - "optional": true + "dev": true }, "concat-map": { "version": "0.0.1", "bundled": true, - "dev": true, - "optional": true + "dev": true }, "console-control-strings": { "version": "1.1.0", "bundled": true, - "dev": true, - "optional": true + "dev": true }, "core-util-is": { "version": "1.0.2", @@ -5627,8 +5585,7 @@ "inherits": { "version": "2.0.3", "bundled": true, - "dev": true, - "optional": true + "dev": true }, "ini": { "version": "1.3.5", @@ -5640,7 +5597,6 @@ "version": "1.0.0", "bundled": true, "dev": true, - "optional": true, "requires": { "number-is-nan": "^1.0.0" } @@ -5655,7 +5611,6 @@ "version": "3.0.4", "bundled": true, "dev": true, - "optional": true, "requires": { "brace-expansion": "^1.1.7" } @@ -5663,14 +5618,12 @@ "minimist": { "version": "0.0.8", "bundled": true, - "dev": true, - "optional": true + "dev": true }, "minipass": { "version": "2.3.5", "bundled": true, "dev": true, - "optional": true, "requires": { "safe-buffer": "^5.1.2", "yallist": "^3.0.0" @@ -5689,7 +5642,6 @@ "version": "0.5.1", "bundled": true, "dev": true, - "optional": true, "requires": { "minimist": "0.0.8" } @@ -5770,8 +5722,7 @@ "number-is-nan": { "version": "1.0.1", "bundled": true, - "dev": true, - "optional": true + "dev": true }, "object-assign": { "version": "4.1.1", @@ -5783,7 +5734,6 @@ "version": "1.4.0", "bundled": true, "dev": true, - "optional": true, "requires": { "wrappy": "1" } @@ -5869,8 +5819,7 @@ "safe-buffer": { "version": "5.1.2", "bundled": true, - "dev": true, - "optional": true + "dev": true }, "safer-buffer": { "version": "2.1.2", @@ -5906,7 +5855,6 @@ "version": "1.0.2", "bundled": true, "dev": true, - "optional": true, "requires": { "code-point-at": "^1.0.0", "is-fullwidth-code-point": "^1.0.0", @@ -5926,7 +5874,6 @@ "version": "3.0.1", "bundled": true, "dev": true, - "optional": true, "requires": { "ansi-regex": "^2.0.0" } @@ -5970,14 +5917,12 @@ "wrappy": { "version": "1.0.2", "bundled": true, - "dev": true, - "optional": true + "dev": true }, "yallist": { "version": "3.0.3", "bundled": true, - "dev": true, - "optional": true + "dev": true } } }, @@ -6004,7 +5949,6 @@ "resolved": "https://registry.npmjs.org/get-proxy/-/get-proxy-2.1.0.tgz", "integrity": "sha512-zmZIaQTWnNQb4R4fJUEp/FC51eZsc6EkErspy3xtIYStaq8EB/hDIWipxsal+E8rz0qD7f2sL/NA9Xee4RInJw==", "dev": true, - "optional": true, "requires": { "npm-conf": "^1.1.0" } @@ -6013,15 +5957,13 @@ "version": "4.0.1", "resolved": "https://registry.npmjs.org/get-stdin/-/get-stdin-4.0.1.tgz", "integrity": "sha1-uWjGsKBDhDJJAui/Gl3zJXmkUP4=", - "dev": true, - "optional": true + "dev": true }, "get-stream": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-3.0.0.tgz", "integrity": "sha1-jpQ9E1jcN1VQVOy+LtsFqhdO3hQ=", - "dev": true, - "optional": true + "dev": true }, "get-value": { "version": "2.0.6", @@ -6336,8 +6278,7 @@ "version": "1.0.1", "resolved": "https://registry.npmjs.org/graceful-readlink/-/graceful-readlink-1.0.1.tgz", "integrity": "sha1-TK+tdrxi8C+gObL5Tpo906ORpyU=", - "dev": true, - "optional": true + "dev": true }, "growly": { "version": "1.3.0", @@ -7108,8 +7049,7 @@ "version": "1.4.2", "resolved": "https://registry.npmjs.org/has-symbol-support-x/-/has-symbol-support-x-1.4.2.tgz", "integrity": "sha512-3ToOva++HaW+eCpgqZrCfN51IPB+7bJNVT6CUATzueB5Heb8o6Nam0V3HG5dlDvZU1Gn5QLcbahiKw/XVk5JJw==", - "dev": true, - "optional": true + "dev": true }, "has-symbols": { "version": "1.0.0", @@ -7122,7 +7062,6 @@ "resolved": "https://registry.npmjs.org/has-to-string-tag-x/-/has-to-string-tag-x-1.4.1.tgz", "integrity": "sha512-vdbKfmw+3LoOYVr+mtxHaX5a96+0f3DljYd8JOqvOLsf5mw2Otda2qCDT9qRqLAhrjyQ0h7ual5nOiASpsGNFw==", "dev": true, - "optional": true, "requires": { "has-symbol-support-x": "^1.4.1" } @@ -7322,8 +7261,7 @@ "version": "1.1.13", "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.1.13.tgz", "integrity": "sha512-4vf7I2LYV/HaWerSo3XmlMkp5eZ83i+/CDluXi/IGTs/O1sejBNhTtnxzmRZfvOUqj7lZjqHkeTvpgSFDlWZTg==", - "dev": true, - "optional": true + "dev": true }, "ignore": { "version": "4.0.6", @@ -7453,7 +7391,6 @@ "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-2.1.0.tgz", "integrity": "sha1-ji1INIdCEhtKghi3oTfppSBJ3IA=", "dev": true, - "optional": true, "requires": { "repeating": "^2.0.0" } @@ -7781,7 +7718,6 @@ "resolved": "https://registry.npmjs.org/is-finite/-/is-finite-1.0.2.tgz", "integrity": "sha1-zGZ3aVYCvlUO8R6LSqYwU0K20Ko=", "dev": true, - "optional": true, "requires": { "number-is-nan": "^1.0.0" } @@ -7834,8 +7770,7 @@ "version": "4.0.1", "resolved": "https://registry.npmjs.org/is-natural-number/-/is-natural-number-4.0.1.tgz", "integrity": "sha1-q5124dtM7VHjXeDHLr7PCfc0zeg=", - "dev": true, - "optional": true + "dev": true }, "is-negated-glob": { "version": "1.0.0", @@ -7873,15 +7808,13 @@ "version": "1.0.1", "resolved": "https://registry.npmjs.org/is-object/-/is-object-1.0.1.tgz", "integrity": "sha1-iVJojF7C/9awPsyF52ngKQMINHA=", - "dev": true, - "optional": true + "dev": true }, "is-plain-obj": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-1.1.0.tgz", "integrity": "sha1-caUMhCnfync8kqOQpKA7OfzVHT4=", - "dev": true, - "optional": true + "dev": true }, "is-plain-object": { "version": "2.0.4", @@ -7951,15 +7884,13 @@ "version": "1.2.0", "resolved": "https://registry.npmjs.org/is-retry-allowed/-/is-retry-allowed-1.2.0.tgz", "integrity": "sha512-RUbUeKwvm3XG2VYamhJL1xFktgjvPzL0Hq8C+6yrWIswDy3BIXGqCxhxkc30N9jqK311gVU137K8Ei55/zVJRg==", - "dev": true, - "optional": true + "dev": true }, "is-stream": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-1.1.0.tgz", "integrity": "sha1-EtSj3U5o4Lec6428hBc66A2RykQ=", - "dev": true, - "optional": true + "dev": true }, "is-svg": { "version": "3.0.0", @@ -8056,7 +7987,6 @@ "resolved": "https://registry.npmjs.org/isurl/-/isurl-1.0.0.tgz", "integrity": "sha512-1P/yWsxPlDtn7QeRD+ULKQPaIaN6yF368GZ2vDfv0AL0NwpStafjWCDDdn0k8wgFMWpVAqG7oJhxHnlud42i9w==", "dev": true, - "optional": true, "requires": { "has-to-string-tag-x": "^1.2.0", "is-object": "^1.0.1" @@ -8969,8 +8899,7 @@ "version": "1.0.1", "resolved": "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-1.0.1.tgz", "integrity": "sha1-b54wtHCE2XGnyCD/FabFFnt0wm8=", - "dev": true, - "optional": true + "dev": true }, "lpad-align": { "version": "1.1.2", @@ -9040,8 +8969,7 @@ "version": "1.0.1", "resolved": "https://registry.npmjs.org/map-obj/-/map-obj-1.0.1.tgz", "integrity": "sha1-2TPOuSBdgr3PSIb2dCvcK03qFG0=", - "dev": true, - "optional": true + "dev": true }, "map-visit": { "version": "1.0.0", @@ -9211,8 +9139,7 @@ "version": "1.0.1", "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-1.0.1.tgz", "integrity": "sha512-j5EctnkH7amfV/q5Hgmoal1g2QHFJRraOtmx0JpIqkxhBhI/lJSl1nMpQ45hVarwNETOoWEimndZ4QK0RHxuxQ==", - "dev": true, - "optional": true + "dev": true }, "minimatch": { "version": "3.0.4", @@ -9435,9 +9362,9 @@ "dev": true }, "nouislider": { - "version": "14.6.3", - "resolved": "https://registry.npmjs.org/nouislider/-/nouislider-14.6.3.tgz", - "integrity": "sha512-/3tAqsWY2JYW9vd7bC14bFRA1P9A+pRHOtKmoMsyfnB0fQcd1UFx2pdY1Ey5wAUzTnXTesmYaEo/ecLVETijIQ==" + "version": "14.6.4", + "resolved": "https://registry.npmjs.org/nouislider/-/nouislider-14.6.4.tgz", + "integrity": "sha512-PVCGYl+aC7/nVEbW61ypJWfuW3UCpvctz/luxpt4byxxli1FFyjBX9NIiy4Yak9AaO6a5BkPGfFYMCW4eg3eeQ==" }, "now-and-later": { "version": "2.0.1", @@ -12547,7 +12474,6 @@ "resolved": "https://registry.npmjs.org/npm-conf/-/npm-conf-1.1.3.tgz", "integrity": "sha512-Yic4bZHJOt9RCFbRP3GgpqhScOY4HH3V2P8yBj6CeYq118Qr+BLXqT2JvpJ00mryLESpgOxf5XlFv4ZjXxLScw==", "dev": true, - "optional": true, "requires": { "config-chain": "^1.1.11", "pify": "^3.0.0" @@ -12557,8 +12483,7 @@ "version": "3.0.0", "resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz", "integrity": "sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY=", - "dev": true, - "optional": true + "dev": true } } }, @@ -12567,7 +12492,6 @@ "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-2.0.2.tgz", "integrity": "sha1-NakjLfo11wZ7TLLd8jV7GHFTbF8=", "dev": true, - "optional": true, "requires": { "path-key": "^2.0.0" } @@ -12929,8 +12853,7 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/p-finally/-/p-finally-1.0.0.tgz", "integrity": "sha1-P7z7FbiZpEEjs0ttzBi3JDNqLK4=", - "dev": true, - "optional": true + "dev": true }, "p-is-promise": { "version": "1.1.0", @@ -12967,7 +12890,6 @@ "resolved": "https://registry.npmjs.org/p-timeout/-/p-timeout-1.2.1.tgz", "integrity": "sha1-XrOzU7f86Z8QGhA4iAuwVOu+o4Y=", "dev": true, - "optional": true, "requires": { "p-finally": "^1.0.0" } @@ -13158,8 +13080,7 @@ "version": "1.2.0", "resolved": "https://registry.npmjs.org/pend/-/pend-1.2.0.tgz", "integrity": "sha1-elfrVQpng/kRUzH89GY9XI4AelA=", - "dev": true, - "optional": true + "dev": true }, "performance-now": { "version": "2.1.0", @@ -13667,8 +13588,7 @@ "version": "1.2.4", "resolved": "https://registry.npmjs.org/proto-list/-/proto-list-1.2.4.tgz", "integrity": "sha1-IS1b/hMYMGpCD2QCuOJv85ZHqEk=", - "dev": true, - "optional": true + "dev": true }, "prr": { "version": "1.0.1", @@ -14024,7 +13944,6 @@ "resolved": "https://registry.npmjs.org/repeating/-/repeating-2.0.1.tgz", "integrity": "sha1-UhTFOpJtNVJwdSf7q0FdvAjQbdo=", "dev": true, - "optional": true, "requires": { "is-finite": "^1.0.0" } @@ -14386,7 +14305,6 @@ "resolved": "https://registry.npmjs.org/seek-bzip/-/seek-bzip-1.0.5.tgz", "integrity": "sha1-z+kXyz0nS8/6x5J1ivUxc+sfq9w=", "dev": true, - "optional": true, "requires": { "commander": "~2.8.1" } @@ -14789,7 +14707,6 @@ "resolved": "https://registry.npmjs.org/sort-keys/-/sort-keys-1.1.2.tgz", "integrity": "sha1-RBttTTRnmPG05J6JIK37oOVD+a0=", "dev": true, - "optional": true, "requires": { "is-plain-obj": "^1.0.0" } @@ -14799,7 +14716,6 @@ "resolved": "https://registry.npmjs.org/sort-keys-length/-/sort-keys-length-1.0.1.tgz", "integrity": "sha1-nLb09OnkgVWmqgZx7dM2/xR5oYg=", "dev": true, - "optional": true, "requires": { "sort-keys": "^1.0.0" } @@ -15130,7 +15046,6 @@ "resolved": "https://registry.npmjs.org/strip-dirs/-/strip-dirs-2.1.0.tgz", "integrity": "sha512-JOCxOeKLm2CAS73y/U4ZeZPTkE+gNVCzKt7Eox84Iej1LT/2pTWYpZKJuxwQpvX1LiZb1xokNR7RLfuBAa7T3g==", "dev": true, - "optional": true, "requires": { "is-natural-number": "^4.0.1" } @@ -15139,8 +15054,7 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/strip-eof/-/strip-eof-1.0.0.tgz", "integrity": "sha1-u0P/VZim6wXYm1n80SnJgzE2Br8=", - "dev": true, - "optional": true + "dev": true }, "strip-indent": { "version": "1.0.1", @@ -15163,7 +15077,6 @@ "resolved": "https://registry.npmjs.org/strip-outer/-/strip-outer-1.0.1.tgz", "integrity": "sha1-sv0qv2YEudHmATBXGV34Nrip1jE=", "dev": true, - "optional": true, "requires": { "escape-string-regexp": "^1.0.2" } @@ -15289,7 +15202,6 @@ "resolved": "https://registry.npmjs.org/tar-stream/-/tar-stream-1.6.2.tgz", "integrity": "sha1-jqVdqzeXIlPZqa+Q/c1VmuQ1xVU=", "dev": true, - "optional": true, "requires": { "bl": "^1.0.0", "buffer-alloc": "^1.2.0", @@ -15304,15 +15216,13 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=", - "dev": true, - "optional": true + "dev": true }, "readable-stream": { "version": "2.3.6", "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz", "integrity": "sha1-sRwn2IuP8fvgcGQ8+UsMea4bCq8=", "dev": true, - "optional": true, "requires": { "core-util-is": "~1.0.0", "inherits": "~2.0.3", @@ -15328,7 +15238,6 @@ "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", "integrity": "sha1-nPFhG6YmhdcDCunkujQUnDrwP8g=", "dev": true, - "optional": true, "requires": { "safe-buffer": "~5.1.0" } @@ -15339,15 +15248,13 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/temp-dir/-/temp-dir-1.0.0.tgz", "integrity": "sha1-CnwOom06Oa+n4OvqnB/AvE2qAR0=", - "dev": true, - "optional": true + "dev": true }, "tempfile": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/tempfile/-/tempfile-2.0.0.tgz", "integrity": "sha1-awRGhWqbERTRhW/8vlCczLCXcmU=", "dev": true, - "optional": true, "requires": { "temp-dir": "^1.0.0", "uuid": "^3.0.1" @@ -15442,8 +15349,7 @@ "version": "4.0.1", "resolved": "https://registry.npmjs.org/timed-out/-/timed-out-4.0.1.tgz", "integrity": "sha1-8y6srFoXW+ol1/q1Zas+2HQe9W8=", - "dev": true, - "optional": true + "dev": true }, "timers-ext": { "version": "0.1.7", @@ -15500,8 +15406,7 @@ "version": "1.1.1", "resolved": "https://registry.npmjs.org/to-buffer/-/to-buffer-1.1.1.tgz", "integrity": "sha1-STvUj2LXxD/N7TE6A9ytsuEhOoA=", - "dev": true, - "optional": true + "dev": true }, "to-fast-properties": { "version": "2.0.0", @@ -15605,7 +15510,6 @@ "resolved": "https://registry.npmjs.org/trim-repeated/-/trim-repeated-1.0.0.tgz", "integrity": "sha1-42RqLqTokTEr9+rObPsFOAvAHCE=", "dev": true, - "optional": true, "requires": { "escape-string-regexp": "^1.0.2" } @@ -15742,7 +15646,6 @@ "resolved": "https://registry.npmjs.org/unbzip2-stream/-/unbzip2-stream-1.3.3.tgz", "integrity": "sha512-fUlAF7U9Ah1Q6EieQ4x4zLNejrRvDWUYmxXUpN3uziFYCHapjWFaCAnreY9bGgxzaMCFAPPpYNng57CypwJVhg==", "dev": true, - "optional": true, "requires": { "buffer": "^5.2.1", "through": "^2.3.8" @@ -15943,8 +15846,7 @@ "version": "1.0.1", "resolved": "https://registry.npmjs.org/url-to-options/-/url-to-options-1.0.1.tgz", "integrity": "sha1-FQWgOiiaSMvXpDTvuu7FBV9WM6k=", - "dev": true, - "optional": true + "dev": true }, "use": { "version": "3.1.1", @@ -16440,7 +16342,6 @@ "resolved": "https://registry.npmjs.org/yauzl/-/yauzl-2.10.0.tgz", "integrity": "sha1-x+sXyT4RLLEIb6bY5R+wZnt5pfk=", "dev": true, - "optional": true, "requires": { "buffer-crc32": "~0.2.3", "fd-slicer": "~1.1.0" diff --git a/src/Umbraco.Web.UI.Client/package.json b/src/Umbraco.Web.UI.Client/package.json index 6514f2f217..d0f1c1cb99 100644 --- a/src/Umbraco.Web.UI.Client/package.json +++ b/src/Umbraco.Web.UI.Client/package.json @@ -54,7 +54,7 @@ "@babel/core": "7.6.4", "@babel/preset-env": "7.6.3", "autoprefixer": "9.6.5", - "caniuse-lite": "^1.0.30001037", + "caniuse-lite": "^1.0.30001237", "cssnano": "4.1.10", "fs": "0.0.2", "gulp": "4.0.2", @@ -77,8 +77,8 @@ "jasmine-core": "3.5.0", "jsdom": "16.4.0", "karma": "4.4.1", - "karma-jsdom-launcher": "^8.0.2", "karma-jasmine": "2.0.1", + "karma-jsdom-launcher": "^8.0.2", "karma-junit-reporter": "2.0.1", "karma-spec-reporter": "0.0.32", "less": "3.10.3", From 348d1676cd7b82a70f82496619ad34722c0bdadf Mon Sep 17 00:00:00 2001 From: Andy Butland Date: Sat, 29 May 2021 07:29:00 +0200 Subject: [PATCH 67/70] Handle only single content type event to avoid reloading the content and media cache multiple times after a deployment containing more than one changed document type. --- .../Cache/DistributedCacheBinderTests.cs | 16 +++++- .../Cache/DistributedCacheBinder.cs | 54 +++++++++++++++++-- 2 files changed, 66 insertions(+), 4 deletions(-) diff --git a/src/Umbraco.Tests/Cache/DistributedCacheBinderTests.cs b/src/Umbraco.Tests/Cache/DistributedCacheBinderTests.cs index e446e049b6..00a33c0b6c 100644 --- a/src/Umbraco.Tests/Cache/DistributedCacheBinderTests.cs +++ b/src/Umbraco.Tests/Cache/DistributedCacheBinderTests.cs @@ -9,6 +9,7 @@ using Umbraco.Core.Events; using Umbraco.Core.Models; using Umbraco.Core.Models.Membership; using Umbraco.Core.Services; +using Umbraco.Core.Services.Changes; using Umbraco.Tests.Testing; using Umbraco.Tests.Testing.Objects.Accessors; using Umbraco.Web; @@ -148,7 +149,6 @@ namespace Umbraco.Tests.Cache { // works because that event definition maps to an empty handler new EventDefinition>(null, Current.Services.ContentTypeService, new SaveEventArgs(Enumerable.Empty()), "Saved"), - }; var umbracoContextFactory = new UmbracoContextFactory( @@ -166,5 +166,19 @@ namespace Umbraco.Tests.Cache var refreshers = new DistributedCacheBinder(null, umbracoContextFactory, null); refreshers.HandleEvents(definitions); } + + [Test] + public void OnlyHandlesOnContentTypeEvent() + { + var definitions = new IEventDefinition[] + { + new EventDefinition.EventArgs>(null, Current.Services.ContentTypeService, new ContentTypeChange.EventArgs(Enumerable.Empty>()), "Changed"), + new EventDefinition>(null, Current.Services.ContentTypeService, new SaveEventArgs(Enumerable.Empty()), "Saved"), + new EventDefinition.EventArgs>(null, Current.Services.ContentTypeService, new ContentTypeChange.EventArgs(Enumerable.Empty>()), "Changed"), + new EventDefinition>(null, Current.Services.ContentTypeService, new SaveEventArgs(Enumerable.Empty()), "Saved"), + }; + var result = DistributedCacheBinder.GetReducedEventList(definitions); + Assert.AreEqual(1, result.Count()); + } } } diff --git a/src/Umbraco.Web/Cache/DistributedCacheBinder.cs b/src/Umbraco.Web/Cache/DistributedCacheBinder.cs index 3ee24a23bf..e3a5a01d54 100644 --- a/src/Umbraco.Web/Cache/DistributedCacheBinder.cs +++ b/src/Umbraco.Web/Cache/DistributedCacheBinder.cs @@ -61,11 +61,15 @@ namespace Umbraco.Web.Cache /// public void HandleEvents(IEnumerable events) { - // ensure we run with an UmbracoContext, because this may run in a background task, - // yet developers may be using the 'current' UmbracoContext in the event handlers + // Ensure we run with an UmbracoContext, because this may run in a background task, + // yet developers may be using the 'current' UmbracoContext in the event handlers. using (_umbracoContextFactory.EnsureUmbracoContext()) { - foreach (var e in events) + // When it comes to content types types, a change to any single one will trigger a reload of the content and media caches. + // As far as I (AB) can tell, there's no type specific logic here, they all clear caches for all content types, and trigger a reload of all content and media. + // We also have events registered for Changed and Saved, which do the same thing, so really only need one of these. + // Hence if we have more than one document or media types, we can and should only handle one of the events for one, to avoid repeated cache reloads. + foreach (var e in GetReducedEventList(events)) { var handler = FindHandler(e); if (handler == null) @@ -80,5 +84,49 @@ namespace Umbraco.Web.Cache } } } + + // Internal for tests + internal static IEnumerable GetReducedEventList(IEnumerable events) + { + var reducedEvents = new List(); + + var gotDoumentType = false; + var gotMediaType = false; + var gotMemberType = false; + + foreach (var evt in events) + { + if (evt.Sender.ToString().Contains(nameof(Core.Services.Implement.ContentTypeService))) + { + if (gotDoumentType == false) + { + reducedEvents.Add(evt); + gotDoumentType = true; + } + } + else if (evt.Sender.ToString().Contains(nameof(Core.Services.Implement.MediaTypeService))) + { + if (gotMediaType == false) + { + reducedEvents.Add(evt); + gotMediaType = true; + } + } + else if (evt.Sender.ToString().Contains(nameof(Core.Services.Implement.MemberTypeService))) + { + if (gotMemberType == false) + { + reducedEvents.Add(evt); + gotMemberType = true; + } + } + else + { + reducedEvents.Add(evt); + } + } + + return reducedEvents; + } } } From dc334c10154820cf0958e901dd6c00906084727a Mon Sep 17 00:00:00 2001 From: Warren Buckley Date: Wed, 16 Jun 2021 10:00:29 +0100 Subject: [PATCH 68/70] Automated install user with Environment Variables & unattended.user.json (#9930) * Try to update admin user unattended This will fail because we're not in install runtime state * Create a new user instead of trying to update the default admin * Create a new user instead of trying to update the default admin * Use same logic from NewInstallStep to modify the SuperUser aka -1 * Add back stuff after merge conflict from v8/dev * Add event to be raised * Trying to wire up events * Remove commented out code - just need to figure out why event is not hit/triggered * Read Appsettings as opposed to ENV variables * Use a JSON file that deletes itself as storing secrets in web.config will be accidently committed * Remove component based event - Component were only initialized after DB creation * Move UnattendedInstall down after _factory * Remove commented out code * Fixed issue where upgrader UI would show up - needed to recheck the Runtimelevel after UnattenedInstall * Apply suggestions from code review - Thanks Marc :) Co-authored-by: Marc Goodson Co-authored-by: Mole Co-authored-by: Marc Goodson --- .../Events/UnattendedInstallEventArgs.cs | 9 ++ src/Umbraco.Core/Runtime/CoreRuntime.cs | 137 +++++++++++++++++- src/Umbraco.Core/Umbraco.Core.csproj | 1 + 3 files changed, 141 insertions(+), 6 deletions(-) create mode 100644 src/Umbraco.Core/Events/UnattendedInstallEventArgs.cs diff --git a/src/Umbraco.Core/Events/UnattendedInstallEventArgs.cs b/src/Umbraco.Core/Events/UnattendedInstallEventArgs.cs new file mode 100644 index 0000000000..3029126dea --- /dev/null +++ b/src/Umbraco.Core/Events/UnattendedInstallEventArgs.cs @@ -0,0 +1,9 @@ +namespace Umbraco.Core.Events +{ + /// + /// Used to notify that an Unattended install has completed + /// + public class UnattendedInstallEventArgs : System.ComponentModel.CancelEventArgs + { + } +} diff --git a/src/Umbraco.Core/Runtime/CoreRuntime.cs b/src/Umbraco.Core/Runtime/CoreRuntime.cs index 25bb5d3151..4345469f54 100644 --- a/src/Umbraco.Core/Runtime/CoreRuntime.cs +++ b/src/Umbraco.Core/Runtime/CoreRuntime.cs @@ -1,13 +1,17 @@ -using System; +using Newtonsoft.Json; +using System; using System.Collections.Generic; using System.Diagnostics; +using System.IO; using System.Linq; +using System.Runtime.Serialization; using System.Threading; using System.Web; using System.Web.Hosting; using Umbraco.Core.Cache; using Umbraco.Core.Composing; using Umbraco.Core.Configuration; +using Umbraco.Core.Events; using Umbraco.Core.Exceptions; using Umbraco.Core.IO; using Umbraco.Core.Logging; @@ -16,6 +20,9 @@ using Umbraco.Core.Migrations.Install; using Umbraco.Core.Migrations.Upgrade; using Umbraco.Core.Persistence; using Umbraco.Core.Persistence.Mappers; +using Umbraco.Core.Scoping; +using Umbraco.Core.Security; +using Umbraco.Core.Services; using Umbraco.Core.Sync; namespace Umbraco.Core.Runtime @@ -119,6 +126,9 @@ namespace Umbraco.Core.Runtime try { + // Setup event listener + UnattendedInstalled += CoreRuntime_UnattendedInstalled; + // throws if not full-trust new AspNetHostingPermission(AspNetHostingPermissionLevel.Unrestricted).Demand(); @@ -162,8 +172,7 @@ namespace Umbraco.Core.Runtime // run handlers RuntimeOptions.DoRuntimeEssentials(composition, appCaches, typeLoader, databaseFactory); - // determines if unattended install is enabled and performs it if required - DoUnattendedInstall(databaseFactory); + // register runtime-level services // there should be none, really - this is here "just in case" @@ -190,6 +199,13 @@ namespace Umbraco.Core.Runtime // create the factory _factory = Current.Factory = composition.CreateFactory(); + // determines if unattended install is enabled and performs it if required + DoUnattendedInstall(databaseFactory); + + // determine our runtime level (AFTER UNATTENDED INSTALL) + // TODO: Feels kinda weird to call this again + DetermineRuntimeLevel(databaseFactory, ProfilingLogger); + // if level is Run and reason is UpgradeMigrations, that means we need to perform an unattended upgrade if (_state.Reason == RuntimeLevelReason.UpgradeMigrations && _state.Level == RuntimeLevel.Run) { @@ -203,8 +219,6 @@ namespace Umbraco.Core.Runtime // create & initialize the components _components = _factory.GetInstance(); _components.Initialize(); - - } catch (Exception e) { @@ -242,6 +256,93 @@ namespace Umbraco.Core.Runtime return _factory; } + private void CoreRuntime_UnattendedInstalled(IRuntime sender, UnattendedInstallEventArgs e) + { + var unattendedName = Environment.GetEnvironmentVariable("UnattendedUserName"); + var unattendedEmail = Environment.GetEnvironmentVariable("UnattendedUserEmail"); + var unattendedPassword = Environment.GetEnvironmentVariable("UnattendedUserPassword"); + + var fileExists = false; + var filePath = IOHelper.MapPath("~/App_Data/unattended.user.json"); + + // No values store in ENV vars - try fallback file of /app_data/unattended.user.json + if (unattendedName.IsNullOrWhiteSpace() + || unattendedEmail.IsNullOrWhiteSpace() + || unattendedPassword.IsNullOrWhiteSpace()) + { + + fileExists = File.Exists(filePath); + if (fileExists == false) + { + return; + } + + // Attempt to deserialize JSON + try + { + var fileContents = File.ReadAllText(filePath); + var credentials = JsonConvert.DeserializeObject(fileContents); + + unattendedName = credentials.Name; + unattendedEmail = credentials.Email; + unattendedPassword = credentials.Password; + } + catch (Exception ex) + { + + throw; + } + } + + // ENV Variables & JSON still empty + if (unattendedName.IsNullOrWhiteSpace() + || unattendedEmail.IsNullOrWhiteSpace() + || unattendedPassword.IsNullOrWhiteSpace()) + { + return; + } + + + // Update user details + var currentProvider = MembershipProviderExtensions.GetUsersMembershipProvider(); + var admin = Current.Services.UserService.GetUserById(Constants.Security.SuperUserId); + if (admin == null) + { + throw new InvalidOperationException("Could not find the super user!"); + } + + var membershipUser = currentProvider.GetUser(Constants.Security.SuperUserId, true); + if (membershipUser == null) + { + throw new InvalidOperationException($"No user found in membership provider with id of {Constants.Security.SuperUserId}."); + } + + try + { + var success = membershipUser.ChangePassword("default", unattendedPassword.Trim()); + if (success == false) + { + throw new FormatException("Password must be at least " + currentProvider.MinRequiredPasswordLength + " characters long and contain at least " + currentProvider.MinRequiredNonAlphanumericCharacters + " symbols"); + } + } + catch (Exception) + { + throw new FormatException("Password must be at least " + currentProvider.MinRequiredPasswordLength + " characters long and contain at least " + currentProvider.MinRequiredNonAlphanumericCharacters + " symbols"); + } + + admin.Email = unattendedEmail.Trim(); + admin.Name = unattendedName.Trim(); + admin.Username = unattendedEmail.Trim(); + + Current.Services.UserService.Save(admin); + + // Delete JSON file if it existed to tidy + if (fileExists) + { + File.Delete(filePath); + } + } + private void DoUnattendedInstall(IUmbracoDatabaseFactory databaseFactory) { // unattended install is not enabled @@ -285,6 +386,11 @@ namespace Umbraco.Core.Runtime var creator = new DatabaseSchemaCreator(database, Logger); creator.InitializeDatabaseSchema(); database.CompleteTransaction(); + + // Emit an event that unattended install completed + // Then this event can be listened for and create an unattended user + UnattendedInstalled?.Invoke(this, new UnattendedInstallEventArgs()); + Logger.Info("Unattended install completed."); } catch (Exception ex) @@ -397,6 +503,7 @@ namespace Umbraco.Core.Runtime public virtual void Terminate() { _components?.Terminate(); + UnattendedInstalled -= CoreRuntime_UnattendedInstalled; } /// @@ -404,7 +511,7 @@ namespace Umbraco.Core.Runtime /// public virtual void Compose(Composition composition) { - // nothing + // Nothing } #region Getters @@ -465,5 +572,23 @@ namespace Umbraco.Core.Runtime } #endregion + + /// + /// Event to be used to notify when the Unattended Install has finished + /// + public static event TypedEventHandler UnattendedInstalled; + + [DataContract] + public class UnattendedUserConfig + { + [DataMember(Name = "name")] + public string Name { get; set; } + + [DataMember(Name = "email")] + public string Email { get; set; } + + [DataMember(Name = "password")] + public string Password { get; set; } + } } } diff --git a/src/Umbraco.Core/Umbraco.Core.csproj b/src/Umbraco.Core/Umbraco.Core.csproj index 0a453ad75f..14444f5d59 100755 --- a/src/Umbraco.Core/Umbraco.Core.csproj +++ b/src/Umbraco.Core/Umbraco.Core.csproj @@ -131,6 +131,7 @@ + From 585f7bb57135ab31e36b782b78e0e151d8503625 Mon Sep 17 00:00:00 2001 From: Mads Rasmussen Date: Thu, 17 Jun 2021 09:40:07 +0200 Subject: [PATCH 69/70] Make dashboards support deep linking (#10283) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Ronald Barendse Co-authored-by: Niels Lyngsø --- .../src/views/common/dashboard.controller.js | 59 +++++++++++++------ 1 file changed, 40 insertions(+), 19 deletions(-) diff --git a/src/Umbraco.Web.UI.Client/src/views/common/dashboard.controller.js b/src/Umbraco.Web.UI.Client/src/views/common/dashboard.controller.js index e788e6fc9b..d7d5153956 100644 --- a/src/Umbraco.Web.UI.Client/src/views/common/dashboard.controller.js +++ b/src/Umbraco.Web.UI.Client/src/views/common/dashboard.controller.js @@ -7,38 +7,59 @@ * Controls the dashboards of the application * */ - -function DashboardController($scope, $routeParams, dashboardResource, localizationService) { + +function DashboardController($scope, $q, $routeParams, $location, dashboardResource, localizationService) { + const DASHBOARD_QUERY_PARAM = 'dashboard'; $scope.page = {}; $scope.page.nameLocked = true; $scope.page.loading = true; $scope.dashboard = {}; - localizationService.localize("sections_" + $routeParams.section).then(function(name){ - $scope.dashboard.name = name; - }); - - dashboardResource.getDashboard($routeParams.section).then(function(tabs){ - $scope.dashboard.tabs = tabs; - - // set first tab to active - if($scope.dashboard.tabs && $scope.dashboard.tabs.length > 0) { - $scope.dashboard.tabs[0].active = true; - } + var promises = []; + + promises.push(localizationService.localize("sections_" + $routeParams.section).then(function (name) { + $scope.dashboard.name = name; + })); + + promises.push(dashboardResource.getDashboard($routeParams.section).then(function (tabs) { + $scope.dashboard.tabs = tabs; + + if ($scope.dashboard.tabs && $scope.dashboard.tabs.length > 0) { + initActiveTab(); + } + })); + + $q.all(promises).then(function () { $scope.page.loading = false; }); - $scope.changeTab = function(tab) { - $scope.dashboard.tabs.forEach(function(tab) { - tab.active = false; - }); + $scope.changeTab = function (tab) { + if ($scope.dashboard.tabs && $scope.dashboard.tabs.length > 0) { + $scope.dashboard.tabs.forEach(function (tab) { + tab.active = false; + }); + } + tab.active = true; + $location.search(DASHBOARD_QUERY_PARAM, tab.alias); }; + function initActiveTab() { + // Check the query parameter for a dashboard alias + const dashboardAlias = $location.search()[DASHBOARD_QUERY_PARAM]; + const dashboardIndex = $scope.dashboard.tabs.findIndex(tab => tab.alias === dashboardAlias); + + // Set the first dashboard to active if there is no query parameter or we can't find a matching dashboard for the alias + const activeIndex = dashboardIndex !== -1 ? dashboardIndex : 0; + + const tab = $scope.dashboard.tabs[activeIndex]; + + tab.active = true; + $location.search(DASHBOARD_QUERY_PARAM, tab.alias); + } } - -//register it +// Register it angular.module('umbraco').controller("Umbraco.DashboardController", DashboardController); From ed79bd65f2d9f4217df4dee35279d7d675e01b6a Mon Sep 17 00:00:00 2001 From: Mole Date: Mon, 21 Jun 2021 13:38:49 +0200 Subject: [PATCH 70/70] Fix certified to verified refactoring --- .../src/views/packages/views/repo.html | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/Umbraco.Web.UI.Client/src/views/packages/views/repo.html b/src/Umbraco.Web.UI.Client/src/views/packages/views/repo.html index 18fd7c55f5..d467c513ec 100644 --- a/src/Umbraco.Web.UI.Client/src/views/packages/views/repo.html +++ b/src/Umbraco.Web.UI.Client/src/views/packages/views/repo.html @@ -65,7 +65,7 @@
    - Certified to work on Umbraco Cloud + Verified to work on Umbraco Cloud
    @@ -116,7 +116,7 @@ - + @@ -282,7 +282,7 @@
    -
    Verified to work on Umbraco CLoud
    +
    Verified to work on Umbraco CLoud