From eb04d55d2b7b1cfd68d2a205033d3951454652cf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dani=C3=ABl=20Knippers?= Date: Mon, 16 Mar 2020 20:00:39 +0100 Subject: [PATCH 01/35] Makes sure supplied arguments cannot be used more than once. --- src/Umbraco.Core/FactoryExtensions.cs | 20 +++++++++++++++++--- 1 file changed, 17 insertions(+), 3 deletions(-) diff --git a/src/Umbraco.Core/FactoryExtensions.cs b/src/Umbraco.Core/FactoryExtensions.cs index 8514525417..8ae2f76af3 100644 --- a/src/Umbraco.Core/FactoryExtensions.cs +++ b/src/Umbraco.Core/FactoryExtensions.cs @@ -1,4 +1,5 @@ using System; +using System.Collections.Generic; using System.Linq; using System.Reflection; using Umbraco.Core.Composing; @@ -77,15 +78,28 @@ namespace Umbraco.Core var ctorParameters = ctor.GetParameters(); var ctorArgs = new object[ctorParameters.Length]; + var availableArgs = new List(args); var i = 0; foreach (var parameter in ctorParameters) { // no! IsInstanceOfType is not ok here // ReSharper disable once UseMethodIsInstanceOfType - var arg = args?.FirstOrDefault(a => parameter.ParameterType.IsAssignableFrom(a.GetType())); - ctorArgs[i++] = arg ?? factory.GetInstance(parameter.ParameterType); + var idx = availableArgs.FindIndex(a => parameter.ParameterType.IsAssignableFrom(a.GetType())); + if(idx >= 0) + { + // Found a suitable supplied argument + ctorArgs[i++] = availableArgs[idx]; + + // A supplied argument can be used at most once + availableArgs.RemoveAt(idx); + } + else + { + // None of the provided arguments is suitable: get an instance from the factory + ctorArgs[i++] = factory.GetInstance(parameter.ParameterType); + } } return ctor.Invoke(ctorArgs); } } -} \ No newline at end of file +} From c3f59602c21d6a07f553066af7e8dd742114fd83 Mon Sep 17 00:00:00 2001 From: Jeavon Leopold Date: Wed, 22 Apr 2020 11:33:27 +0100 Subject: [PATCH 02/35] Add GetMainDom method to UmbracoApplication so GetRuntime can be overridden (cherry picked from commit 549b4c58a7b8dec8eae15cb0cbb3bd1e1268ead8) --- src/Umbraco.Web/UmbracoApplication.cs | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/src/Umbraco.Web/UmbracoApplication.cs b/src/Umbraco.Web/UmbracoApplication.cs index f8ee238da7..b5ecacfd13 100644 --- a/src/Umbraco.Web/UmbracoApplication.cs +++ b/src/Umbraco.Web/UmbracoApplication.cs @@ -2,6 +2,7 @@ using System.Threading; using System.Web; using Umbraco.Core; +using Umbraco.Core.Logging; using Umbraco.Core.Logging.Serilog; using Umbraco.Core.Runtime; using Umbraco.Web.Runtime; @@ -17,16 +18,24 @@ namespace Umbraco.Web { var logger = SerilogLogger.CreateWithDefaultConfiguration(); + var runtime = new WebRuntime(this, logger, GetMainDom(logger)); + + return runtime; + } + + /// + /// Returns a new MainDom + /// + public static IMainDom GetMainDom(ILogger logger) + { // Determine if we should use the sql main dom or the default var appSettingMainDomLock = ConfigurationManager.AppSettings[Constants.AppSettings.MainDomLock]; var mainDomLock = appSettingMainDomLock == "SqlMainDomLock" ? (IMainDomLock)new SqlMainDomLock(logger) : new MainDomSemaphoreLock(logger); - - var runtime = new WebRuntime(this, logger, new MainDom(logger, mainDomLock)); - return runtime; + return new MainDom(logger, mainDomLock); } /// From bac42c6fb29352efee074e0194fd821870a57a65 Mon Sep 17 00:00:00 2001 From: Shannon Date: Thu, 30 Apr 2020 22:46:06 +1000 Subject: [PATCH 03/35] change to protected --- src/Umbraco.Web/UmbracoApplication.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Umbraco.Web/UmbracoApplication.cs b/src/Umbraco.Web/UmbracoApplication.cs index b5ecacfd13..f5667a5a85 100644 --- a/src/Umbraco.Web/UmbracoApplication.cs +++ b/src/Umbraco.Web/UmbracoApplication.cs @@ -26,7 +26,7 @@ namespace Umbraco.Web /// /// Returns a new MainDom /// - public static IMainDom GetMainDom(ILogger logger) + protected IMainDom GetMainDom(ILogger logger) { // Determine if we should use the sql main dom or the default var appSettingMainDomLock = ConfigurationManager.AppSettings[Constants.AppSettings.MainDomLock]; From 0717d5b2467c78e24a5c0cbee7570e6b11e7fe8b Mon Sep 17 00:00:00 2001 From: Shannon Date: Mon, 4 May 2020 18:57:55 +1000 Subject: [PATCH 04/35] Fixes: SqlMainDom setting for Azure does not work in Load Balancing #8038 --- src/Umbraco.Core/Runtime/SqlMainDomLock.cs | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/src/Umbraco.Core/Runtime/SqlMainDomLock.cs b/src/Umbraco.Core/Runtime/SqlMainDomLock.cs index f3bfe4eefc..0107ecb8da 100644 --- a/src/Umbraco.Core/Runtime/SqlMainDomLock.cs +++ b/src/Umbraco.Core/Runtime/SqlMainDomLock.cs @@ -5,6 +5,7 @@ using System.Diagnostics; using System.Linq; using System.Threading; using System.Threading.Tasks; +using System.Web; using Umbraco.Core.Logging; using Umbraco.Core.Persistence; using Umbraco.Core.Persistence.Dtos; @@ -16,7 +17,7 @@ namespace Umbraco.Core.Runtime internal class SqlMainDomLock : IMainDomLock { private string _lockId; - private const string MainDomKey = "Umbraco.Core.Runtime.SqlMainDom"; + private const string MainDomKeyPrefix = "Umbraco.Core.Runtime.SqlMainDom"; private const string UpdatedSuffix = "_updated"; private readonly ILogger _logger; private IUmbracoDatabase _db; @@ -126,6 +127,14 @@ namespace Umbraco.Core.Runtime } + /// + /// Returns the keyvalue table key for the current server/app + /// + private string MainDomKey { get; } = MainDomKeyPrefix + "-" + + (NetworkHelper.MachineName // eg DOMAIN\SERVER + + HttpRuntime.AppDomainAppId) // eg /LM/S3SVC/11/ROOT + .GenerateHash(); + private void ListeningLoop() { while (true) From 2dd938bf29134910f3769b5a26501b473d7185d2 Mon Sep 17 00:00:00 2001 From: Shannon Date: Mon, 4 May 2020 19:12:20 +1000 Subject: [PATCH 05/35] Change to re-use the MainDomId of the normal maindom --- src/Umbraco.Core/Runtime/SqlMainDomLock.cs | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/src/Umbraco.Core/Runtime/SqlMainDomLock.cs b/src/Umbraco.Core/Runtime/SqlMainDomLock.cs index 0107ecb8da..5f5d0d607f 100644 --- a/src/Umbraco.Core/Runtime/SqlMainDomLock.cs +++ b/src/Umbraco.Core/Runtime/SqlMainDomLock.cs @@ -3,6 +3,7 @@ using System.Data; using System.Data.SqlClient; using System.Diagnostics; using System.Linq; +using System.Security.Cryptography; using System.Threading; using System.Threading.Tasks; using System.Web; @@ -130,10 +131,12 @@ namespace Umbraco.Core.Runtime /// /// Returns the keyvalue table key for the current server/app /// - private string MainDomKey { get; } = MainDomKeyPrefix + "-" - + (NetworkHelper.MachineName // eg DOMAIN\SERVER - + HttpRuntime.AppDomainAppId) // eg /LM/S3SVC/11/ROOT - .GenerateHash(); + /// + /// The key is the the normal MainDomId which takes into account the AppDomainAppId and the physical file path of the app and this is + /// combined with the current machine name. The machine name is required because the default semaphore lock is machine wide so it implicitly + /// takes into account machine name whereas this needs to be explicitly per machine. + /// + private string MainDomKey { get; } = MainDomKeyPrefix + "-" + (NetworkHelper.MachineName + MainDom.GetMainDomId()).GenerateHash(); private void ListeningLoop() { From c6055cf0e3043020fbce00de809ea662f88d01f9 Mon Sep 17 00:00:00 2001 From: Kevin Jump Date: Mon, 11 May 2020 14:39:12 +0100 Subject: [PATCH 06/35] Add keys for custom audit events #8050 (#8051) --- src/Umbraco.Web.UI/Umbraco/config/lang/en.xml | 2 ++ src/Umbraco.Web.UI/Umbraco/config/lang/en_us.xml | 2 ++ 2 files changed, 4 insertions(+) diff --git a/src/Umbraco.Web.UI/Umbraco/config/lang/en.xml b/src/Umbraco.Web.UI/Umbraco/config/lang/en.xml index d7ccb13193..e764b5591e 100644 --- a/src/Umbraco.Web.UI/Umbraco/config/lang/en.xml +++ b/src/Umbraco.Web.UI/Umbraco/config/lang/en.xml @@ -168,6 +168,7 @@ Content sent for publishing Content sent for publishing for languages: %0% Sort child items performed by user + %0% Copy Publish Publish @@ -180,6 +181,7 @@ Send To Publish Send To Publish Sort + Custom History (all variants) 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 e4c764e112..e1b1df2c34 100644 --- a/src/Umbraco.Web.UI/Umbraco/config/lang/en_us.xml +++ b/src/Umbraco.Web.UI/Umbraco/config/lang/en_us.xml @@ -170,6 +170,7 @@ Content sent for publishing Content sent for publishing for languages: %0% Sort child items performed by user + %0% Copy Publish Publish @@ -183,6 +184,7 @@ Send To Publish Send To Publish Sort + Custom History (all variants) From 89143b5daef2b6996250c6c1a16c741417e2bb1e Mon Sep 17 00:00:00 2001 From: Alan Mac Kenna Date: Sat, 2 May 2020 14:47:59 +0100 Subject: [PATCH 07/35] upgraded tinymce to 4.9.10 --- 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 8ab5980107..c298f063a7 100644 --- a/src/Umbraco.Web.UI.Client/package.json +++ b/src/Umbraco.Web.UI.Client/package.json @@ -42,7 +42,7 @@ "npm": "6.13.6", "signalr": "2.4.0", "spectrum-colorpicker": "1.8.0", - "tinymce": "4.9.9", + "tinymce": "4.9.10", "typeahead.js": "0.11.1", "underscore": "1.9.1" }, From b2a9e17c90ab5c9d2bfa7c7b6d2e738a152073e0 Mon Sep 17 00:00:00 2001 From: Alan Thom Date: Fri, 8 May 2020 13:41:28 +0100 Subject: [PATCH 08/35] Adding ng-trim="false" attribute to textarea property editor --- .../src/views/propertyeditors/textarea/textarea.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Umbraco.Web.UI.Client/src/views/propertyeditors/textarea/textarea.html b/src/Umbraco.Web.UI.Client/src/views/propertyeditors/textarea/textarea.html index d255c4a5d6..87f6ffeac9 100644 --- a/src/Umbraco.Web.UI.Client/src/views/propertyeditors/textarea/textarea.html +++ b/src/Umbraco.Web.UI.Client/src/views/propertyeditors/textarea/textarea.html @@ -1,6 +1,6 @@
- + {{mandatoryMessage}} From 8059927ac340c346ecfac07b33ef24f06d9d972f Mon Sep 17 00:00:00 2001 From: Kenn Jacobsen Date: Thu, 14 May 2020 08:41:05 +0200 Subject: [PATCH 09/35] Remove "double tabbing" in the datatype picker (#8102) --- .../datatypepicker/datatypepicker.html | 15 ++++++--------- 1 file changed, 6 insertions(+), 9 deletions(-) diff --git a/src/Umbraco.Web.UI.Client/src/views/common/infiniteeditors/datatypepicker/datatypepicker.html b/src/Umbraco.Web.UI.Client/src/views/common/infiniteeditors/datatypepicker/datatypepicker.html index b31a396c2d..768f8a8c24 100644 --- a/src/Umbraco.Web.UI.Client/src/views/common/infiniteeditors/datatypepicker/datatypepicker.html +++ b/src/Umbraco.Web.UI.Client/src/views/common/infiniteeditors/datatypepicker/datatypepicker.html @@ -37,9 +37,8 @@
{{key | umbCmsTitleCase}}
public string Culture { get; set; } + /// + /// When dealing with content variants, this is the segment for the variant + /// + public string Segment { get; set; } + /// /// An array of metadata that is parsed out from the file info posted to the server which is set on the client. /// diff --git a/src/Umbraco.Web.UI.Client/src/common/directives/components/upload/umbpropertyfileupload.directive.js b/src/Umbraco.Web.UI.Client/src/common/directives/components/upload/umbpropertyfileupload.directive.js index 96a072330b..653b4f427c 100644 --- a/src/Umbraco.Web.UI.Client/src/common/directives/components/upload/umbpropertyfileupload.directive.js +++ b/src/Umbraco.Web.UI.Client/src/common/directives/components/upload/umbpropertyfileupload.directive.js @@ -26,6 +26,7 @@ fileManager.setFiles({ propertyAlias: vm.propertyAlias, culture: vm.culture, + segment: vm.segment, files: [] }); //clear the current files @@ -92,6 +93,11 @@ vm.culture = null; } + //normalize segment to null if it's not there + if (!vm.segment) { + vm.segment = null; + } + // TODO: need to figure out what we can do for things like Nested Content var existingClientFiles = checkPendingClientFiles(); @@ -134,11 +140,16 @@ vm.culture = null; } + //normalize segment to null if it's not there + if (!vm.segment) { + vm.segment = null; + } + //check the file manager to see if there's already local files pending for this editor var existingClientFiles = _.map( _.filter(fileManager.getFiles(), function (f) { - return f.alias === vm.propertyAlias && f.culture === vm.culture; + return f.alias === vm.propertyAlias && f.culture === vm.culture && f.segment === vm.segment; }), function (f) { return f.file; @@ -264,7 +275,8 @@ fileManager.setFiles({ propertyAlias: vm.propertyAlias, files: args.files, - culture: vm.culture + culture: vm.culture, + segment: vm.segment }); updateModelFromSelectedFiles(args.files).then(function(newVal) { @@ -287,6 +299,7 @@ templateUrl: 'views/components/upload/umb-property-file-upload.html', bindings: { culture: "@?", + segment: "@?", propertyAlias: "@", value: "<", hideSelection: "<", diff --git a/src/Umbraco.Web.UI.Client/src/common/services/filemanager.service.js b/src/Umbraco.Web.UI.Client/src/common/services/filemanager.service.js index 9e0285d58d..38aee3fc4a 100644 --- a/src/Umbraco.Web.UI.Client/src/common/services/filemanager.service.js +++ b/src/Umbraco.Web.UI.Client/src/common/services/filemanager.service.js @@ -39,18 +39,22 @@ function fileManager($rootScope) { args.culture = null; } + if (!args.segment) { + args.segment = null; + } + var metaData = []; if (Utilities.isArray(args.metaData)) { metaData = args.metaData; } - //this will clear the files for the current property/culture and then add the new ones for the current property + //this will clear the files for the current property/culture/segment and then add the new ones for the current property fileCollection = _.reject(fileCollection, function (item) { - return item.alias === args.propertyAlias && (!args.culture || args.culture === item.culture); + return item.alias === args.propertyAlias && (!args.culture || args.culture === item.culture) && (!args.segment || args.segment === item.segment); }); for (var i = 0; i < args.files.length; i++) { //save the file object to the files collection - fileCollection.push({ alias: args.propertyAlias, file: args.files[i], culture: args.culture, metaData: metaData }); + fileCollection.push({ alias: args.propertyAlias, file: args.files[i], culture: args.culture, segment: args.segment, metaData: metaData }); } }, diff --git a/src/Umbraco.Web.UI.Client/src/common/services/umbrequesthelper.service.js b/src/Umbraco.Web.UI.Client/src/common/services/umbrequesthelper.service.js index edf698c8a7..4cbc5e567a 100644 --- a/src/Umbraco.Web.UI.Client/src/common/services/umbrequesthelper.service.js +++ b/src/Umbraco.Web.UI.Client/src/common/services/umbrequesthelper.service.js @@ -252,12 +252,13 @@ function umbRequestHelper($http, $q, notificationsService, eventsService, formHe for (var f in args.files) { //each item has a property alias and the file object, we'll ensure that the alias is suffixed to the key // so we know which property it belongs to on the server side - var fileKey = "file_" + args.files[f].alias + "_" + (args.files[f].culture ? args.files[f].culture : ""); + var file = args.files[f]; + var fileKey = "file_" + file.alias + "_" + (file.culture ? file.culture : "") + "_" + (file.segment ? file.segment : ""); - if (Utilities.isArray(args.files[f].metaData) && args.files[f].metaData.length > 0) { - fileKey += ("_" + args.files[f].metaData.join("_")); + if (Utilities.isArray(file.metaData) && file.metaData.length > 0) { + fileKey += ("_" + file.metaData.join("_")); } - formData.append(fileKey, args.files[f].file); + formData.append(fileKey, file.file); } }).then(function (response) { //success callback diff --git a/src/Umbraco.Web.UI.Client/src/views/propertyeditors/fileupload/fileupload.controller.js b/src/Umbraco.Web.UI.Client/src/views/propertyeditors/fileupload/fileupload.controller.js index 17959b9950..c485f4bbc6 100644 --- a/src/Umbraco.Web.UI.Client/src/views/propertyeditors/fileupload/fileupload.controller.js +++ b/src/Umbraco.Web.UI.Client/src/views/propertyeditors/fileupload/fileupload.controller.js @@ -34,6 +34,7 @@ fileManager.setFiles({ propertyAlias: $scope.model.alias, culture: $scope.model.culture, + segment: $scope.model.segment, files: [] }); } diff --git a/src/Umbraco.Web.UI.Client/src/views/propertyeditors/fileupload/fileupload.html b/src/Umbraco.Web.UI.Client/src/views/propertyeditors/fileupload/fileupload.html index 2bc609714a..522278e99e 100644 --- a/src/Umbraco.Web.UI.Client/src/views/propertyeditors/fileupload/fileupload.html +++ b/src/Umbraco.Web.UI.Client/src/views/propertyeditors/fileupload/fileupload.html @@ -1,5 +1,6 @@ 
3) + { + segment = parts[3]; + //normalize to null if empty + if (segment.IsNullOrWhiteSpace()) + { + segment = null; + } + } + + // TODO: anything after 4 parts we can put in metadata var fileName = file.Headers.ContentDisposition.FileName.Trim('\"'); @@ -59,6 +71,7 @@ namespace Umbraco.Web.Editors.Binders TempFilePath = file.LocalFileName, PropertyAlias = propAlias, Culture = culture, + Segment = segment, FileName = fileName }); } diff --git a/src/Umbraco.Web/Editors/ContentControllerBase.cs b/src/Umbraco.Web/Editors/ContentControllerBase.cs index 300c777b3a..893c9f5941 100644 --- a/src/Umbraco.Web/Editors/ContentControllerBase.cs +++ b/src/Umbraco.Web/Editors/ContentControllerBase.cs @@ -76,7 +76,7 @@ namespace Umbraco.Web.Editors // prepare files, if any matching property and culture var files = contentItem.UploadedFiles - .Where(x => x.PropertyAlias == propertyDto.Alias && x.Culture == propertyDto.Culture) + .Where(x => x.PropertyAlias == propertyDto.Alias && x.Culture == propertyDto.Culture && x.Segment == propertyDto.Segment) .ToArray(); foreach (var file in files) From c36495ac9c5f00c02943b9df18f36ce5b58d1571 Mon Sep 17 00:00:00 2001 From: Sebastiaan Janssen Date: Wed, 20 May 2020 10:30:07 +0200 Subject: [PATCH 13/35] Use a language that's more common to people's machines --- .../cypress/integration/Settings/languages.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Umbraco.Tests.AcceptanceTest/cypress/integration/Settings/languages.ts b/src/Umbraco.Tests.AcceptanceTest/cypress/integration/Settings/languages.ts index 17b7bb6805..49bcf94943 100644 --- a/src/Umbraco.Tests.AcceptanceTest/cypress/integration/Settings/languages.ts +++ b/src/Umbraco.Tests.AcceptanceTest/cypress/integration/Settings/languages.ts @@ -6,7 +6,7 @@ context('Languages', () => { }); it('Add language', () => { - const name = "Neddersass’sch (Nedderlannen)"; // Must be an option in the select box + const name = "Kyrgyz (Kyrgyzstan)"; // Must be an option in the select box cy.umbracoEnsureLanguageNameNotExists(name); From 5b7f1227f9b4f97ede6e2799a1aa36bb9c4fd823 Mon Sep 17 00:00:00 2001 From: Bjarke Berg Date: Fri, 22 May 2020 10:46:13 +0200 Subject: [PATCH 14/35] Bugfix for issue with hanging saves. + Fix for double post of save templates --- .../cypress/integration/Settings/templates.ts | 28 +++++++++---------- src/Umbraco.Tests.AcceptanceTest/package.json | 2 +- .../NuCache/PublishedSnapshotService.cs | 23 ++++++--------- 3 files changed, 23 insertions(+), 30 deletions(-) diff --git a/src/Umbraco.Tests.AcceptanceTest/cypress/integration/Settings/templates.ts b/src/Umbraco.Tests.AcceptanceTest/cypress/integration/Settings/templates.ts index bbabbcb4bf..c135258ec5 100644 --- a/src/Umbraco.Tests.AcceptanceTest/cypress/integration/Settings/templates.ts +++ b/src/Umbraco.Tests.AcceptanceTest/cypress/integration/Settings/templates.ts @@ -6,28 +6,28 @@ context('Templates', () => { }); it('Create template', () => { - const name = "Test template"; + const name = "Test template"; - cy.umbracoEnsureTemplateNameNotExists(name); + cy.umbracoEnsureTemplateNameNotExists(name); - cy.umbracoSection('settings'); - cy.get('li .umb-tree-root:contains("Settings")').should("be.visible"); + cy.umbracoSection('settings'); + cy.get('li .umb-tree-root:contains("Settings")').should("be.visible"); - cy.umbracoTreeItem("settings", ["Templates"]).rightclick(); + cy.umbracoTreeItem("settings", ["Templates"]).rightclick(); - cy.umbracoContextMenuAction("action-create").click(); + cy.umbracoContextMenuAction("action-create").click(); - //Type name - cy.umbracoEditorHeaderName(name); + //Type name + cy.umbracoEditorHeaderName(name); - //Save - cy.get('.btn-success').click(); + //Save + cy.get("form[name='contentForm']").submit(); - //Assert - cy.umbracoSuccessNotification().should('be.visible'); + //Assert + cy.umbracoSuccessNotification().should('be.visible'); - //Clean up - cy.umbracoEnsureTemplateNameNotExists(name); + //Clean up + cy.umbracoEnsureTemplateNameNotExists(name); }); }); diff --git a/src/Umbraco.Tests.AcceptanceTest/package.json b/src/Umbraco.Tests.AcceptanceTest/package.json index daa1c424bb..997de4db77 100644 --- a/src/Umbraco.Tests.AcceptanceTest/package.json +++ b/src/Umbraco.Tests.AcceptanceTest/package.json @@ -6,7 +6,7 @@ "devDependencies": { "cross-env": "^7.0.2", "ncp": "^2.0.0", - "cypress": "^4.5.0", + "cypress": "^4.6.0", "umbraco-cypress-testhelpers": "1.0.0-beta-38" }, "dependencies": { diff --git a/src/Umbraco.Web/PublishedCache/NuCache/PublishedSnapshotService.cs b/src/Umbraco.Web/PublishedCache/NuCache/PublishedSnapshotService.cs index 7e78b2e96f..a39e26e2b1 100755 --- a/src/Umbraco.Web/PublishedCache/NuCache/PublishedSnapshotService.cs +++ b/src/Umbraco.Web/PublishedCache/NuCache/PublishedSnapshotService.cs @@ -882,22 +882,15 @@ namespace Umbraco.Web.PublishedCache.NuCache // they require. // These can be run side by side in parallel. + using (_contentStore.GetScopedWriteLock(_scopeProvider)) + { + NotifyLocked(new[] { new ContentCacheRefresher.JsonPayload(0, null, TreeChangeTypes.RefreshAll) }, out _, out _); + } - Parallel.Invoke( - () => - { - using (_contentStore.GetScopedWriteLock(_scopeProvider)) - { - NotifyLocked(new[] { new ContentCacheRefresher.JsonPayload(0, null, TreeChangeTypes.RefreshAll) }, out _, out _); - } - }, - () => - { - using (_mediaStore.GetScopedWriteLock(_scopeProvider)) - { - NotifyLocked(new[] { new MediaCacheRefresher.JsonPayload(0, null, TreeChangeTypes.RefreshAll) }, out _); - } - }); + using (_mediaStore.GetScopedWriteLock(_scopeProvider)) + { + NotifyLocked(new[] { new MediaCacheRefresher.JsonPayload(0, null, TreeChangeTypes.RefreshAll) }, out _); + } } ((PublishedSnapshot)CurrentPublishedSnapshot)?.Resync(); From 5be8282ce45c3a11ff2d23eb2667e5bfc9d4ec7d Mon Sep 17 00:00:00 2001 From: Bjarke Berg Date: Fri, 22 May 2020 12:00:56 +0200 Subject: [PATCH 15/35] Delete templates test --- src/Umbraco.Tests.AcceptanceTest/cypress.json | 3 ++- .../cypress/integration/Settings/templates.ts | 24 +++++++++++++++++++ 2 files changed, 26 insertions(+), 1 deletion(-) diff --git a/src/Umbraco.Tests.AcceptanceTest/cypress.json b/src/Umbraco.Tests.AcceptanceTest/cypress.json index 051bf4a871..33978211ed 100644 --- a/src/Umbraco.Tests.AcceptanceTest/cypress.json +++ b/src/Umbraco.Tests.AcceptanceTest/cypress.json @@ -6,5 +6,6 @@ "username": "", "password": "" }, - "supportFile": "cypress/support/index.ts" + "supportFile": "cypress/support/index.ts", + "videoUploadOnPasses" : false } diff --git a/src/Umbraco.Tests.AcceptanceTest/cypress/integration/Settings/templates.ts b/src/Umbraco.Tests.AcceptanceTest/cypress/integration/Settings/templates.ts index c135258ec5..6871db7ffe 100644 --- a/src/Umbraco.Tests.AcceptanceTest/cypress/integration/Settings/templates.ts +++ b/src/Umbraco.Tests.AcceptanceTest/cypress/integration/Settings/templates.ts @@ -1,4 +1,6 @@ /// +import {DocumentTypeBuilder, TemplateBuilder} from "umbraco-cypress-testhelpers"; + context('Templates', () => { beforeEach(() => { @@ -30,4 +32,26 @@ context('Templates', () => { cy.umbracoEnsureTemplateNameNotExists(name); }); + it('Delete template', () => { + const name = "Test template"; + cy.umbracoEnsureTemplateNameNotExists(name); + + const template = new TemplateBuilder() + .withName(name) + .build(); + + cy.saveTemplate(template); + + cy.umbracoSection('settings'); + cy.get('li .umb-tree-root:contains("Settings")').should("be.visible"); + + cy.umbracoTreeItem("settings", ["Templates", name]).rightclick(); + cy.umbracoContextMenuAction("action-delete").click(); + + cy.umbracoButtonByLabelKey("general_ok").click(); + + cy.contains(name).should('not.exist'); + + cy.umbracoEnsureTemplateNameNotExists(name); + }); }); From 1a04b9711b565d173f336bdb4dc96745c87b3e3f Mon Sep 17 00:00:00 2001 From: Bjarke Berg Date: Fri, 22 May 2020 12:56:17 +0200 Subject: [PATCH 16/35] Updated testhelpers reference --- src/Umbraco.Tests.AcceptanceTest/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Umbraco.Tests.AcceptanceTest/package.json b/src/Umbraco.Tests.AcceptanceTest/package.json index 997de4db77..ad125d090a 100644 --- a/src/Umbraco.Tests.AcceptanceTest/package.json +++ b/src/Umbraco.Tests.AcceptanceTest/package.json @@ -7,7 +7,7 @@ "cross-env": "^7.0.2", "ncp": "^2.0.0", "cypress": "^4.6.0", - "umbraco-cypress-testhelpers": "1.0.0-beta-38" + "umbraco-cypress-testhelpers": "1.0.0-beta-39" }, "dependencies": { "typescript": "^3.9.2" From 4c16421cbb60f1f0b4f2e9be4fad602f436866bd Mon Sep 17 00:00:00 2001 From: Lee Kelleher Date: Sat, 23 May 2020 16:15:42 +0100 Subject: [PATCH 17/35] Update umb-button.html (#8145) Noticed the missing closing bracket on the `
From b6262bf33413493f952d088c4e61150b641998ec Mon Sep 17 00:00:00 2001 From: Marc Goodson Date: Mon, 25 May 2020 16:51:52 +0100 Subject: [PATCH 18/35] Remove ContentFinderByRedirectUrl if RedirectUrlTracking is disabled (#7761) --- src/Umbraco.Web/Runtime/WebInitialComposer.cs | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/src/Umbraco.Web/Runtime/WebInitialComposer.cs b/src/Umbraco.Web/Runtime/WebInitialComposer.cs index 203bae4854..c631aac5e3 100644 --- a/src/Umbraco.Web/Runtime/WebInitialComposer.cs +++ b/src/Umbraco.Web/Runtime/WebInitialComposer.cs @@ -179,7 +179,7 @@ namespace Umbraco.Web.Runtime .Remove() .Remove() .Remove(); - + // add all known factories, devs can then modify this list on application // startup either by binding to events or in their own global.asax composition.FilteredControllerFactory() @@ -203,8 +203,12 @@ namespace Umbraco.Web.Runtime .Append() .Append() //.Append() // disabled, this is an odd finder - .Append() - .Append(); + .Append(); + //only append ContentFinderByRedirectUrl if RedirectUrlTracking is not disabled + if (composition.Configs.Settings().WebRouting.DisableRedirectUrlTracking == false) + { + composition.ContentFinders().Append(); + } composition.RegisterUnique(); From 5215a769feb593d4675d832e112618a581912cf8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dani=C3=ABl=20Knippers?= Date: Mon, 25 May 2020 21:30:56 +0200 Subject: [PATCH 19/35] Added unit test that fails before PR and succeeds after PR --- .../Composing/ContainerConformingTests.cs | 23 +++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/src/Umbraco.Tests/Composing/ContainerConformingTests.cs b/src/Umbraco.Tests/Composing/ContainerConformingTests.cs index f5c1ff9bc7..06ab246d84 100644 --- a/src/Umbraco.Tests/Composing/ContainerConformingTests.cs +++ b/src/Umbraco.Tests/Composing/ContainerConformingTests.cs @@ -330,6 +330,17 @@ namespace Umbraco.Tests.Composing var s1 = factory.GetInstance(); var s2 = factory.GetInstance(); Assert.AreSame(s1, s2); + + register.Register(factory => + { + var param1 = new Thing1(); + var param2 = new Thing1(); + + return factory.CreateInstance(param1, param2); + }); + + var instance = factory.GetInstance(); + Assert.AreNotEqual(instance.Thing, instance.AnotherThing); } public interface IThing { } @@ -352,5 +363,17 @@ namespace Umbraco.Tests.Composing public IEnumerable Things { get; } } + + public class Thing4 : ThingBase + { + public readonly Thing1 Thing; + public readonly Thing1 AnotherThing; + + public Thing4(Thing1 thing, Thing1 anotherThing) + { + Thing = thing; + AnotherThing = anotherThing; + } + } } } From 558ffaeba70e922240a124a47faa1718a8f3e0be Mon Sep 17 00:00:00 2001 From: Sebastiaan Janssen Date: Tue, 26 May 2020 09:18:09 +0200 Subject: [PATCH 20/35] Move test and use params that are easier to distinguish --- .../Composing/ContainerConformingTests.cs | 19 ++++++++++++------- 1 file changed, 12 insertions(+), 7 deletions(-) diff --git a/src/Umbraco.Tests/Composing/ContainerConformingTests.cs b/src/Umbraco.Tests/Composing/ContainerConformingTests.cs index 06ab246d84..22978bdb43 100644 --- a/src/Umbraco.Tests/Composing/ContainerConformingTests.cs +++ b/src/Umbraco.Tests/Composing/ContainerConformingTests.cs @@ -330,15 +330,20 @@ namespace Umbraco.Tests.Composing var s1 = factory.GetInstance(); var s2 = factory.GetInstance(); Assert.AreSame(s1, s2); + } - register.Register(factory => + [Test] + public void CanRegisterMultipleSameTypeParametersWithCreateInstance() + { + var register = GetRegister(); + var factory = register.CreateFactory(); + register.Register(factory => { - var param1 = new Thing1(); - var param2 = new Thing1(); + var param1 = "param1"; + var param2 = "param2"; return factory.CreateInstance(param1, param2); }); - var instance = factory.GetInstance(); Assert.AreNotEqual(instance.Thing, instance.AnotherThing); } @@ -366,10 +371,10 @@ namespace Umbraco.Tests.Composing public class Thing4 : ThingBase { - public readonly Thing1 Thing; - public readonly Thing1 AnotherThing; + public readonly string Thing; + public readonly string AnotherThing; - public Thing4(Thing1 thing, Thing1 anotherThing) + public Thing4(string thing, string anotherThing) { Thing = thing; AnotherThing = anotherThing; From 41ac96d69da6af39407cceaa022435645f543ec3 Mon Sep 17 00:00:00 2001 From: Marc Goodson Date: Tue, 26 May 2020 08:45:57 +0100 Subject: [PATCH 21/35] Fix HasValue and IsValue for Dropdown Property Types with no Values (#8154) --- .../dropdownFlexible/dropdownFlexible.controller.js | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/src/Umbraco.Web.UI.Client/src/views/propertyeditors/dropdownFlexible/dropdownFlexible.controller.js b/src/Umbraco.Web.UI.Client/src/views/propertyeditors/dropdownFlexible/dropdownFlexible.controller.js index a8979c949b..afbb4feb20 100644 --- a/src/Umbraco.Web.UI.Client/src/views/propertyeditors/dropdownFlexible/dropdownFlexible.controller.js +++ b/src/Umbraco.Web.UI.Client/src/views/propertyeditors/dropdownFlexible/dropdownFlexible.controller.js @@ -15,7 +15,14 @@ angular.module("umbraco").controller("Umbraco.PropertyEditors.DropdownFlexibleCo //ensure this is a bool, old data could store zeros/ones or string versions $scope.model.config.multiple = Object.toBoolean($scope.model.config.multiple); - + + //ensure when form is saved that we don't store [] or [null] as string values in the database when no items are selected + $scope.$on("formSubmitting", function () { + if ($scope.model.value.length === 0 || $scope.model.value[0] === null) { + $scope.model.value = null; + } + }); + function convertArrayToDictionaryArray(model){ //now we need to format the items in the dictionary because we always want to have an array var newItems = []; From f33b4b7be534e6e3504da53fce20450e6201477e Mon Sep 17 00:00:00 2001 From: Sebastiaan Janssen Date: Tue, 26 May 2020 11:49:35 +0200 Subject: [PATCH 22/35] Some cleanup and fixing the build --- .../Composing/ContainerConformingTests.cs | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/src/Umbraco.Tests/Composing/ContainerConformingTests.cs b/src/Umbraco.Tests/Composing/ContainerConformingTests.cs index 22978bdb43..d7a19cb553 100644 --- a/src/Umbraco.Tests/Composing/ContainerConformingTests.cs +++ b/src/Umbraco.Tests/Composing/ContainerConformingTests.cs @@ -336,14 +336,16 @@ namespace Umbraco.Tests.Composing public void CanRegisterMultipleSameTypeParametersWithCreateInstance() { var register = GetRegister(); - var factory = register.CreateFactory(); - register.Register(factory => - { - var param1 = "param1"; - var param2 = "param2"; - return factory.CreateInstance(param1, param2); + register.Register(c => + { + const string param1 = "param1"; + const string param2 = "param2"; + + return c.CreateInstance(param1, param2); }); + + var factory = register.CreateFactory(); var instance = factory.GetInstance(); Assert.AreNotEqual(instance.Thing, instance.AnotherThing); } From c3c98e2621d31dc095f012012ff2103db230f5b8 Mon Sep 17 00:00:00 2001 From: Rachel Breeze Date: Tue, 26 May 2020 13:04:06 +0100 Subject: [PATCH 23/35] v8: Fix for login screen title display (#7412) --- src/Umbraco.Web.UI.Client/package-lock.json | 6 +++--- .../directives/components/application/umblogin.directive.js | 2 ++ src/Umbraco.Web.UI.Client/src/main.controller.js | 6 ++++-- 3 files changed, 9 insertions(+), 5 deletions(-) diff --git a/src/Umbraco.Web.UI.Client/package-lock.json b/src/Umbraco.Web.UI.Client/package-lock.json index b8087066c9..12e7b115e7 100644 --- a/src/Umbraco.Web.UI.Client/package-lock.json +++ b/src/Umbraco.Web.UI.Client/package-lock.json @@ -15313,9 +15313,9 @@ "integrity": "sha512-NB6Dk1A9xgQPMoGqC5CVXn123gWyte215ONT5Pp5a0yt4nlEoO1ZWeCwpncaekPHXO60i47ihFnZPiRPjRMq4Q==" }, "tinymce": { - "version": "4.9.9", - "resolved": "https://registry.npmjs.org/tinymce/-/tinymce-4.9.9.tgz", - "integrity": "sha512-7Wqh4PGSAWm6FyNwyI1uFAaZyzeQeiwd9Gg2R89SpFIqoMrSzNHIYBqnZnlDm4Bd2DJ0wcC6uJhwFrabIE8puw==" + "version": "4.9.10", + "resolved": "https://registry.npmjs.org/tinymce/-/tinymce-4.9.10.tgz", + "integrity": "sha512-vyzGG04Q44Y7zWIKA4c+G7MxMCsed6JkrhU+k0TaDs9XKAiS+e+D3Fzz5OIJ7p5keF7lbRK5czgI8T1JtouZqw==" }, "tmp": { "version": "0.0.33", diff --git a/src/Umbraco.Web.UI.Client/src/common/directives/components/application/umblogin.directive.js b/src/Umbraco.Web.UI.Client/src/common/directives/components/application/umblogin.directive.js index 541cc647fb..ec8da898ad 100644 --- a/src/Umbraco.Web.UI.Client/src/common/directives/components/application/umblogin.directive.js +++ b/src/Umbraco.Web.UI.Client/src/common/directives/components/application/umblogin.directive.js @@ -209,6 +209,7 @@ } if (vm.loginForm.$invalid) { + SetTitle(); return; } @@ -257,6 +258,7 @@ vm.loginForm.password.$setValidity('auth', true); } }); + SetTitle(); } function requestPasswordResetSubmit(email) { diff --git a/src/Umbraco.Web.UI.Client/src/main.controller.js b/src/Umbraco.Web.UI.Client/src/main.controller.js index 81eadf150f..297d93f4bc 100644 --- a/src/Umbraco.Web.UI.Client/src/main.controller.js +++ b/src/Umbraco.Web.UI.Client/src/main.controller.js @@ -56,12 +56,14 @@ function MainController($scope, $location, appState, treeService, notificationsS appState.setSearchState("show", false); }; - $scope.showLoginScreen = function(isTimedOut) { + $scope.showLoginScreen = function (isTimedOut) { + $scope.login.pageTitle = $scope.$root.locationTitle; $scope.login.isTimedOut = isTimedOut; $scope.login.show = true; }; - $scope.hideLoginScreen = function() { + $scope.hideLoginScreen = function () { + $scope.$root.locationTitle = $scope.login.pageTitle; $scope.login.show = false; }; From 5541d130207b8a32dfb361bc4d7143c85143c645 Mon Sep 17 00:00:00 2001 From: Rachel Breeze Date: Tue, 26 May 2020 13:59:33 +0100 Subject: [PATCH 24/35] V8: Accessibility Changes For umbEditorHeader Directive (edit user) (#7102) --- .../editor/umbeditorheader.directive.js | 140 ++++++++++-------- .../src/views/users/user.controller.js | 1 + 2 files changed, 78 insertions(+), 63 deletions(-) diff --git a/src/Umbraco.Web.UI.Client/src/common/directives/components/editor/umbeditorheader.directive.js b/src/Umbraco.Web.UI.Client/src/common/directives/components/editor/umbeditorheader.directive.js index 87053c083c..58f799e5af 100644 --- a/src/Umbraco.Web.UI.Client/src/common/directives/components/editor/umbeditorheader.directive.js +++ b/src/Umbraco.Web.UI.Client/src/common/directives/components/editor/umbeditorheader.directive.js @@ -206,7 +206,7 @@ Use this directive to construct a header inside the main editor window. (function () { 'use strict'; - function EditorHeaderDirective(editorService, localizationService, editorState) { + function EditorHeaderDirective(editorService, localizationService, editorState, $rootScope) { function link(scope, $injector) { @@ -224,27 +224,9 @@ Use this directive to construct a header inside the main editor window. if (editorState.current) { //to do make work for user create/edit // to do make it work for user group create/ edit - // to do make it work for language edit/create - // to do make it work for log viewer - scope.isNew = editorState.current.id === 0 || - editorState.current.id === "0" || - editorState.current.id === -1 || - editorState.current.id === 0 || - editorState.current.id === "-1"; - - var localizeVars = [ - scope.isNew ? "visuallyHiddenTexts_createItem" : "visuallyHiddenTexts_edit", - "visuallyHiddenTexts_name", - scope.isNew ? "general_new" : "general_edit" - ]; - - if (scope.editorfor) { - localizeVars.push(scope.editorfor); - } - localizationService.localizeMany(localizeVars).then(function(data) { - setAccessibilityForEditor(data); - scope.loading = false; - }); + // to make it work for language edit/create + setAccessibilityForEditorState(); + scope.loading = false; } else { scope.loading = false; } @@ -283,59 +265,91 @@ Use this directive to construct a header inside the main editor window. editorService.iconPicker(iconPicker); }; - function setAccessibilityForEditor(data) { - - if (editorState.current) { - if (scope.nameLocked) { - scope.accessibility.a11yName = scope.name; - SetPageTitle(scope.name); - } else { - - scope.accessibility.a11yMessage = data[0]; - scope.accessibility.a11yName = data[1]; - var title = data[2] + ":"; - if (!scope.isNew) { - scope.accessibility.a11yMessage += " " + scope.name; - title += " " + scope.name; - } else { - var name = ""; - if (editorState.current.contentTypeName) { - name = editorState.current.contentTypeName; - } else if (scope.editorfor) { - name = data[3]; - } - if (name !== "") { - scope.accessibility.a11yMessage += " " + name; - scope.accessibility.a11yName = name + " " + scope.accessibility.a11yName; - title += " " + name; - } - } - if (title !== data[2] + ":") { - SetPageTitle(title); - } - - } - scope.accessibility.a11yMessageVisible = !isEmptyOrSpaces(scope.accessibility.a11yMessage); - scope.accessibility.a11yNameVisible = !isEmptyOrSpaces(scope.accessibility.a11yName); + function setAccessibilityForEditorState() { + var isNew = editorState.current.id === 0 || + editorState.current.id === "0" || + editorState.current.id === -1 || + editorState.current.id === 0 || + editorState.current.id === "-1"; + + var contentTypeName = ""; + if (editorState.current.contentTypeName) { + contentTypeName = editorState.current.contentTypeName; } - + + var setTitle = false; + if (scope.setpagetitle !== undefined) { + setTitle = scope.setpagetitle; + } + setAccessibilityHeaderDirective(isNew, scope.editorfor, scope.nameLocked, scope.name, contentTypeName, setTitle); } + function setAccessibilityHeaderDirective(isNew, editorFor, nameLocked, entityName, contentTypeName, setTitle) { + + var localizeVars = [ + isNew ? "visuallyHiddenTexts_createItem" : "visuallyHiddenTexts_edit", + "visuallyHiddenTexts_name", + isNew ? "general_new" : "general_edit" + ]; + + if (editorFor) { + localizeVars.push(editorFor); + } + localizationService.localizeMany(localizeVars).then(function(data) { + if (nameLocked) { + scope.accessibility.a11yName = entityName; + if (setTitle) { + SetPageTitle(entityName); + } + } else { + + scope.accessibility.a11yMessage = data[0]; + scope.accessibility.a11yName = data[1]; + var title = data[2] + ":"; + if (!isNew) { + scope.accessibility.a11yMessage += " " + entityName; + title += " " + entityName; + } else { + var name = ""; + if (contentTypeName) { + name = editorState.current.contentTypeName; + } else if (editorFor) { + name = data[3]; + } + if (name !== "") { + scope.accessibility.a11yMessage += " " + name; + scope.accessibility.a11yName = name + " " + scope.accessibility.a11yName; + title += " " + name; + } + } + if (setTitle && title !== data[2] + ":") { + SetPageTitle(title); + } + + } + scope.accessibility.a11yMessageVisible = !isEmptyOrSpaces(scope.accessibility.a11yMessage); + scope.accessibility.a11yNameVisible = !isEmptyOrSpaces(scope.accessibility.a11yName); + + }); + } + + + function isEmptyOrSpaces(str) { return str === null || str===undefined || str.trim ===''; } function SetPageTitle(title) { - var setTitle = false; - if (scope.setpagetitle !== undefined) { - setTitle = scope.setpagetitle; - } - if (setTitle) { scope.$emit("$changeTitle", title); - } } + + $rootScope.$on('$setAccessibleHeader', function (event, isNew, editorFor, nameLocked, name, contentTypeName, setTitle) { + setAccessibilityHeaderDirective(isNew, editorFor, nameLocked, name, contentTypeName, setTitle); + }); } + + var directive = { transclude: true, restrict: 'E', diff --git a/src/Umbraco.Web.UI.Client/src/views/users/user.controller.js b/src/Umbraco.Web.UI.Client/src/views/users/user.controller.js index ecea3b1dba..19218d3d08 100644 --- a/src/Umbraco.Web.UI.Client/src/views/users/user.controller.js +++ b/src/Umbraco.Web.UI.Client/src/views/users/user.controller.js @@ -103,6 +103,7 @@ vm.changePasswordModel.config.allowManuallyChangingPassword = true; } + $scope.$emit("$setAccessibleHeader", false, "general_user", false, vm.user.name, "", true); vm.loading = false; }); }); From b80dfbf5fce0f03f299c105f2ea167a5c55aa7b0 Mon Sep 17 00:00:00 2001 From: Rachel Breeze Date: Tue, 26 May 2020 14:01:50 +0100 Subject: [PATCH 25/35] Fix for tiny MCE when language is en-US (#8002) --- .../lib/tinymce/langs/en_US.js | 261 ++++++++++++++++++ 1 file changed, 261 insertions(+) create mode 100644 src/Umbraco.Web.UI.Client/lib/tinymce/langs/en_US.js diff --git a/src/Umbraco.Web.UI.Client/lib/tinymce/langs/en_US.js b/src/Umbraco.Web.UI.Client/lib/tinymce/langs/en_US.js new file mode 100644 index 0000000000..90eae85800 --- /dev/null +++ b/src/Umbraco.Web.UI.Client/lib/tinymce/langs/en_US.js @@ -0,0 +1,261 @@ +tinymce.addI18n('en_US',{ +"Redo": "Redo", +"Undo": "Undo", +"Cut": "Cut", +"Copy": "Copy", +"Paste": "Paste", +"Select all": "Select all", +"New document": "New document", +"Ok": "Ok", +"Cancel": "Cancel", +"Visual aids": "Visual aids", +"Bold": "Bold", +"Italic": "Italic", +"Underline": "Underline", +"Strikethrough": "Strikethrough", +"Superscript": "Superscript", +"Subscript": "Subscript", +"Clear formatting": "Clear formatting", +"Align left": "Align left", +"Align center": "Align center", +"Align right": "Align right", +"Justify": "Justify", +"Bullet list": "Bullet list", +"Numbered list": "Numbered list", +"Decrease indent": "Decrease indent", +"Increase indent": "Increase indent", +"Close": "Close", +"Formats": "Formats", +"Your browser doesn't support direct access to the clipboard. Please use the Ctrl+X\/C\/V keyboard shortcuts instead.": "Your browser doesn't support direct access to the clipboard. Please use the Ctrl+X\/C\/V keyboard shortcuts instead.", +"Headers": "Headers", +"Header 1": "Header 1", +"Header 2": "Header 2", +"Header 3": "Header 3", +"Header 4": "Header 4", +"Header 5": "Header 5", +"Header 6": "Header 6", +"Headings": "Headings", +"Heading 1": "Heading 1", +"Heading 2": "Heading 2", +"Heading 3": "Heading 3", +"Heading 4": "Heading 4", +"Heading 5": "Heading 5", +"Heading 6": "Heading 6", +"Preformatted": "Preformatted", +"Div": "Div", +"Pre": "Pre", +"Code": "Code", +"Paragraph": "Paragraph", +"Blockquote": "Blockquote", +"Inline": "Inline", +"Blocks": "Blocks", +"Paste is now in plain text mode. Contents will now be pasted as plain text until you toggle this option off.": "Paste is now in plain text mode. Contents will now be pasted as plain text until you toggle this option off.", +"Font Family": "Font Family", +"Font Sizes": "Font Sizes", +"Class": "Class", +"Browse for an image": "Browse for an image", +"OR": "OR", +"Drop an image here": "Drop an image here", +"Upload": "Upload", +"Block": "Blocks", +"Align": "Align", +"Default": "Default", +"Circle": "Circle", +"Disc": "Disc", +"Square": "Square", +"Lower Alpha": "Lower Alpha", +"Lower Greek": "Lower Greek", +"Lower Roman": "Lower Roman", +"Upper Alpha": "Upper Alpha", +"Upper Roman": "Upper Roman", +"Anchor": "Anchor", +"Name": "Name", +"Id": "ID", +"Id should start with a letter, followed only by letters, numbers, dashes, dots, colons or underscores.": "ID should start with a letter, followed only by letters, numbers, dashes, dots, colons, or underscores.", +"You have unsaved changes are you sure you want to navigate away?": "You have unsaved changes are you sure you want to navigate away?", +"Restore last draft": "Restore last draft", +"Special character": "Special character", +"Source code": "Source code", +"Insert\/Edit code sample": "Insert\/Edit code sample", +"Language": "Language", +"Code sample": "Code sample", +"Color": "color", +"R": "R", +"G": "G", +"B": "B", +"Left to right": "Left to right", +"Right to left": "Right to left", +"Emoticons": "Emoticons", +"Document properties": "Document properties", +"Title": "Title", +"Keywords": "Keywords", +"Description": "Description", +"Robots": "Robots", +"Author": "Author", +"Encoding": "Encoding", +"Fullscreen": "Fullscreen", +"Action": "Action", +"Shortcut": "Shortcut", +"Help": "Help", +"Address": "Address", +"Focus to menubar": "Focus to menubar", +"Focus to toolbar": "Focus to toolbar", +"Focus to element path": "Focus to element path", +"Focus to contextual toolbar": "Focus to contextual toolbar", +"Insert link (if link plugin activated)": "Insert link (if link plugin activated)", +"Save (if save plugin activated)": "Save (if save plugin activated)", +"Find (if searchreplace plugin activated)": "Find (if searchreplace plugin activated)", +"Plugins installed ({0}):": "Plugins installed ({0}):", +"Premium plugins:": "Premium plugins:", +"Learn more...": "Learn more...", +"You are using {0}": "You are using {0}", +"Plugins": "Plugins", +"Handy Shortcuts": "Handy Shortcuts", +"Horizontal line": "Horizontal line", +"Insert\/edit image": "Insert\/edit image", +"Image description": "Image description", +"Source": "Source", +"Dimensions": "Dimensions", +"Constrain proportions": "Constrain proportions", +"General": "General", +"Advanced": "Advanced", +"Style": "Style", +"Vertical space": "Vertical space", +"Horizontal space": "Horizontal space", +"Border": "Border", +"Insert image": "Insert image", +"Image": "Image", +"Image list": "Image list", +"Rotate counterclockwise": "Rotate counterclockwise", +"Rotate clockwise": "Rotate clockwise", +"Flip vertically": "Flip vertically", +"Flip horizontally": "Flip horizontally", +"Edit image": "Edit image", +"Image options": "Image options", +"Zoom in": "Zoom in", +"Zoom out": "Zoom out", +"Crop": "Crop", +"Resize": "Resize", +"Orientation": "Orientation", +"Brightness": "Brightness", +"Sharpen": "Sharpen", +"Contrast": "Contrast", +"Color levels": "color levels", +"Gamma": "Gamma", +"Invert": "Invert", +"Apply": "Apply", +"Back": "Back", +"Insert date\/time": "Insert date\/time", +"Date\/time": "Date\/time", +"Insert link": "Insert link", +"Insert\/edit link": "Insert\/edit link", +"Text to display": "Text to display", +"Url": "Url", +"Target": "Target", +"None": "None", +"New window": "New window", +"Remove link": "Remove link", +"Anchors": "Anchors", +"Link": "Link", +"Paste or type a link": "Paste or type a link", +"The URL you entered seems to be an email address. Do you want to add the required mailto: prefix?": "The URL you entered seems to be an email address. Do you want to add the required mailto: prefix?", +"The URL you entered seems to be an external link. Do you want to add the required http:\/\/ prefix?": "The URL you entered seems to be an external link. Do you want to add the required http:\/\/ prefix?", +"Link list": "Link list", +"Insert video": "Insert video", +"Insert\/edit video": "Insert\/edit video", +"Insert\/edit media": "Insert\/edit media", +"Alternative source": "Alternative source", +"Poster": "Poster", +"Paste your embed code below:": "Paste your embed code below:", +"Embed": "Embed", +"Media": "Media", +"Nonbreaking space": "Nonbreaking space", +"Page break": "Page break", +"Paste as text": "Paste as text", +"Preview": "Preview", +"Print": "Print", +"Save": "Save", +"Find": "Find", +"Replace with": "Replace with", +"Replace": "Replace", +"Replace all": "Replace all", +"Prev": "Prev", +"Next": "Next", +"Find and replace": "Find and replace", +"Could not find the specified string.": "Could not find the specified string.", +"Match case": "Match case", +"Whole words": "Whole words", +"Spellcheck": "Spellcheck", +"Ignore": "Ignore", +"Ignore all": "Ignore all", +"Finish": "Finish", +"Add to Dictionary": "Add to Dictionary", +"Insert table": "Insert table", +"Table properties": "Table properties", +"Delete table": "Delete table", +"Cell": "Cell", +"Row": "Row", +"Column": "Column", +"Cell properties": "Cell properties", +"Merge cells": "Merge cells", +"Split cell": "Split cell", +"Insert row before": "Insert row before", +"Insert row after": "Insert row after", +"Delete row": "Delete row", +"Row properties": "Row properties", +"Cut row": "Cut row", +"Copy row": "Copy row", +"Paste row before": "Paste row before", +"Paste row after": "Paste row after", +"Insert column before": "Insert column before", +"Insert column after": "Insert column after", +"Delete column": "Delete column", +"Cols": "Cols", +"Rows": "Rows", +"Width": "Width", +"Height": "Height", +"Cell spacing": "Cell spacing", +"Cell padding": "Cell padding", +"Caption": "Caption", +"Left": "Left", +"Center": "Center", +"Right": "Right", +"Cell type": "Cell type", +"Scope": "Scope", +"Alignment": "Alignment", +"H Align": "H Align", +"V Align": "V Align", +"Top": "Top", +"Middle": "Middle", +"Bottom": "Bottom", +"Header cell": "Header cell", +"Row group": "Row group", +"Column group": "Column group", +"Row type": "Row type", +"Header": "Header", +"Body": "Body", +"Footer": "Footer", +"Border color": "Border color", +"Insert template": "Insert template", +"Templates": "Templates", +"Template": "Template", +"Text color": "Text color", +"Background color": "Background color", +"Custom...": "Custom...", +"Custom color": "Custom color", +"No color": "No color", +"Table of Contents": "Table of Contents", +"Show blocks": "Show blocks", +"Show invisible characters": "Show invisible characters", +"Words: {0}": "Words: {0}", +"{0} words": "{0} words", +"File": "File", +"Edit": "Edit", +"Insert": "Insert", +"View": "View", +"Format": "Format", +"Table": "Table", +"Tools": "Tools", +"Powered by {0}": "Powered by {0}", +"Rich Text Area. Press ALT-F9 for menu. Press ALT-F10 for toolbar. Press ALT-0 for help": "Rich Text Area. Press ALT-F9 for menu. Press ALT-F10 for toolbar. Press ALT-0 for help" +}); \ No newline at end of file From e2604103a32ec01ffd722a3b51ceb23a855a2f83 Mon Sep 17 00:00:00 2001 From: Rachel Breeze Date: Tue, 26 May 2020 14:10:16 +0100 Subject: [PATCH 26/35] v8: Accessibility Create User Page Title (#7104) --- .../src/views/users/views/users/users.controller.js | 1 + 1 file changed, 1 insertion(+) diff --git a/src/Umbraco.Web.UI.Client/src/views/users/views/users/users.controller.js b/src/Umbraco.Web.UI.Client/src/views/users/views/users/users.controller.js index 102efae702..2217628872 100644 --- a/src/Umbraco.Web.UI.Client/src/views/users/views/users/users.controller.js +++ b/src/Umbraco.Web.UI.Client/src/views/users/views/users/users.controller.js @@ -814,6 +814,7 @@ vm.newUser.message = ""; // clear button state vm.page.createButtonState = "init"; + $scope.$emit("$setAccessibleHeader", true, "general_user", false, "", "", true); } init(); From 6da69f1e429e4666592a81c615e9e95aa5ad092e Mon Sep 17 00:00:00 2001 From: Rachel Breeze Date: Tue, 26 May 2020 14:34:30 +0100 Subject: [PATCH 27/35] V8: Accessibility changes for login screen (#5800) --- .../application/umblogin.directive.js | 124 +++++++++--------- .../src/less/pages/login.less | 5 +- .../components/application/umb-login.html | 6 +- 3 files changed, 69 insertions(+), 66 deletions(-) diff --git a/src/Umbraco.Web.UI.Client/src/common/directives/components/application/umblogin.directive.js b/src/Umbraco.Web.UI.Client/src/common/directives/components/application/umblogin.directive.js index ec8da898ad..6dd740e08b 100644 --- a/src/Umbraco.Web.UI.Client/src/common/directives/components/application/umblogin.directive.js +++ b/src/Umbraco.Web.UI.Client/src/common/directives/components/application/umblogin.directive.js @@ -63,10 +63,14 @@ vm.labels = {}; localizationService.localizeMany([ vm.usernameIsEmail ? "general_email" : "general_username", - vm.usernameIsEmail ? "placeholders_email" : "placeholders_usernameHint"] + vm.usernameIsEmail ? "placeholders_email" : "placeholders_usernameHint", + vm.usernameIsEmail ? "placeholders_emptyEmail" : "placeholders_emptyUsername", + "placeholders_emptyPassword"] ).then(function (data) { vm.labels.usernameLabel = data[0]; vm.labels.usernamePlaceholder = data[1]; + vm.labels.usernameError = data[2]; + vm.labels.passwordError = data[3]; }); vm.twoFactor = {}; @@ -193,72 +197,70 @@ } function loginSubmit() { - - // make sure that we are returning to the login view. - vm.view = "login"; - - // TODO: Do validation properly like in the invite password update + + if (formHelper.submitForm({ scope: $scope })) { + //if the login and password are not empty we need to automatically + // validate them - this is because if there are validation errors on the server + // then the user has to change both username & password to resubmit which isn't ideal, + // so if they're not empty, we'll just make sure to set them to valid. + if (vm.login && vm.password && vm.login.length > 0 && vm.password.length > 0) { + vm.loginForm.username.$setValidity('auth', true); + vm.loginForm.password.$setValidity('auth', true); + } + + if (vm.loginForm.$invalid) { + SetTitle(); + return; + } + + // make sure that we are returning to the login view. + vm.view = "login"; - //if the login and password are not empty we need to automatically - // validate them - this is because if there are validation errors on the server - // then the user has to change both username & password to resubmit which isn't ideal, - // so if they're not empty, we'll just make sure to set them to valid. - if (vm.login && vm.password && vm.login.length > 0 && vm.password.length > 0) { - vm.loginForm.username.$setValidity('auth', true); - vm.loginForm.password.$setValidity('auth', true); - } + vm.loginStates.submitButton = "busy"; - if (vm.loginForm.$invalid) { - SetTitle(); - return; - } + userService.authenticate(vm.login, vm.password) + .then(function(data) { + vm.loginStates.submitButton = "success"; + userService._retryRequestQueue(true); + if (vm.onLogin) { + vm.onLogin(); + } + }, + function(reason) { - vm.loginStates.submitButton = "busy"; + //is Two Factor required? + if (reason.status === 402) { + vm.errorMsg = "Additional authentication required"; + show2FALoginDialog(reason.data.twoFactorView); + } else { + vm.loginStates.submitButton = "error"; + vm.errorMsg = reason.errorMsg; - userService.authenticate(vm.login, vm.password) - .then(function (data) { - vm.loginStates.submitButton = "success"; - userService._retryRequestQueue(true); - if(vm.onLogin) { - vm.onLogin(); + //set the form inputs to invalid + vm.loginForm.username.$setValidity("auth", false); + vm.loginForm.password.$setValidity("auth", false); + } + + userService._retryRequestQueue(); + + }); + + //setup a watch for both of the model values changing, if they change + // while the form is invalid, then revalidate them so that the form can + // be submitted again. + vm.loginForm.username.$viewChangeListeners.push(function() { + if (vm.loginForm.$invalid) { + vm.loginForm.username.$setValidity('auth', true); + vm.loginForm.password.$setValidity('auth', true); } - }, - function (reason) { - - //is Two Factor required? - if (reason.status === 402) { - vm.errorMsg = "Additional authentication required"; - show2FALoginDialog(reason.data.twoFactorView); - } - else { - vm.loginStates.submitButton = "error"; - vm.errorMsg = reason.errorMsg; - - //set the form inputs to invalid - vm.loginForm.username.$setValidity("auth", false); - vm.loginForm.password.$setValidity("auth", false); - } - - userService._retryRequestQueue(); - }); - - //setup a watch for both of the model values changing, if they change - // while the form is invalid, then revalidate them so that the form can - // be submitted again. - vm.loginForm.username.$viewChangeListeners.push(function () { - if (vm.loginForm.$invalid) { - vm.loginForm.username.$setValidity('auth', true); - vm.loginForm.password.$setValidity('auth', true); - } - }); - vm.loginForm.password.$viewChangeListeners.push(function () { - if (vm.loginForm.$invalid) { - vm.loginForm.username.$setValidity('auth', true); - vm.loginForm.password.$setValidity('auth', true); - } - }); - SetTitle(); + vm.loginForm.password.$viewChangeListeners.push(function() { + if (vm.loginForm.$invalid) { + vm.loginForm.username.$setValidity('auth', true); + vm.loginForm.password.$setValidity('auth', true); + } + }); + } } function requestPasswordResetSubmit(email) { diff --git a/src/Umbraco.Web.UI.Client/src/less/pages/login.less b/src/Umbraco.Web.UI.Client/src/less/pages/login.less index e36acdc273..818b1d84d1 100644 --- a/src/Umbraco.Web.UI.Client/src/less/pages/login.less +++ b/src/Umbraco.Web.UI.Client/src/less/pages/login.less @@ -123,6 +123,7 @@ position: relative; text-align: right; user-select: none; + margin-left: auto; a { opacity: .5; @@ -134,8 +135,8 @@ .password-text { background-repeat: no-repeat; background-size: 18px; - background-position: left center; - padding-left: 26px; + background-position: 0px 1px; + padding-left: 24px; &.show { background-image: url("data:image/svg+xml;charset=utf8,%3Csvg xmlns='http://www.w3.org/2000/svg' width='32' height='32' viewBox='0 0 32 32'%3E%3Cpath fill='%23444' d='M16 6C9 6 3 10 0 16c3 6 9 10 16 10s13-4 16-10c-3-6-9-10-16-10zm8 5.3c1.8 1.2 3.4 2.8 4.6 4.7-1.2 2-2.8 3.5-4.7 4.7-3 1.5-6 2.3-8 2.3s-6-.8-8-2.3C6 19.5 4 18 3 16c1.5-2 3-3.5 5-4.7l.6-.2C8 12 8 13 8 14c0 4.5 3.5 8 8 8s8-3.5 8-8c0-1-.3-2-.6-2.6l.4.3zM16 13c0 1.7-1.3 3-3 3s-3-1.3-3-3 1.3-3 3-3 3 1.3 3 3z'/%3E%3C/svg%3E"); diff --git a/src/Umbraco.Web.UI.Client/src/views/components/application/umb-login.html b/src/Umbraco.Web.UI.Client/src/views/components/application/umb-login.html index 2e81395643..098d69960d 100644 --- a/src/Umbraco.Web.UI.Client/src/views/components/application/umb-login.html +++ b/src/Umbraco.Web.UI.Client/src/views/components/application/umb-login.html @@ -149,16 +149,16 @@
- +
- +
- +
Show password From 32a0c3b075f8230dd00142aa7ebc161a67faffaf Mon Sep 17 00:00:00 2001 From: Jan Skovgaard Date: Tue, 26 May 2020 17:45:39 +0200 Subject: [PATCH 28/35] "Actions" drop down options do not give context to the user (#6301) --- .../views/components/editor/umb-editor-menu.html | 9 ++++++++- src/Umbraco.Web.UI/Umbraco/config/lang/da.xml | 10 +++++++++- src/Umbraco.Web.UI/Umbraco/config/lang/en.xml | 10 +++++++++- src/Umbraco.Web.UI/Umbraco/config/lang/en_us.xml | 14 +++++++++++++- src/Umbraco.Web/Models/Trees/MenuItem.cs | 9 ++++++++- src/Umbraco.Web/Models/Trees/MenuItemList.cs | 11 ++++++++--- src/Umbraco.Web/Trees/ContentTreeController.cs | 2 +- 7 files changed, 56 insertions(+), 9 deletions(-) diff --git a/src/Umbraco.Web.UI.Client/src/views/components/editor/umb-editor-menu.html b/src/Umbraco.Web.UI.Client/src/views/components/editor/umb-editor-menu.html index fe90fef07a..ceae7c3bb9 100644 --- a/src/Umbraco.Web.UI.Client/src/views/components/editor/umb-editor-menu.html +++ b/src/Umbraco.Web.UI.Client/src/views/components/editor/umb-editor-menu.html @@ -15,7 +15,14 @@ diff --git a/src/Umbraco.Web.UI/Umbraco/config/lang/da.xml b/src/Umbraco.Web.UI/Umbraco/config/lang/da.xml index 7cead86114..a876b1a6b7 100644 --- a/src/Umbraco.Web.UI/Umbraco/config/lang/da.xml +++ b/src/Umbraco.Web.UI/Umbraco/config/lang/da.xml @@ -247,7 +247,7 @@ Dette dokument er udgivet, men dets URL kan ikke dirigeres Udgiv Udgivet - Udgivet (Afventende ændringer) + Udgivet (Ventede ændringer) Udgivelsesstatus Udgiv med undersider for at udgive %0% og alle sider under og dermed gøre deres indhold offentligt tilgængelige.]]> Udgiv med undersider for at udgive de valgte sprog og de samme sprog for sider under og dermed gøre deres indhold offentligt tilgængelige.]]> @@ -426,6 +426,7 @@ Internt link: Ved lokalt link, indsæt da en "#" foran linket Åben i nyt vindue? + Makroindstillinger Denne makro har ingen egenskaber du kan redigere Indsæt tekst Rediger rettigheder for @@ -663,6 +664,7 @@ Ikon Id Importer + Inkludér undermapper i søgning Søg kun i denne mappe Info Indre margen @@ -1749,6 +1751,12 @@ Mange hilsner fra Umbraco robotten Åben backoffice søgning Åben/Luk backoffice hjælp Åben/Luk dine profil indstillinger + Tilføj domæne på %0% + Opret ny node under %0% + Opsæt offentlig adgang på %0% + Opsæt rettigheder på %0% + Juster soterings rækkefølgen for %0% + Opret indholds skabelon baseret på %0% Aktivt sprog Skift sprog til Opret ny mappe diff --git a/src/Umbraco.Web.UI/Umbraco/config/lang/en.xml b/src/Umbraco.Web.UI/Umbraco/config/lang/en.xml index e764b5591e..e4f9ed7b91 100644 --- a/src/Umbraco.Web.UI/Umbraco/config/lang/en.xml +++ b/src/Umbraco.Web.UI/Umbraco/config/lang/en.xml @@ -141,6 +141,7 @@ Save and send for approval Save list view Schedule + Preview Save and preview Preview is disabled because there's no template assigned Choose style @@ -686,6 +687,7 @@ Icon Id Import + Include subfolders in search Search only this folder Info Inner margin @@ -2228,6 +2230,12 @@ To manage your website, simply open the Umbraco back office and start adding con Open backoffice search Open/Close backoffice help Open/Close your profile options + Setup Culture and Hostnames for %0% + Create new node under %0% + Setup Public access on %0% + Setup Permissions on %0% + Change sort order for %0% + Create Content Template based on %0% Open context menu for Current language Switch language to @@ -2243,7 +2251,7 @@ To manage your website, simply open the Umbraco back office and start adding con Create Edit Name - Add new row + Add new row View more options 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 e1b1df2c34..5fc037d8b3 100644 --- a/src/Umbraco.Web.UI/Umbraco/config/lang/en_us.xml +++ b/src/Umbraco.Web.UI/Umbraco/config/lang/en_us.xml @@ -140,6 +140,7 @@ Send for approval Save list view Schedule + Preview Save and preview Preview is disabled because there's no template assigned Choose style @@ -369,7 +370,8 @@ Document Types within the Settings section, by changing the Allow as root option under Permissions.]]> Media Types Types within the Settings section, by editing the Allowed child node types under Permissions.]]> The selected media in the tree doesn't allow for any other media to be created below it. - Edit permissions for this media type Document Type without a template + Edit permissions for this media type + Document Type without a template New folder New data type New JavaScript file @@ -570,6 +572,9 @@ #value or ?key=value Enter alias... Generating alias... + Create item + Edit + Name Create custom list view @@ -690,6 +695,7 @@ Icon Id Import + Include subfolders in search Search only this folder Info Inner margin @@ -2244,6 +2250,12 @@ To manage your website, simply open the Umbraco back office and start adding con Open backoffice search Open/Close backoffice help Open/Close your profile options + Setup Culture and Hostnames for %0% + Create new node under %0% + Setup Public access on %0% + Setup Permissions on %0% + Change sort order for %0% + Create Content Template based on %0% Open context menu for Current language Switch language to diff --git a/src/Umbraco.Web/Models/Trees/MenuItem.cs b/src/Umbraco.Web/Models/Trees/MenuItem.cs index 9d4c76eea1..094c6b24ff 100644 --- a/src/Umbraco.Web/Models/Trees/MenuItem.cs +++ b/src/Umbraco.Web/Models/Trees/MenuItem.cs @@ -5,6 +5,7 @@ using System.Collections.Generic; using Umbraco.Core; using Umbraco.Core.Services; using Umbraco.Web.Actions; +using System.Threading; namespace Umbraco.Web.Models.Trees { @@ -28,12 +29,15 @@ namespace Umbraco.Web.Models.Trees Name = name; } - public MenuItem(string alias, ILocalizedTextService textService) : this() { + var values = textService.GetAllStoredValues(Thread.CurrentThread.CurrentUICulture); + values.TryGetValue($"visuallyHiddenTexts/{alias}_description", out var textDescription); + Alias = alias; Name = textService.Localize($"actions/{Alias}"); + TextDescription = textDescription; } /// @@ -74,6 +78,9 @@ namespace Umbraco.Web.Models.Trees [Required] public string Alias { get; set; } + [DataMember(Name = "textDescription")] + public string TextDescription { get; set; } + /// /// Ensures a menu separator will exist before this menu item /// diff --git a/src/Umbraco.Web/Models/Trees/MenuItemList.cs b/src/Umbraco.Web/Models/Trees/MenuItemList.cs index 1df486ebdf..4aaf0632ab 100644 --- a/src/Umbraco.Web/Models/Trees/MenuItemList.cs +++ b/src/Umbraco.Web/Models/Trees/MenuItemList.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using System.Threading; using Umbraco.Core; using Umbraco.Core.Services; using Umbraco.Web.Actions; @@ -75,7 +76,7 @@ namespace Umbraco.Web.Models.Trees } return null; } - + internal MenuItem CreateMenuItem(string name, bool hasSeparator = false, bool opensDialog = false) where T : IAction { @@ -96,14 +97,18 @@ namespace Umbraco.Web.Models.Trees var item = Current.Actions.GetAction(); if (item == null) return null; + var values = textService.GetAllStoredValues(Thread.CurrentThread.CurrentUICulture); + values.TryGetValue($"visuallyHiddenTexts/{item.Alias}Description", out var textDescription); + var menuItem = new MenuItem(item, textService.Localize($"actions/{item.Alias}")) { SeparatorBefore = hasSeparator, - OpensDialog = opensDialog + OpensDialog = opensDialog, + TextDescription = textDescription, }; return menuItem; } - + } } diff --git a/src/Umbraco.Web/Trees/ContentTreeController.cs b/src/Umbraco.Web/Trees/ContentTreeController.cs index 85ff30487d..663af43643 100644 --- a/src/Umbraco.Web/Trees/ContentTreeController.cs +++ b/src/Umbraco.Web/Trees/ContentTreeController.cs @@ -323,7 +323,7 @@ namespace Umbraco.Web.Trees private void AddActionNode(IUmbracoEntity item, MenuItemCollection menu, bool hasSeparator = false, bool opensDialog = false) where TAction : IAction { - var menuItem = menu.Items.Add(Services.TextService.Localize("actions", _actions.GetAction().Alias), hasSeparator, opensDialog); + var menuItem = menu.Items.Add(Services.TextService, hasSeparator, opensDialog); } public IEnumerable Search(string query, int pageSize, long pageIndex, out long totalFound, string searchFrom = null) From cc04a1c8fe9d7d3c639d744a618bfd9cd631a41a Mon Sep 17 00:00:00 2001 From: Jan Skovgaard Date: Tue, 26 May 2020 18:01:17 +0200 Subject: [PATCH 29/35] Content templates dashboard: Add translations and move styles external (#6888) --- src/Umbraco.Web.UI.Client/src/less/belle.less | 1 + .../less/dashboards/content-templates.less | 22 +++++++++++ .../src/views/contentblueprints/intro.html | 37 ++++++++++++------- src/Umbraco.Web.UI/Umbraco/config/lang/en.xml | 17 +++++++++ .../Umbraco/config/lang/en_us.xml | 17 +++++++++ 5 files changed, 81 insertions(+), 13 deletions(-) create mode 100644 src/Umbraco.Web.UI.Client/src/less/dashboards/content-templates.less diff --git a/src/Umbraco.Web.UI.Client/src/less/belle.less b/src/Umbraco.Web.UI.Client/src/less/belle.less index 174f9f41d7..f0d7c6f1e1 100644 --- a/src/Umbraco.Web.UI.Client/src/less/belle.less +++ b/src/Umbraco.Web.UI.Client/src/less/belle.less @@ -227,6 +227,7 @@ @import "dashboards/umbraco-forms.less"; @import "dashboards/examine-management.less"; @import "dashboards/healthcheck.less"; +@import "dashboards/content-templates.less"; @import "dashboards/nucache.less"; @import "typeahead.less"; diff --git a/src/Umbraco.Web.UI.Client/src/less/dashboards/content-templates.less b/src/Umbraco.Web.UI.Client/src/less/dashboards/content-templates.less new file mode 100644 index 0000000000..9966fc97e1 --- /dev/null +++ b/src/Umbraco.Web.UI.Client/src/less/dashboards/content-templates.less @@ -0,0 +1,22 @@ +.content-templates-dashboard{ + p{ + line-height: 1.6em; + margin-bottom: 30px; + + &:last-child{ + margin-bottom: 0; + } + } + + ul{ + margin-bottom: 15px; + } + + li{ + margin-bottom: 5px; + + &:last-child{ + margin-bottom: 0; + } + } +} \ No newline at end of file diff --git a/src/Umbraco.Web.UI.Client/src/views/contentblueprints/intro.html b/src/Umbraco.Web.UI.Client/src/views/contentblueprints/intro.html index ce423225f6..66695ace91 100644 --- a/src/Umbraco.Web.UI.Client/src/views/contentblueprints/intro.html +++ b/src/Umbraco.Web.UI.Client/src/views/contentblueprints/intro.html @@ -12,21 +12,32 @@ - -

What are Content Templates?

-

Content Templates are pre-defined content that can be selected when creating a new content node.

+ +

+ What are Content Templates? +

+

+ Content Templates are pre-defined content that can be selected when creating a new content node. +

-

How do I create a Content Template?

-

There are two ways to create a Content Template:

-
    -
  • Right-click a content node and select "Create Content Template" to create a new Content Template.
  • -
  • Right-click the Content Templates tree in the Settings section and select the Document Type you want to create a Content Template for.
  • -
-

Once given a name, editors can start using the Content Template as a foundation for their new page.

+

+ How do I create a Content Template? +

+ +

There are two ways to create a Content Template:

+
    +
  • Right-click a content node and select "Create Content Template" to create a new Content Template.
  • +
  • Right-click the Content Templates tree in the Settings section and select the Document Type you want to create a Content Template for.
  • +
+

Once given a name, editors can start using the Content Template as a foundation for their new page.

+
-

How do I manage Content Templates

-

You can edit and delete Content Templates from the "Content Templates" tree in the Settings section. Just expand the Document Type which the - Content Template is based on and click it to edit or delete it.

+

+ How do I manage Content Templates? +

+

+ You can edit and delete Content Templates from the "Content Templates" tree in the Settings section. Just expand the Document Type which the Content Template is based on and click it to edit or delete it. +

diff --git a/src/Umbraco.Web.UI/Umbraco/config/lang/en.xml b/src/Umbraco.Web.UI/Umbraco/config/lang/en.xml index e4f9ed7b91..e96ef754c4 100644 --- a/src/Umbraco.Web.UI/Umbraco/config/lang/en.xml +++ b/src/Umbraco.Web.UI/Umbraco/config/lang/en.xml @@ -2423,4 +2423,21 @@ To manage your website, simply open the Umbraco back office and start adding con Umbraco Forms Create forms using an intuitive drag and drop interface. From simple contact forms that sends e-mails to advanced questionaires that integrate with CRM systems. Your clients will love it! + + What are Content Templates? + Content Templates are pre-defined content that can be selected when creating a new content node. + How do I create a Content Template? + + There are two ways to create a Content Template:

+
    +
  • Right-click a content node and select "Create Content Template" to create a new Content Template.
  • +
  • Right-click the Content Templates tree in the Settings section and select the Document Type you want to create a Content Template for.
  • +
+

Once given a name, editors can start using the Content Template as a foundation for their new page.

+ ]]> +
+ How do I manage Content Templates? + You can edit and delete Content Templates from the "Content Templates" tree in the Settings section. Expand the Document Type which the Content Template is based on and click it to edit or delete it. + 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 5fc037d8b3..2bb6495977 100644 --- a/src/Umbraco.Web.UI/Umbraco/config/lang/en_us.xml +++ b/src/Umbraco.Web.UI/Umbraco/config/lang/en_us.xml @@ -2443,4 +2443,21 @@ To manage your website, simply open the Umbraco back office and start adding con Umbraco Forms Create forms using an intuitive drag and drop interface. From simple contact forms that sends e-mails to advanced questionaires that integrate with CRM systems. Your clients will love it! + + What are Content Templates? + Content Templates are pre-defined content that can be selected when creating a new content node. + How do I create a Content Template? + + There are two ways to create a Content Template:

+
    +
  • Right-click a content node and select "Create Content Template" to create a new Content Template.
  • +
  • Right-click the Content Templates tree in the Settings section and select the Document Type you want to create a Content Template for.
  • +
+

Once given a name, editors can start using the Content Template as a foundation for their new page.

+ ]]> +
+ How do I manage Content Templates? + You can edit and delete Content Templates from the "Content Templates" tree in the Settings section. Expand the Document Type which the Content Template is based on and click it to edit or delete it. + From 19f16c3b1fefadfd71d2de523fd13561ffeb69aa Mon Sep 17 00:00:00 2001 From: Jan Skovgaard Date: Tue, 26 May 2020 18:02:21 +0200 Subject: [PATCH 30/35] Theme backoffice docs for v8 to clearly differentiate it from the v7 docs (#8010) --- src/Umbraco.Web.UI.Docs/gulpfile.js | 4 +-- src/Umbraco.Web.UI.Docs/umb-docs.css | 39 +++++++++++++++++----------- 2 files changed, 26 insertions(+), 17 deletions(-) diff --git a/src/Umbraco.Web.UI.Docs/gulpfile.js b/src/Umbraco.Web.UI.Docs/gulpfile.js index 789e2b7845..a3e596ecad 100644 --- a/src/Umbraco.Web.UI.Docs/gulpfile.js +++ b/src/Umbraco.Web.UI.Docs/gulpfile.js @@ -16,7 +16,7 @@ gulp.task('docs', [], function (cb) { var options = { html5Mode: false, startPage: '/api', - title: "Umbraco Backoffice UI API Documentation", + title: "Umbraco 8 Backoffice UI API Documentation", dest: './api', styles: ['./umb-docs.css'], image: "https://our.umbraco.com/assets/images/logo.svg" @@ -53,4 +53,4 @@ gulp.task('open:docs', function (cb) { gulp.src(__filename) .pipe(open(options)); cb(); -}); \ No newline at end of file +}); diff --git a/src/Umbraco.Web.UI.Docs/umb-docs.css b/src/Umbraco.Web.UI.Docs/umb-docs.css index 0f2e3e7f74..b748a0a609 100644 --- a/src/Umbraco.Web.UI.Docs/umb-docs.css +++ b/src/Umbraco.Web.UI.Docs/umb-docs.css @@ -4,7 +4,7 @@ html { } body { font-family: 'Segoe UI', Tahoma, Helvetica, sans-serif; - + } .container, .navbar-static-top .container, .navbar-fixed-top .container, .navbar-fixed-bottom .container { @@ -33,37 +33,43 @@ body { font-family: inherit; } +.navbar .container{ + min-height: inherit; + display: flex; + align-items: center; +} + .navbar .brand { display: block; - float: left; - padding: 10px 20px 10px; - margin-left: -20px; - font-size: 20px; - font-weight: 200; - color: rgba(0,0,0,.8); + color: white; text-shadow: none; } .navbar-fixed-top .navbar-inner { min-height: 50px; - background: #a3db78; + background: #3544b1; } .form-search .well { - background-color: #f5fbf1; + background-color: #f7f7f7; } .form-search > ul.nav > li.module { - background-color: #daf0c9; + background-color: #3544b1; } -.breadcrumb { - background-color: #f5fbf1; +.form-search > ul.nav > li.module a { + color: white; } -a { - color: #f36f21; +.form-search > ul.nav > li.section { + background-color: #ccc; } + +.breadcrumb { + background-color: #f7f7f7; +} + a:hover { text-decoration: none; color: rgba(0,0,0,.8); @@ -87,9 +93,12 @@ a:hover { color: #000; } +.form-search > ul.nav > li.module > a:hover{ + color: #fff; +} + .header img { width: 50px; - margin-top: 5px; } .content .methods code { From 14ad2bd27cae73f2dcf41d8f810ec1c50975b032 Mon Sep 17 00:00:00 2001 From: Jan Skovgaard Date: Tue, 26 May 2020 18:15:18 +0200 Subject: [PATCH 31/35] Convert span to button, add missing label, hide icons for screen readers (#8011) --- src/Umbraco.Web.UI.Client/src/less/property-editors.less | 2 +- .../src/views/propertyeditors/datepicker/datepicker.html | 9 +++++---- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/src/Umbraco.Web.UI.Client/src/less/property-editors.less b/src/Umbraco.Web.UI.Client/src/less/property-editors.less index 764b73c593..b5870b8dce 100644 --- a/src/Umbraco.Web.UI.Client/src/less/property-editors.less +++ b/src/Umbraco.Web.UI.Client/src/less/property-editors.less @@ -863,11 +863,11 @@ .bootstrap-datetimepicker-widget .picker-switch .btn{ background: none; border: none;} .umb-datepicker .input-append .add-on{cursor: pointer;} .umb-datepicker .input-append .on-top { + border: 0 none; position: absolute; margin-left: -31px; margin-top: 1px; display: inline-block; - height: 22px; padding: 5px 6px 3px 6px; font-size: @baseFontSize; font-weight: normal; diff --git a/src/Umbraco.Web.UI.Client/src/views/propertyeditors/datepicker/datepicker.html b/src/Umbraco.Web.UI.Client/src/views/propertyeditors/datepicker/datepicker.html index e697dc56a5..b35663c3df 100644 --- a/src/Umbraco.Web.UI.Client/src/views/propertyeditors/datepicker/datepicker.html +++ b/src/Umbraco.Web.UI.Client/src/views/propertyeditors/datepicker/datepicker.html @@ -20,10 +20,11 @@ ng-required="model.validation.mandatory" val-server="value" class="datepickerinput"> - - - - + +
From 62b0886afe8b6bbc394709be51376c446b3961be Mon Sep 17 00:00:00 2001 From: BatJan Date: Sat, 16 May 2020 20:23:44 +0200 Subject: [PATCH 32/35] Fix label alignment --- .../src/less/components/umb-form-check.less | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/Umbraco.Web.UI.Client/src/less/components/umb-form-check.less b/src/Umbraco.Web.UI.Client/src/less/components/umb-form-check.less index a52f81b92a..9a3760444d 100644 --- a/src/Umbraco.Web.UI.Client/src/less/components/umb-form-check.less +++ b/src/Umbraco.Web.UI.Client/src/less/components/umb-form-check.less @@ -18,6 +18,8 @@ label.umb-form-check--checkbox{ } .umb-form-check__info { margin-left:20px; + position: relative; + top: 3px; } From 30900c59aef9d160136f559ac230ef060572b40b Mon Sep 17 00:00:00 2001 From: BatJan Date: Sat, 16 May 2020 21:00:41 +0200 Subject: [PATCH 33/35] Add disable-dirty-check option --- .../components/forms/umbcheckbox.directive.js | 4 +++- .../views/components/forms/umb-checkbox.html | 19 ++++++++++++++++--- 2 files changed, 19 insertions(+), 4 deletions(-) diff --git a/src/Umbraco.Web.UI.Client/src/common/directives/components/forms/umbcheckbox.directive.js b/src/Umbraco.Web.UI.Client/src/common/directives/components/forms/umbcheckbox.directive.js index 9a9d6d4a76..389aec2044 100644 --- a/src/Umbraco.Web.UI.Client/src/common/directives/components/forms/umbcheckbox.directive.js +++ b/src/Umbraco.Web.UI.Client/src/common/directives/components/forms/umbcheckbox.directive.js @@ -32,6 +32,7 @@ @param {boolean} required Set the checkbox to be required. @param {callback} onChange Callback when the value of the checkbox change by interaction. @param {string} cssClass Set a css class modifier +@param {boolean} disableDirtyCheck Disable checking if the model is dirty **/ @@ -84,7 +85,8 @@ required: "<", onChange: "&?", cssClass: "@?", - iconClass: "@?" + iconClass: "@?", + disableDirtyCheck: "=?" } }; diff --git a/src/Umbraco.Web.UI.Client/src/views/components/forms/umb-checkbox.html b/src/Umbraco.Web.UI.Client/src/views/components/forms/umb-checkbox.html index ba5adf199a..5f83d9ae53 100644 --- a/src/Umbraco.Web.UI.Client/src/views/components/forms/umb-checkbox.html +++ b/src/Umbraco.Web.UI.Client/src/views/components/forms/umb-checkbox.html @@ -1,7 +1,7 @@
- + ng-change="vm.change()" + no-dirty-check /> + +
-
{{ name }}
+
{{ name }}
{{ description }}
From 9df6a8bd6af17ecfb2aa2e0a7107798236703db8 Mon Sep 17 00:00:00 2001 From: Warren Buckley Date: Wed, 27 May 2020 14:59:15 +0000 Subject: [PATCH 35/35] Bugfix: Adds new confirmation email marketing step (#8091) --- .../confirm/confirm.controller.js | 15 +++++++++++++++ .../tours/umbEmailMarketing/confirm/confirm.html | 15 +++++++++++++++ .../umbEmailMarketing/emails/emails.controller.js | 5 +---- .../config/BackOfficeTours/getting-started.json | 4 ++++ 4 files changed, 35 insertions(+), 4 deletions(-) create mode 100644 src/Umbraco.Web.UI.Client/src/views/common/tours/umbEmailMarketing/confirm/confirm.controller.js create mode 100644 src/Umbraco.Web.UI.Client/src/views/common/tours/umbEmailMarketing/confirm/confirm.html diff --git a/src/Umbraco.Web.UI.Client/src/views/common/tours/umbEmailMarketing/confirm/confirm.controller.js b/src/Umbraco.Web.UI.Client/src/views/common/tours/umbEmailMarketing/confirm/confirm.controller.js new file mode 100644 index 0000000000..ef4f5ce1ce --- /dev/null +++ b/src/Umbraco.Web.UI.Client/src/views/common/tours/umbEmailMarketing/confirm/confirm.controller.js @@ -0,0 +1,15 @@ +(function () { + "use strict"; + + function ConfirmController($scope, userService) { + + var vm = this; + vm.userEmailAddress = ""; + + userService.getCurrentUser().then(function(user){ + vm.userEmailAddress = user.email; + }); + } + + angular.module("umbraco").controller("Umbraco.Tours.UmbEmailMarketing.ConfirmController", ConfirmController); +})(); diff --git a/src/Umbraco.Web.UI.Client/src/views/common/tours/umbEmailMarketing/confirm/confirm.html b/src/Umbraco.Web.UI.Client/src/views/common/tours/umbEmailMarketing/confirm/confirm.html new file mode 100644 index 0000000000..34acb194e3 --- /dev/null +++ b/src/Umbraco.Web.UI.Client/src/views/common/tours/umbEmailMarketing/confirm/confirm.html @@ -0,0 +1,15 @@ +
+ + + + +

We have sent a welcome email to your email address {{ vm.userEmailAddress }}

+
+ + +
+ +
+
+ +
diff --git a/src/Umbraco.Web.UI.Client/src/views/common/tours/umbEmailMarketing/emails/emails.controller.js b/src/Umbraco.Web.UI.Client/src/views/common/tours/umbEmailMarketing/emails/emails.controller.js index 8ecc737278..d3040a5c3f 100644 --- a/src/Umbraco.Web.UI.Client/src/views/common/tours/umbEmailMarketing/emails/emails.controller.js +++ b/src/Umbraco.Web.UI.Client/src/views/common/tours/umbEmailMarketing/emails/emails.controller.js @@ -13,10 +13,7 @@ userService.addUserToEmailMarketing(user); }); - // Mark Tour as complete - // This is also can help us indicate that the user accepted - // Where disabled is set if user closes modal or chooses NO - $scope.model.completeTour(); + $scope.model.nextStep(); } } diff --git a/src/Umbraco.Web.UI/config/BackOfficeTours/getting-started.json b/src/Umbraco.Web.UI/config/BackOfficeTours/getting-started.json index 7b3f2a2184..d0aa1a1c34 100644 --- a/src/Umbraco.Web.UI/config/BackOfficeTours/getting-started.json +++ b/src/Umbraco.Web.UI/config/BackOfficeTours/getting-started.json @@ -14,6 +14,10 @@ "content": "

Thank you for using Umbraco! Would you like to stay up-to-date with Umbraco product updates, security advisories, community news and special offers? Sign up for our newsletter and never miss out on the latest Umbraco news.

By signing up, you agree that we can use your info according to our privacy policy.

", "view": "emails", "type": "promotion" + }, + { + "title": "Thank you for subscribing to our mailing list", + "view": "confirm" } ] },