From 45f574ed3a6c90137d1e0a18b8a3188b30685339 Mon Sep 17 00:00:00 2001 From: Kenn Jacobsen Date: Sat, 29 Sep 2018 07:27:39 +0200 Subject: [PATCH 01/98] Ensure the correct color for items in the Nested Content item picker --- .../less/components/umb-nested-content.less | 22 +++++++++++++++---- 1 file changed, 18 insertions(+), 4 deletions(-) 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 514a73407c..e433b9fe4a 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 @@ -208,11 +208,25 @@ width: 99%; } -.usky-grid.umb-nested-content__node-type-picker .cell-tools-menu { - position: relative; - transform: translate(-50%, -25%); -} +.usky-grid.umb-nested-content__node-type-picker { + .cell-tools-menu { + position: relative; + transform: translate(-50%, -25%); + } + .elements li { + &:hover { + i { + color: @white !important; + } + } + + i { + // make sure the item icons shown are in the correct color according to their doc type icon instead of the grid editor item color + color: unset; + } + } +} // this resolves the layout issue introduced in nested content in 7.12 with the addition of the input for link anchors // the attribute selector ensures the change only applies to the linkpicker overlay From c6e2ced971e3fefba29c0082be9c29431fe98984 Mon Sep 17 00:00:00 2001 From: Kenn Jacobsen Date: Sat, 29 Sep 2018 07:30:27 +0200 Subject: [PATCH 02/98] Fix Nested Content "second time dragging" issue --- .../src/less/components/umb-nested-content.less | 1 + 1 file changed, 1 insertion(+) 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 514a73407c..31ebe15d8a 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 @@ -1,5 +1,6 @@ .umb-nested-content { text-align: center; + position: relative; } .umb-nested-content--not-supported { From a7573ce31f1f166f86c821ddbbb169383c904281 Mon Sep 17 00:00:00 2001 From: Kenn Jacobsen Date: Sat, 29 Sep 2018 07:35:16 +0200 Subject: [PATCH 03/98] Avoid data loss when dragging an unsaved Nested Content item (#3014) --- .../propertyeditors/nestedcontent/nestedcontent.controller.js | 1 + 1 file changed, 1 insertion(+) diff --git a/src/Umbraco.Web.UI.Client/src/views/propertyeditors/nestedcontent/nestedcontent.controller.js b/src/Umbraco.Web.UI.Client/src/views/propertyeditors/nestedcontent/nestedcontent.controller.js index 0a44a9fcaa..c527cc50a0 100644 --- a/src/Umbraco.Web.UI.Client/src/views/propertyeditors/nestedcontent/nestedcontent.controller.js +++ b/src/Umbraco.Web.UI.Client/src/views/propertyeditors/nestedcontent/nestedcontent.controller.js @@ -231,6 +231,7 @@ angular.module("umbraco").controller("Umbraco.PropertyEditors.NestedContent.Prop cursor: "move", handle: ".umb-nested-content__icon--move", start: function (ev, ui) { + updateModel(); // Yea, yea, we shouldn't modify the dom, sue me $("#umb-nested-content--" + $scope.model.id + " .umb-rte textarea").each(function () { tinymce.execCommand('mceRemoveEditor', false, $(this).attr('id')); From 0dbbb585ad2c76647ae151403e3cb3d81c8ac254 Mon Sep 17 00:00:00 2001 From: Kenn Jacobsen Date: Sat, 29 Sep 2018 17:06:04 +0200 Subject: [PATCH 04/98] Fix loading issue for RTE's in Nested Content --- src/Umbraco.Web.UI.Client/src/less/property-editors.less | 7 +++++++ .../src/views/propertyeditors/rte/rte.html | 2 +- 2 files changed, 8 insertions(+), 1 deletion(-) 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 fabe7c2291..4805c820ee 100644 --- a/src/Umbraco.Web.UI.Client/src/less/property-editors.less +++ b/src/Umbraco.Web.UI.Client/src/less/property-editors.less @@ -115,6 +115,13 @@ div.umb-codeeditor .umb-btn-toolbar { // // RTE // -------------------------------------------------- +.umb-rte { + position: relative; + + .-loading { + position: absolute; + } +} .mce-tinymce{border: 1px solid @gray-8 !important; border-radius: 0px !important;} .mce-panel{background: @gray-10 !important; border-color: @gray-8 !important;} .mce-btn-group, .mce-btn{border: none !important; background: none !important;} 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 774f860c31..b9c2364925 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,5 +1,5 @@
-
Loading...
+
Loading...
From 2c9256c6724d2e840b0b267657a3db930f00e225 Mon Sep 17 00:00:00 2001 From: Kenn Jacobsen Date: Sun, 30 Sep 2018 18:50:33 +0200 Subject: [PATCH 05/98] Don't let the same doctype be selectable twice in the Nested Content configuration --- .../nestedcontent/nestedcontent.controller.js | 12 ++++++++++++ .../nestedcontent/nestedcontent.doctypepicker.html | 2 +- 2 files changed, 13 insertions(+), 1 deletion(-) diff --git a/src/Umbraco.Web.UI.Client/src/views/propertyeditors/nestedcontent/nestedcontent.controller.js b/src/Umbraco.Web.UI.Client/src/views/propertyeditors/nestedcontent/nestedcontent.controller.js index 0a44a9fcaa..7be141362e 100644 --- a/src/Umbraco.Web.UI.Client/src/views/propertyeditors/nestedcontent/nestedcontent.controller.js +++ b/src/Umbraco.Web.UI.Client/src/views/propertyeditors/nestedcontent/nestedcontent.controller.js @@ -37,6 +37,18 @@ }); }); + $scope.selectableDocTypesFor = function (config) { + // return all doctypes that are: + // 1. either already selected for this config, or + // 2. not selected in any other config + return _.filter($scope.model.docTypes, function (docType) { + return docType.alias === config.ncAlias || !_.find($scope.model.value, function(c) { + return docType.alias === c.ncAlias; + }); + }); + + } + if (!$scope.model.value) { $scope.model.value = []; $scope.add(); diff --git a/src/Umbraco.Web.UI.Client/src/views/propertyeditors/nestedcontent/nestedcontent.doctypepicker.html b/src/Umbraco.Web.UI.Client/src/views/propertyeditors/nestedcontent/nestedcontent.doctypepicker.html index 0617331682..e0a16d8687 100644 --- a/src/Umbraco.Web.UI.Client/src/views/propertyeditors/nestedcontent/nestedcontent.doctypepicker.html +++ b/src/Umbraco.Web.UI.Client/src/views/propertyeditors/nestedcontent/nestedcontent.doctypepicker.html @@ -22,7 +22,7 @@ From eda6e084a78f88afd53802bf42cad658f71e71e3 Mon Sep 17 00:00:00 2001 From: Stephan Date: Mon, 1 Oct 2018 14:37:40 +0200 Subject: [PATCH 06/98] Fix casing issue in member group service/repo --- .../Repositories/MemberGroupRepository.cs | 2 +- .../Services/MemberServiceTests.cs | 25 ++++++++++++++++++- 2 files changed, 25 insertions(+), 2 deletions(-) diff --git a/src/Umbraco.Core/Persistence/Repositories/MemberGroupRepository.cs b/src/Umbraco.Core/Persistence/Repositories/MemberGroupRepository.cs index 404c32640a..8b5dbb435e 100644 --- a/src/Umbraco.Core/Persistence/Repositories/MemberGroupRepository.cs +++ b/src/Umbraco.Core/Persistence/Repositories/MemberGroupRepository.cs @@ -284,7 +284,7 @@ namespace Umbraco.Core.Persistence.Repositories var nonAssignedRoles = roleNames.Except(assignedRoles, StringComparer.CurrentCultureIgnoreCase); foreach (var toAssign in nonAssignedRoles) { - var groupId = rolesForNames.First(x => x.Text == toAssign).NodeId; + var groupId = rolesForNames.First(x => x.Text.InvariantEquals(toAssign)).NodeId; Database.Insert(new Member2MemberGroupDto { Member = mId, MemberGroup = groupId }); } } diff --git a/src/Umbraco.Tests/Services/MemberServiceTests.cs b/src/Umbraco.Tests/Services/MemberServiceTests.cs index 4ba3866c64..3ee5a4804e 100644 --- a/src/Umbraco.Tests/Services/MemberServiceTests.cs +++ b/src/Umbraco.Tests/Services/MemberServiceTests.cs @@ -288,6 +288,29 @@ namespace Umbraco.Tests.Services Assert.AreEqual(2, membersInRole.Count()); } + [Test] + public void Associate_Members_To_Roles_With_Member_Id_Casing() + { + ServiceContext.MemberService.AddRole("MyTestRole1"); + + IMemberType memberType = MockedContentTypes.CreateSimpleMemberType(); + ServiceContext.MemberTypeService.Save(memberType); + var member1 = MockedMember.CreateSimpleMember(memberType, "test1", "test1@test.com", "pass", "test1"); + ServiceContext.MemberService.Save(member1); + var member2 = MockedMember.CreateSimpleMember(memberType, "test2", "test2@test.com", "pass", "test2"); + ServiceContext.MemberService.Save(member2); + + // temp make sure they exist + Assert.IsNotNull(ServiceContext.MemberService.GetById(member1.Id)); + Assert.IsNotNull(ServiceContext.MemberService.GetById(member2.Id)); + + ServiceContext.MemberService.AssignRoles(new[] { member1.Id, member2.Id }, new[] { "mytestrole1" }); + + var membersInRole = ServiceContext.MemberService.GetMembersInRole("MyTestRole1"); + + Assert.AreEqual(2, membersInRole.Count()); + } + [Test] public void Associate_Members_To_Roles_With_Member_Username() { @@ -1179,4 +1202,4 @@ namespace Umbraco.Tests.Services } } -} \ No newline at end of file +} From 66221364ca7fd489b28ab44135c8c9174cc072cf Mon Sep 17 00:00:00 2001 From: Anders Bjerner Date: Mon, 1 Oct 2018 21:21:17 +0200 Subject: [PATCH 07/98] Hide "Created Date" field when the media hasn't yet been created --- .../src/views/components/media/umb-media-node-info.html | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/Umbraco.Web.UI.Client/src/views/components/media/umb-media-node-info.html b/src/Umbraco.Web.UI.Client/src/views/components/media/umb-media-node-info.html index 19095acb90..7cfcb835a5 100644 --- a/src/Umbraco.Web.UI.Client/src/views/components/media/umb-media-node-info.html +++ b/src/Umbraco.Web.UI.Client/src/views/components/media/umb-media-node-info.html @@ -29,11 +29,11 @@ - + {{node.createDateFormatted}} by {{ node.owner.name }} - + {{node.updateDateFormatted}} @@ -47,7 +47,7 @@ - +
{{ node.id }}
{{ node.key }}
From 9c04abc5ad7eef49ac7b3d829083832f3284667b Mon Sep 17 00:00:00 2001 From: Anders Bjerner Date: Mon, 1 Oct 2018 21:40:24 +0200 Subject: [PATCH 08/98] Hide the "Links" box when there are no links --- .../src/views/components/content/umb-content-node-info.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Umbraco.Web.UI.Client/src/views/components/content/umb-content-node-info.html b/src/Umbraco.Web.UI.Client/src/views/components/content/umb-content-node-info.html index 0706e9596c..7085babf59 100644 --- a/src/Umbraco.Web.UI.Client/src/views/components/content/umb-content-node-info.html +++ b/src/Umbraco.Web.UI.Client/src/views/components/content/umb-content-node-info.html @@ -2,7 +2,7 @@
- +
From 0a245dda4358206df1d4da3c79541201eb21b888 Mon Sep 17 00:00:00 2001 From: Jan Skovgaard Date: Tue, 2 Oct 2018 19:54:12 +0200 Subject: [PATCH 19/98] Add an outer check to make sure the scope.includeSubFolders property is not undefined, which makes the media render in the view again --- .../components/umbmediagrid.directive.js | 20 ++++++++++++------- 1 file changed, 13 insertions(+), 7 deletions(-) diff --git a/src/Umbraco.Web.UI.Client/src/common/directives/components/umbmediagrid.directive.js b/src/Umbraco.Web.UI.Client/src/common/directives/components/umbmediagrid.directive.js index 9aa4965022..d31ef61150 100644 --- a/src/Umbraco.Web.UI.Client/src/common/directives/components/umbmediagrid.directive.js +++ b/src/Umbraco.Web.UI.Client/src/common/directives/components/umbmediagrid.directive.js @@ -125,13 +125,19 @@ Use this directive to generate a thumbnail grid of media items. i--; } - if (scope.includeSubFolders !== 'true') { - if (item.parentId !== parseInt(scope.currentFolderId)) { - scope.items.splice(i, 1); - i--; + + // If subfolder search is not enabled remove the media items that's not needed + // Make sure that includeSubFolder is not undefined since the directive is used + // in contexts where it should not be used. Currently only used when we trigger + // a media picker + if(scope.includeSubFolders !== undefined){ + if (scope.includeSubFolders !== 'true') { + if (item.parentId !== parseInt(scope.currentFolderId)) { + scope.items.splice(i, 1); + i--; + } } } - } @@ -152,7 +158,7 @@ Use this directive to generate a thumbnail grid of media items. } if (!item.isFolder) { - + // handle entity if(item.image) { item.thumbnail = mediaHelper.resolveFileFromEntity(item, true); @@ -161,7 +167,7 @@ Use this directive to generate a thumbnail grid of media items. } else { item.thumbnail = mediaHelper.resolveFile(item, true); item.image = mediaHelper.resolveFile(item, false); - + var fileProp = _.find(item.properties, function (v) { return (v.alias === "umbracoFile"); }); From a8df8f484ff7eb8e03584f3691bf9b9001ba9849 Mon Sep 17 00:00:00 2001 From: KimHolzmann Date: Wed, 3 Oct 2018 18:13:35 +0200 Subject: [PATCH 20/98] #3022 media uploader in rte doesn't select uploaded image (#3117) --- .../common/overlays/mediaPicker/mediapicker.controller.js | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/Umbraco.Web.UI.Client/src/views/common/overlays/mediaPicker/mediapicker.controller.js b/src/Umbraco.Web.UI.Client/src/views/common/overlays/mediaPicker/mediapicker.controller.js index 60c89197a9..7c43f5909f 100644 --- a/src/Umbraco.Web.UI.Client/src/views/common/overlays/mediaPicker/mediapicker.controller.js +++ b/src/Umbraco.Web.UI.Client/src/views/common/overlays/mediaPicker/mediapicker.controller.js @@ -237,7 +237,10 @@ angular.module("umbraco") $scope.onUploadComplete = function(files) { $scope.gotoFolder($scope.currentFolder).then(function() { if (files.length === 1 && $scope.model.selectedImages.length === 0) { - selectImage($scope.images[$scope.images.length - 1]); + var image = $scope.images[$scope.images.length - 1]; + $scope.target = image; + $scope.target.url = mediaHelper.resolveFile(image); + selectImage(image); } }); }; From c27b9d76dbb0c72a700a6af13f4b50c50994a4b8 Mon Sep 17 00:00:00 2001 From: Claus Date: Wed, 3 Oct 2018 08:09:39 +0200 Subject: [PATCH 21/98] fixes #3126 - If no property data is found for a specific version - a null exception is thrown. - Throwing an exception with a description instead of hitting a null exception. --- .../Repositories/ContentRepository.cs | 33 +++++++++++-------- 1 file changed, 20 insertions(+), 13 deletions(-) diff --git a/src/Umbraco.Core/Persistence/Repositories/ContentRepository.cs b/src/Umbraco.Core/Persistence/Repositories/ContentRepository.cs index 6c00964c15..4f19dc9241 100644 --- a/src/Umbraco.Core/Persistence/Repositories/ContentRepository.cs +++ b/src/Umbraco.Core/Persistence/Repositories/ContentRepository.cs @@ -134,7 +134,7 @@ namespace Umbraco.Core.Persistence.Repositories .InnerJoin(SqlSyntax) .On(SqlSyntax, left => left.NodeId, right => right.NodeId) .InnerJoin(SqlSyntax) - .On(SqlSyntax, left => left.NodeId, right => right.NodeId) + .On(SqlSyntax, left => left.NodeId, right => right.NodeId) .InnerJoin() .On(left => left.NodeId, right => right.ContentTypeId); //TODO: IF we want to enable querying on content type information this will need to be joined @@ -836,19 +836,19 @@ order by umbracoNode.{2}, umbracoNode.parentID, umbracoNode.sortOrder", } public int CountPublished(string contentTypeAlias = null) - { - if (contentTypeAlias.IsNullOrWhiteSpace()) - { + { + if (contentTypeAlias.IsNullOrWhiteSpace()) + { var sql = GetBaseQuery(true).Where(x => x.Trashed == false) - .Where(x => x.Published == true); - return Database.ExecuteScalar(sql); + .Where(x => x.Published == true); + return Database.ExecuteScalar(sql); } - else - { + else + { var sql = GetBaseQuery(true).Where(x => x.Trashed == false) - .Where(x => x.Published == true) - .Where(x => x.Alias == contentTypeAlias); - return Database.ExecuteScalar(sql); + .Where(x => x.Published == true) + .Where(x => x.Alias == contentTypeAlias); + return Database.ExecuteScalar(sql); } } @@ -1220,7 +1220,14 @@ ORDER BY cmsContentVersion.id DESC if (def.DocumentDto.TemplateId.HasValue) templates.TryGetValue(def.DocumentDto.TemplateId.Value, out template); // else null cc.Template = template; - cc.Properties = propertyData[cc.Version]; + if (propertyData.ContainsKey(cc.Version)) + { + cc.Properties = propertyData[cc.Version]; + } + else + { + throw new InvalidOperationException($"No property data found for version: '{cc.Version}'."); + } //on initial construction we don't want to have dirty properties tracked // http://issues.umbraco.org/issue/U4-1946 @@ -1307,4 +1314,4 @@ ORDER BY cmsContentVersion.id DESC } } } -} \ No newline at end of file +} From 9579b97dde0aca64f5aeaed76d291661bf54141c Mon Sep 17 00:00:00 2001 From: Claus Date: Wed, 3 Oct 2018 08:01:26 +0200 Subject: [PATCH 22/98] fixes #3124 - logging in BaseDataCreation. --- .../Persistence/DatabaseSchemaHelper.cs | 19 +++++++++++++++---- 1 file changed, 15 insertions(+), 4 deletions(-) diff --git a/src/Umbraco.Core/Persistence/DatabaseSchemaHelper.cs b/src/Umbraco.Core/Persistence/DatabaseSchemaHelper.cs index f03e751427..304cdc185f 100644 --- a/src/Umbraco.Core/Persistence/DatabaseSchemaHelper.cs +++ b/src/Umbraco.Core/Persistence/DatabaseSchemaHelper.cs @@ -117,6 +117,8 @@ namespace Umbraco.Core.Persistence var tableExist = TableExist(tableName); if (overwrite && tableExist) { + _logger.Info(string.Format("Table '{0}' already exists, but will be recreated", tableName)); + DropTable(tableName); tableExist = false; } @@ -169,13 +171,22 @@ namespace Umbraco.Core.Persistence _logger.Info(string.Format("Create Foreign Key sql {0}:\n {1}", createdFk, sql)); } - - transaction.Complete(); + if (overwrite) + { + _logger.Info(string.Format("Table '{0}' was recreated", tableName)); + } + else + { + _logger.Info(string.Format("New table '{0}' was created", tableName)); + } } } - - _logger.Info(string.Format("New table '{0}' was created", tableName)); + else + { + // The table exists and was not recreated/overwritten. + _logger.Info(string.Format("Table '{0}' already exists - no changes were made", tableName)); + } } public void DropTable() From bc081db9e6af1cb41b777755a4b9b8b93b0fa963 Mon Sep 17 00:00:00 2001 From: Anders Bjerner Date: Thu, 4 Oct 2018 08:16:11 +0200 Subject: [PATCH 23/98] Sentences should end with a period (#3144) --- src/Umbraco.Web.UI/umbraco/config/lang/da.xml | 2 +- src/Umbraco.Web.UI/umbraco/config/lang/en.xml | 4 ++-- src/Umbraco.Web.UI/umbraco/config/lang/en_us.xml | 4 ++-- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/Umbraco.Web.UI/umbraco/config/lang/da.xml b/src/Umbraco.Web.UI/umbraco/config/lang/da.xml index 8984ffa81a..71195be6f8 100644 --- a/src/Umbraco.Web.UI/umbraco/config/lang/da.xml +++ b/src/Umbraco.Web.UI/umbraco/config/lang/da.xml @@ -259,7 +259,7 @@ Slip filerne her... Link til medie eller klik her for at vælge filer - Du kan trække filer herind for at uploade + Du kan trække filer herind for at uploade. Tilladte filtyper er kun Kan ikke uploade denne fil, den har ikke en godkendt filtype Maks filstørrelse er diff --git a/src/Umbraco.Web.UI/umbraco/config/lang/en.xml b/src/Umbraco.Web.UI/umbraco/config/lang/en.xml index 057eb7dc9f..f12d509416 100644 --- a/src/Umbraco.Web.UI/umbraco/config/lang/en.xml +++ b/src/Umbraco.Web.UI/umbraco/config/lang/en.xml @@ -267,7 +267,7 @@ Drop your files here... Link to media or click here to choose files - You can drag files here to upload + You can drag files here to upload. Only allowed file types are Cannot upload this file, it does not have an approved file type Max file size is @@ -647,7 +647,7 @@ Permissions Scheduled Publishing Search - Sorry, we can not find what you are looking for + Sorry, we can not find what you are looking for. No items have been added Server Show 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 8a24c4a7c2..c6a6aadd77 100644 --- a/src/Umbraco.Web.UI/umbraco/config/lang/en_us.xml +++ b/src/Umbraco.Web.UI/umbraco/config/lang/en_us.xml @@ -268,7 +268,7 @@ Drop your files here... Link to media or click here to choose files - You can drag files here to upload + You can drag files here to upload. Only allowed file types are Cannot upload this file, it does not have an approved file type Max file size is @@ -647,7 +647,7 @@ Permissions Scheduled Publishing Search - Sorry, we can not find what you are looking for + Sorry, we can not find what you are looking for. No items have been added Server Show From deca5d7bdb056363175e6dd06e3415304a12d44b Mon Sep 17 00:00:00 2001 From: Jan Skovgaard Date: Wed, 3 Oct 2018 22:10:32 +0200 Subject: [PATCH 24/98] Refactor error handling to serve different error messages depending on the context. If we know that the id being moved is the same as the id we want to move it to then show a specific error message hinting the editor what's wrong and otherwise show the usual generic error message. --- .../src/common/resources/media.resource.js | 108 ++++++++++-------- 1 file changed, 60 insertions(+), 48 deletions(-) diff --git a/src/Umbraco.Web.UI.Client/src/common/resources/media.resource.js b/src/Umbraco.Web.UI.Client/src/common/resources/media.resource.js index 93a92db1ec..ca106cf65c 100644 --- a/src/Umbraco.Web.UI.Client/src/common/resources/media.resource.js +++ b/src/Umbraco.Web.UI.Client/src/common/resources/media.resource.js @@ -46,7 +46,7 @@ function mediaResource($q, $http, umbDataFormatter, umbRequestHelper) { * .then(function() { * $scope.complete = true; * }); - * + * * @param {Object} args arguments object * @param {Int} args.parentId the ID of the parent node * @param {Array} options.sortedIds array of node IDs as they should be sorted @@ -87,9 +87,9 @@ function mediaResource($q, $http, umbDataFormatter, umbRequestHelper) { * .then(function() { * alert("node was moved"); * }, function(err){ - * alert("node didnt move:" + err.data.Message); + * alert("node didnt move:" + err.data.Message); * }); - * + * * @param {Object} args arguments object * @param {Int} args.idd the ID of the node to move * @param {Int} args.parentId the ID of the parent node to move to @@ -109,11 +109,23 @@ function mediaResource($q, $http, umbDataFormatter, umbRequestHelper) { return umbRequestHelper.resourcePromise( $http.post(umbRequestHelper.getApiUrl("mediaApiBaseUrl", "PostMove"), - { - parentId: args.parentId, - id: args.id - }), - 'Failed to move media'); + { + parentId: args.parentId, + id: args.id + }), + { + error: function(data){ + var errorMsg = 'Failed to move media'; + + if(data.parentId === data.id){ + errorMsg = 'Media can\'t be moved into itself'; + } + + return { + errorMsg: errorMsg + }; + } + }); }, @@ -129,12 +141,12 @@ function mediaResource($q, $http, umbDataFormatter, umbRequestHelper) { *
           * mediaResource.getById(1234)
           *    .then(function(media) {
-          *        var myMedia = media; 
+          *        var myMedia = media;
           *        alert('its here!');
           *    });
-          * 
- * - * @param {Int} id id of media item to return + * + * + * @param {Int} id id of media item to return * @returns {Promise} resourcePromise object containing the media item. * */ @@ -163,9 +175,9 @@ function mediaResource($q, $http, umbDataFormatter, umbRequestHelper) { * .then(function() { * alert('its gone!'); * }); - * - * - * @param {Int} id id of media item to delete + * + * + * @param {Int} id id of media item to delete * @returns {Promise} resourcePromise object. * */ @@ -191,12 +203,12 @@ function mediaResource($q, $http, umbDataFormatter, umbRequestHelper) { *
           * mediaResource.getByIds( [1234,2526,28262])
           *    .then(function(mediaArray) {
-          *        var myDoc = contentArray; 
+          *        var myDoc = contentArray;
           *        alert('they are here!');
           *    });
-          * 
- * - * @param {Array} ids ids of media items to return as an array + * + * + * @param {Array} ids ids of media items to return as an array * @returns {Promise} resourcePromise object containing the media items array. * */ @@ -223,28 +235,28 @@ function mediaResource($q, $http, umbDataFormatter, umbRequestHelper) { * * @description * Returns a scaffold of an empty media item, given the id of the media item to place it underneath and the media type alias. - * + * * - Parent Id must be provided so umbraco knows where to store the media - * - Media Type alias must be provided so umbraco knows which properties to put on the media scaffold - * + * - Media Type alias must be provided so umbraco knows which properties to put on the media scaffold + * * The scaffold is used to build editors for media that has not yet been populated with data. - * + * * ##usage *
           * mediaResource.getScaffold(1234, 'folder')
           *    .then(function(scaffold) {
           *        var myDoc = scaffold;
-          *        myDoc.name = "My new media item"; 
+          *        myDoc.name = "My new media item";
           *
           *        mediaResource.save(myDoc, true)
           *            .then(function(media){
           *                alert("Retrieved, updated and saved again");
           *            });
           *    });
-          * 
- * + * + * * @param {Int} parentId id of media item to return - * @param {String} alias mediatype alias to base the scaffold on + * @param {String} alias mediatype alias to base the scaffold on * @returns {Promise} resourcePromise object containing the media scaffold. * */ @@ -283,11 +295,11 @@ function mediaResource($q, $http, umbDataFormatter, umbRequestHelper) { *
           * mediaResource.getChildren(1234, {pageSize: 10, pageNumber: 2})
           *    .then(function(contentArray) {
-          *        var children = contentArray; 
+          *        var children = contentArray;
           *        alert('they are here!');
           *    });
-          * 
- * + * + * * @param {Int} parentid id of content item to return children of * @param {Object} options optional options object * @param {Int} options.pageSize if paging data, number of nodes per page, default = 0 @@ -361,9 +373,9 @@ function mediaResource($q, $http, umbDataFormatter, umbRequestHelper) { * * @description * Saves changes made to a media item, if the media item is new, the isNew paramater must be passed to force creation - * if the media item needs to have files attached, they must be provided as the files param and passed separately - * - * + * if the media item needs to have files attached, they must be provided as the files param and passed separately + * + * * ##usage *
           * mediaResource.getById(1234)
@@ -374,11 +386,11 @@ function mediaResource($q, $http, umbDataFormatter, umbRequestHelper) {
           *                alert("Retrieved, updated and saved again");
           *            });
           *    });
-          * 
- * + * + * * @param {Object} media The media item object with changes applied - * @param {Bool} isNew set to true to create a new item or to update an existing - * @param {Array} files collection of files for the media item + * @param {Bool} isNew set to true to create a new item or to update an existing + * @param {Array} files collection of files for the media item * @returns {Promise} resourcePromise object containing the saved media item. * */ @@ -400,10 +412,10 @@ function mediaResource($q, $http, umbDataFormatter, umbRequestHelper) { * .then(function(folder) { * alert('New folder'); * }); - * + * * * @param {string} name Name of the folder to create - * @param {int} parentId Id of the media item to create the folder underneath + * @param {int} parentId Id of the media item to create the folder underneath * @returns {Promise} resourcePromise object. * */ @@ -427,18 +439,18 @@ function mediaResource($q, $http, umbDataFormatter, umbRequestHelper) { * Retrieves all media children with types used as folders. * Uses the convention of looking for media items with mediaTypes ending in * *Folder so will match "Folder", "bannerFolder", "secureFolder" etc, - * + * * NOTE: This will return a max of 500 folders, if more is required it needs to be paged - * + * * ##usage *
           * mediaResource.getChildFolders(1234)
           *    .then(function(data) {
           *        alert('folders');
           *    });
-          * 
+ * * - * @param {int} parentId Id of the media item to query for child folders + * @param {int} parentId Id of the media item to query for child folders * @returns {Promise} resourcePromise object. * */ @@ -473,8 +485,8 @@ function mediaResource($q, $http, umbDataFormatter, umbRequestHelper) { * .then(function() { * alert('its empty!'); * }); - * - * + * + * * @returns {Promise} resourcePromise object. * */ @@ -501,8 +513,8 @@ function mediaResource($q, $http, umbDataFormatter, umbRequestHelper) { * .then(function(searchResult) { * alert('it's here!'); * }); - * - * + * + * * @param {string} query The search query * @param {int} pageNumber The page number * @param {int} pageSize The number of media items on a page @@ -513,7 +525,7 @@ function mediaResource($q, $http, umbDataFormatter, umbRequestHelper) { search: function (query, pageNumber, pageSize, searchFrom) { var args = [ - { "query": query }, + { "query": query }, { "pageNumber": pageNumber }, { "pageSize": pageSize }, { "searchFrom": searchFrom } From 7355ba4b235a2ec9ad3cd61262a56673e5cf9ac3 Mon Sep 17 00:00:00 2001 From: Bjarne Fyrstenborg Date: Thu, 4 Oct 2018 08:36:21 +0200 Subject: [PATCH 25/98] Add option to rename colorpicker labels (#3121) --- .../src/less/property-editors.less | 19 +++++++++++-------- .../colorpicker/colorpicker.prevalues.html | 12 ++++++++---- .../multicolorpicker.controller.js | 6 ++++-- 3 files changed, 23 insertions(+), 14 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 1c647eb1d0..d14a1abae9 100644 --- a/src/Umbraco.Web.UI.Client/src/less/property-editors.less +++ b/src/Umbraco.Web.UI.Client/src/less/property-editors.less @@ -144,11 +144,14 @@ div.umb-codeeditor .umb-btn-toolbar { /* pre-value editor */ .control-group.color-picker-preval { .thumbnail { - width: 36px; + width: 34px; + height: 34px; min-width: auto; border: none; cursor: move; border-radius: 3px; + margin-top: auto; + margin-bottom: auto; } .handle { @@ -160,19 +163,19 @@ div.umb-codeeditor .umb-btn-toolbar { div.color-picker-prediv { display: inline-flex; align-items: center; - max-width: 85%; + max-width: 100%; + flex: 1; pre { display: inline-flex; font-family: monospace; - margin-right: 10px; - margin-left: 10px; + margin-left: 15px; + margin-right: 15px; white-space: nowrap; overflow: hidden; margin-bottom: 0; vertical-align: middle; - padding-top: 7px; - padding-bottom: 7px; + padding: 6px 10px; background: #f7f7f7; flex: 0 0 auto; } @@ -201,11 +204,11 @@ div.umb-codeeditor .umb-btn-toolbar { label { border: 1px solid #fff; - padding: 7px 10px; + padding: 6px 10px; font-family: monospace; border: 1px solid #dfdfe1; background: #f7f7f7; - margin: 0 15px 0 0; + margin: 0 15px 0 3px; border-radius: 3px; } } diff --git a/src/Umbraco.Web.UI.Client/src/views/propertyeditors/colorpicker/colorpicker.prevalues.html b/src/Umbraco.Web.UI.Client/src/views/propertyeditors/colorpicker/colorpicker.prevalues.html index 3d9e2efdf8..262c8593ec 100644 --- a/src/Umbraco.Web.UI.Client/src/views/propertyeditors/colorpicker/colorpicker.prevalues.html +++ b/src/Umbraco.Web.UI.Client/src/views/propertyeditors/colorpicker/colorpicker.prevalues.html @@ -3,18 +3,22 @@
- +
-
+
-
-
#{{item.value}}
{{item.label}}
+
+
+
#{{item.value}}
+ + +
Remove diff --git a/src/Umbraco.Web.UI.Client/src/views/propertyeditors/colorpicker/multicolorpicker.controller.js b/src/Umbraco.Web.UI.Client/src/views/propertyeditors/colorpicker/multicolorpicker.controller.js index 7ae728a85a..287a0f48fc 100644 --- a/src/Umbraco.Web.UI.Client/src/views/propertyeditors/colorpicker/multicolorpicker.controller.js +++ b/src/Umbraco.Web.UI.Client/src/views/propertyeditors/colorpicker/multicolorpicker.controller.js @@ -5,8 +5,9 @@ var defaultLabel = null; $scope.newColor = defaultColor; - $scope.newLavel = defaultLabel; + $scope.newLabel = defaultLabel; $scope.hasError = false; + $scope.focusOnNew = false; $scope.labels = {}; @@ -104,7 +105,6 @@ }; $scope.add = function (evt) { - evt.preventDefault(); if ($scope.newColor) { @@ -117,7 +117,9 @@ value: $scope.newColor, label: newLabel }); + $scope.newLabel = ""; $scope.hasError = false; + $scope.focusOnNew = true; return; } From 9d36ee6bd8a87e49704b23995c34e81384a7414e Mon Sep 17 00:00:00 2001 From: Dave Woestenborghs Date: Thu, 4 Oct 2018 15:49:32 +0200 Subject: [PATCH 26/98] #3141 fixed broken Do something else button --- .../src/common/services/navigation.service.js | 1 - 1 file changed, 1 deletion(-) diff --git a/src/Umbraco.Web.UI.Client/src/common/services/navigation.service.js b/src/Umbraco.Web.UI.Client/src/common/services/navigation.service.js index da2fd243e6..8fb7137e9a 100644 --- a/src/Umbraco.Web.UI.Client/src/common/services/navigation.service.js +++ b/src/Umbraco.Web.UI.Client/src/common/services/navigation.service.js @@ -73,7 +73,6 @@ function navigationService($rootScope, $routeParams, $log, $location, $q, $timeo appState.setSectionState("showSearchResults", false); appState.setGlobalState("stickyNavigation", false); appState.setGlobalState("showTray", false); - appState.setMenuState("currentNode", null); if (appState.getGlobalState("isTablet") === true) { appState.setGlobalState("showNavigation", false); From b6c32978848e7c3ef3f43d1689ea03a390e19c96 Mon Sep 17 00:00:00 2001 From: Jannik Anker Date: Thu, 4 Oct 2018 17:16:57 +0200 Subject: [PATCH 27/98] Lecoati CSS reference removed (issue #3147) ApprovedColorPickerController had a reference for no apparent reason. --- .../src/views/common/dialogs/approvedcolorpicker.controller.js | 1 - 1 file changed, 1 deletion(-) diff --git a/src/Umbraco.Web.UI.Client/src/views/common/dialogs/approvedcolorpicker.controller.js b/src/Umbraco.Web.UI.Client/src/views/common/dialogs/approvedcolorpicker.controller.js index 5e5363ae6c..7d9a0d3410 100644 --- a/src/Umbraco.Web.UI.Client/src/views/common/dialogs/approvedcolorpicker.controller.js +++ b/src/Umbraco.Web.UI.Client/src/views/common/dialogs/approvedcolorpicker.controller.js @@ -19,7 +19,6 @@ angular.module("umbraco") $scope.classes.splice(0, 0, "noclass"); }) - assetsService.loadCss("/App_Plugins/Lecoati.uSky.Grid/lib/uSky.Grid.ApprovedColorPicker.css", $scope); assetsService.loadCss(cssPath, $scope); }); }); From e7d7de627307f9e0d3b5e00908c017f42057cee4 Mon Sep 17 00:00:00 2001 From: Rahul Arulkumaran Date: Fri, 5 Oct 2018 11:43:41 +0530 Subject: [PATCH 28/98] Update LICENSE.md --- LICENSE.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/LICENSE.md b/LICENSE.md index c5560c3ce1..fa83dba963 100644 --- a/LICENSE.md +++ b/LICENSE.md @@ -1,6 +1,6 @@ # The MIT License (MIT) # -Copyright (c) 2013 Umbraco +Copyright (c) 2013-present Umbraco Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: From 774f1d706c886f071df2f6c1e284911e2ad38e7c Mon Sep 17 00:00:00 2001 From: Poornima Nayar Date: Thu, 4 Oct 2018 16:21:11 +0100 Subject: [PATCH 29/98] Fixed issue with actions dropdown menu being partially visible. --- src/Umbraco.Web.UI.Client/src/less/panel.less | 1 - 1 file changed, 1 deletion(-) diff --git a/src/Umbraco.Web.UI.Client/src/less/panel.less b/src/Umbraco.Web.UI.Client/src/less/panel.less index 51a2504363..4e26ab73b6 100644 --- a/src/Umbraco.Web.UI.Client/src/less/panel.less +++ b/src/Umbraco.Web.UI.Client/src/less/panel.less @@ -368,7 +368,6 @@ flex-direction: column; height: 99px; padding: 0 20px; - overflow-y: hidden; } .umb-panel-header-content { From 0f3da1ae1446c9e1317b2e8888618a1f54710fec Mon Sep 17 00:00:00 2001 From: Jan Skovgaard Date: Mon, 8 Oct 2018 08:38:24 +0200 Subject: [PATCH 30/98] #3159 - Add border around the colors from the approved color picker (#3161) --- .../src/less/components/umb-color-swatches.less | 5 +++-- .../src/views/propertyeditors/colorpicker/colorpicker.html | 1 + 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/src/Umbraco.Web.UI.Client/src/less/components/umb-color-swatches.less b/src/Umbraco.Web.UI.Client/src/less/components/umb-color-swatches.less index df80aef2ce..d8e67444a1 100644 --- a/src/Umbraco.Web.UI.Client/src/less/components/umb-color-swatches.less +++ b/src/Umbraco.Web.UI.Client/src/less/components/umb-color-swatches.less @@ -3,7 +3,7 @@ flex-flow: row wrap; .umb-color-box { - border: none; + border: 1px solid @gray-8; color: white; cursor: pointer; padding: 1px; @@ -69,7 +69,8 @@ margin-right: -1px; text-indent: 0; text-align: left; - border: 1px solid @gray-8; + border-top: 1px solid @gray-8; + border-bottom: 1px solid @gray-8; border-bottom-left-radius: 3px; border-bottom-right-radius: 3px; overflow: hidden; diff --git a/src/Umbraco.Web.UI.Client/src/views/propertyeditors/colorpicker/colorpicker.html b/src/Umbraco.Web.UI.Client/src/views/propertyeditors/colorpicker/colorpicker.html index ccea7519ac..b09d73cee2 100644 --- a/src/Umbraco.Web.UI.Client/src/views/propertyeditors/colorpicker/colorpicker.html +++ b/src/Umbraco.Web.UI.Client/src/views/propertyeditors/colorpicker/colorpicker.html @@ -1,5 +1,6 @@ 
+
You haven't defined any colors
From a9756e065cb27d06a72124b1ed1c9f98b1423b70 Mon Sep 17 00:00:00 2001 From: Sebastiaan Janssen Date: Mon, 8 Oct 2018 13:07:30 +0200 Subject: [PATCH 31/98] Don't show toggles to create templates when that feature is disabled. Also default the toggle to false when the feature is disabled. --- .../src/views/documenttypes/create.controller.js | 4 ++-- .../src/views/documenttypes/create.html | 16 ++++++++++------ 2 files changed, 12 insertions(+), 8 deletions(-) diff --git a/src/Umbraco.Web.UI.Client/src/views/documenttypes/create.controller.js b/src/Umbraco.Web.UI.Client/src/views/documenttypes/create.controller.js index 551a5d6ec1..b05cb52fe9 100644 --- a/src/Umbraco.Web.UI.Client/src/views/documenttypes/create.controller.js +++ b/src/Umbraco.Web.UI.Client/src/views/documenttypes/create.controller.js @@ -27,8 +27,8 @@ function DocumentTypesCreateController($scope, $location, navigationService, con $scope.showCreateDocTypeCollection = function () { $scope.model.creatingDoctypeCollection = true; - $scope.model.collectionCreateTemplate = true; - $scope.model.collectionItemCreateTemplate = true; + $scope.model.collectionCreateTemplate = !$scope.model.disableTemplates; + $scope.model.collectionItemCreateTemplate = !$scope.model.disableTemplates; }; $scope.createContainer = function () { diff --git a/src/Umbraco.Web.UI.Client/src/views/documenttypes/create.html b/src/Umbraco.Web.UI.Client/src/views/documenttypes/create.html index 98f9b23b64..3519195848 100644 --- a/src/Umbraco.Web.UI.Client/src/views/documenttypes/create.html +++ b/src/Umbraco.Web.UI.Client/src/views/documenttypes/create.html @@ -19,8 +19,8 @@ - - Document type> + + Document type> @@ -80,14 +80,18 @@ - - + + + + - - + + + + From 4d7a36e017772a3d9fd76a69ec7a3e5db24319d6 Mon Sep 17 00:00:00 2001 From: KimHolzmann Date: Mon, 8 Oct 2018 14:04:52 +0200 Subject: [PATCH 32/98] #3001 Styles cannot be saved - Not sure if oldName is legacy (#3123) --- .../WebServices/SaveFileController.cs | 50 +++++++++++-------- .../stylesheet/editstylesheet.aspx.cs | 4 +- 2 files changed, 32 insertions(+), 22 deletions(-) diff --git a/src/Umbraco.Web/WebServices/SaveFileController.cs b/src/Umbraco.Web/WebServices/SaveFileController.cs index fe93fb1e06..5f2fcaeb34 100644 --- a/src/Umbraco.Web/WebServices/SaveFileController.cs +++ b/src/Umbraco.Web/WebServices/SaveFileController.cs @@ -39,13 +39,13 @@ namespace Umbraco.Web.WebServices [HttpPost] public JsonResult SavePartialViewMacro(string filename, string oldName, string contents) { - var svce = (FileService) Services.FileService; + var svce = (FileService)Services.FileService; return SavePartialView(svce, filename, oldName, contents, "MacroPartials/", (s, n) => s.GetPartialViewMacro(n), - (s, v) => s.ValidatePartialViewMacro((PartialView) v), + (s, v) => s.ValidatePartialViewMacro((PartialView)v), (s, v) => s.SavePartialViewMacro(v)); } @@ -59,13 +59,13 @@ namespace Umbraco.Web.WebServices [HttpPost] public JsonResult SavePartialView(string filename, string oldName, string contents) { - var svce = (FileService) Services.FileService; + var svce = (FileService)Services.FileService; return SavePartialView(svce, filename, oldName, contents, "Partials/", (s, n) => s.GetPartialView(n), - (s, v) => s.ValidatePartialView((PartialView) v), + (s, v) => s.ValidatePartialView((PartialView)v), (s, v) => s.SavePartialView(v)); } @@ -77,9 +77,7 @@ namespace Umbraco.Web.WebServices Func> save) { // sanitize input - partial view names have an extension - filename = filename - .Replace('\\', '/') - .TrimStart('/'); + filename = CleanFilename(filename); // sharing the editor with partial views & partial view macros, // using path prefix to differenciate, @@ -98,7 +96,7 @@ namespace Umbraco.Web.WebServices oldname = oldname.TrimStart(pathPrefix); } - var currentView = oldname.IsNullOrWhiteSpace() + var currentView = oldname.IsNullOrWhiteSpace() ? get(svce, filename) : get(svce, oldname); @@ -108,7 +106,7 @@ namespace Umbraco.Web.WebServices currentView.Path = filename; currentView.Content = contents; - + Attempt attempt; @@ -166,7 +164,7 @@ namespace Umbraco.Web.WebServices if (Math.Max(t.MasterTemplate, 0) != Math.Max(masterTemplateId, 0)) { t.MasterTemplate = Math.Max(masterTemplateId, 0); - pathChanged = true; + pathChanged = true; } } catch (ArgumentException ex) @@ -206,11 +204,9 @@ namespace Umbraco.Web.WebServices public JsonResult SaveScript(string filename, string oldName, string contents) { // sanitize input - script names have an extension - filename = filename - .Replace('\\', '/') - .TrimStart('/'); + filename = CleanFilename(filename); - var svce = (FileService) Services.FileService; + var svce = (FileService)Services.FileService; var script = svce.GetScriptByName(oldName); if (script == null) script = new Script(filename); @@ -223,7 +219,7 @@ namespace Umbraco.Web.WebServices if (svce.ValidateScript(script) == false) return Failed(ui.Text("speechBubbles", "scriptErrorText"), ui.Text("speechBubbles", "scriptErrorHeader"), new FileSecurityException("File '" + filename + "' is not a valid script file.")); - + svce.SaveScript(script); } catch (Exception e) @@ -245,12 +241,18 @@ namespace Umbraco.Web.WebServices public JsonResult SaveStylesheet(string filename, string oldName, string contents) { // sanitize input - stylesheet names have no extension - filename = filename - .Replace('\\', '/') - .TrimStart('/') - .EnsureEndsWith(".css"); + var svce = (FileService)Services.FileService; + + filename = CleanFilename(filename); + oldName = CleanFilename(oldName); + + if (filename != oldName) + { + var stylesheetExists = svce.GetStylesheetByName(filename); + if (stylesheetExists != null) + return Failed(ui.Text("speechBubbles", "cssErrorText"), "A file named '" + filename + ".css' already exists."); + } - var svce = (FileService) Services.FileService; var stylesheet = svce.GetStylesheetByName(oldName); if (stylesheet == null) stylesheet = new Stylesheet(filename); @@ -281,6 +283,14 @@ namespace Umbraco.Web.WebServices }); } + private static string CleanFilename(string filename) + { + return filename + .Replace('\\', '/') + .TrimStart('/') + .EnsureEndsWith(".css"); + } + /// /// Returns a successful message /// diff --git a/src/Umbraco.Web/umbraco.presentation/umbraco/settings/stylesheet/editstylesheet.aspx.cs b/src/Umbraco.Web/umbraco.presentation/umbraco/settings/stylesheet/editstylesheet.aspx.cs index 63dec9111a..b9a62fde8f 100644 --- a/src/Umbraco.Web/umbraco.presentation/umbraco/settings/stylesheet/editstylesheet.aspx.cs +++ b/src/Umbraco.Web/umbraco.presentation/umbraco/settings/stylesheet/editstylesheet.aspx.cs @@ -63,7 +63,7 @@ namespace umbraco.cms.presentation.settings.stylesheet TreeSyncPath = DeepLink.GetTreePathFromFilePath(filename).TrimEnd(".css"); // name derives from path, without the .css extension, clean for xss - NameTxt.Text = stylesheet.Path.TrimEnd(".css").CleanForXss('\\', '/'); + NameTxt.Text = stylesheet.Path.TrimEnd(".css").CleanForXss('\\', '/').Replace("\\", "/"); if (IsPostBack == false) { @@ -154,4 +154,4 @@ namespace umbraco.cms.presentation.settings.stylesheet protected global::umbraco.uicontrols.CodeArea editorSource; } -} \ No newline at end of file +} From a3cf1d7d582d6be71fc1c0fb11f54a73c651a43f Mon Sep 17 00:00:00 2001 From: Kim Holzmann Date: Thu, 4 Oct 2018 08:25:51 +0200 Subject: [PATCH 33/98] #3138 - Can add a null item to the grid Don't perform submit function if selectedItem is undefined --- .../src/views/propertyeditors/grid/grid.controller.js | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/src/Umbraco.Web.UI.Client/src/views/propertyeditors/grid/grid.controller.js b/src/Umbraco.Web.UI.Client/src/views/propertyeditors/grid/grid.controller.js index dbfbdbdcad..5e08c5e6b4 100644 --- a/src/Umbraco.Web.UI.Client/src/views/propertyeditors/grid/grid.controller.js +++ b/src/Umbraco.Web.UI.Client/src/views/propertyeditors/grid/grid.controller.js @@ -281,10 +281,12 @@ angular.module("umbraco") availableItems: area.$allowedEditors, event: event, show: true, - submit: function(model) { - $scope.addControl(model.selectedItem, area, index); - $scope.editorOverlay.show = false; - $scope.editorOverlay = null; + submit: function (model) { + if (model.selectedItem) { + $scope.addControl(model.selectedItem, area, index); + $scope.editorOverlay.show = false; + $scope.editorOverlay = null; + } } }; }; From b820baf64350c31808922223cd58f714d965a713 Mon Sep 17 00:00:00 2001 From: Kenn Jacobsen Date: Mon, 8 Oct 2018 14:27:18 +0200 Subject: [PATCH 34/98] Whe moving an item, make sure the current user is registered in Audit instead of the default user (#3150) --- src/Umbraco.Web/Editors/ContentController.cs | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/Umbraco.Web/Editors/ContentController.cs b/src/Umbraco.Web/Editors/ContentController.cs index 1938ac16c2..1a1957cc28 100644 --- a/src/Umbraco.Web/Editors/ContentController.cs +++ b/src/Umbraco.Web/Editors/ContentController.cs @@ -546,9 +546,9 @@ namespace Umbraco.Web.Editors EnsureUniqueName(name, content, "name"); - var blueprint = Services.ContentService.CreateContentFromBlueprint(content, name, Security.GetUserId()); + var blueprint = Services.ContentService.CreateContentFromBlueprint(content, name, Security.CurrentUser.Id); - Services.ContentService.SaveBlueprint(blueprint, Security.GetUserId()); + Services.ContentService.SaveBlueprint(blueprint, Security.CurrentUser.Id); var notificationModel = new SimpleNotificationModel(); notificationModel.AddSuccessNotification( @@ -755,7 +755,7 @@ namespace Umbraco.Web.Editors return HandleContentNotFound(id, false); } - var publishResult = Services.ContentService.PublishWithStatus(foundContent, Security.GetUserId()); + var publishResult = Services.ContentService.PublishWithStatus(foundContent, Security.CurrentUser.Id); if (publishResult.Success == false) { var notificationModel = new SimpleNotificationModel(); @@ -808,7 +808,7 @@ namespace Umbraco.Web.Editors //if the current item is in the recycle bin if (foundContent.IsInRecycleBin() == false) { - var moveResult = Services.ContentService.WithResult().MoveToRecycleBin(foundContent, Security.GetUserId()); + var moveResult = Services.ContentService.WithResult().MoveToRecycleBin(foundContent, Security.CurrentUser.Id); if (moveResult == false) { //returning an object of INotificationModel will ensure that any pending @@ -818,7 +818,7 @@ namespace Umbraco.Web.Editors } else { - var deleteResult = Services.ContentService.WithResult().Delete(foundContent, Security.GetUserId()); + var deleteResult = Services.ContentService.WithResult().Delete(foundContent, Security.CurrentUser.Id); if (deleteResult == false) { //returning an object of INotificationModel will ensure that any pending @@ -895,7 +895,7 @@ namespace Umbraco.Web.Editors { var toMove = ValidateMoveOrCopy(move); - Services.ContentService.Move(toMove, move.ParentId); + Services.ContentService.Move(toMove, move.ParentId, Security.CurrentUser.Id); var response = Request.CreateResponse(HttpStatusCode.OK); response.Content = new StringContent(toMove.Path, Encoding.UTF8, "application/json"); From 2e135d2006212df799765552bc0e916b9711cee9 Mon Sep 17 00:00:00 2001 From: Kenn Jacobsen Date: Thu, 4 Oct 2018 20:27:06 +0200 Subject: [PATCH 35/98] Register an audit on the parent node when sorting child nodes. --- src/Umbraco.Core/Services/ContentService.cs | 13 ++++++++----- src/Umbraco.Web.UI/umbraco/config/lang/da.xml | 2 ++ src/Umbraco.Web.UI/umbraco/config/lang/en.xml | 2 ++ src/Umbraco.Web.UI/umbraco/config/lang/en_us.xml | 2 ++ src/Umbraco.Web/Editors/ContentController.cs | 2 +- 5 files changed, 15 insertions(+), 6 deletions(-) diff --git a/src/Umbraco.Core/Services/ContentService.cs b/src/Umbraco.Core/Services/ContentService.cs index 2f8b9c8340..9b0de40090 100644 --- a/src/Umbraco.Core/Services/ContentService.cs +++ b/src/Umbraco.Core/Services/ContentService.cs @@ -2060,12 +2060,15 @@ namespace Umbraco.Core.Services using (new WriteLock(Locker)) { var allContent = GetByIds(ids).ToDictionary(x => x.Id, x => x); - var items = ids.Select(x => allContent[x]); + if (allContent.Any() == false) + { + return false; + } + var items = ids.Select(x => allContent[x]).ToArray(); using (var uow = UowProvider.GetUnitOfWork()) { - var asArray = items.ToArray(); - var saveEventArgs = new SaveEventArgs(asArray); + var saveEventArgs = new SaveEventArgs(items); if (raiseEvents && uow.Events.DispatchCancelable(Saving, this, saveEventArgs, "Saving")) { uow.Commit(); @@ -2075,7 +2078,7 @@ namespace Umbraco.Core.Services var repository = RepositoryFactory.CreateContentRepository(uow); var i = 0; - foreach (var content in asArray) + foreach (var content in items) { //If the current sort order equals that of the content //we don't need to update it, so just increment the sort order @@ -2122,7 +2125,7 @@ namespace Umbraco.Core.Services _publishingStrategy.PublishingFinalized(uow, shouldBePublished, false); } - Audit(uow, AuditType.Sort, "Sorting content performed by user", userId, 0); + Audit(uow, AuditType.Sort, "Sort child items performed by user", userId, items.First().ParentId); uow.Commit(); } } diff --git a/src/Umbraco.Web.UI/umbraco/config/lang/da.xml b/src/Umbraco.Web.UI/umbraco/config/lang/da.xml index 71195be6f8..0e9fc09bcd 100644 --- a/src/Umbraco.Web.UI/umbraco/config/lang/da.xml +++ b/src/Umbraco.Web.UI/umbraco/config/lang/da.xml @@ -147,6 +147,7 @@ Brugeren har tilbagerullet indholdet til en tidligere tilstand Brugeren har sendt indholdet til udgivelse Brugeren har sendt indholdet til oversættelse + Brugeren har sorteret de underliggende sider Kopieret Udgivet Flyttet @@ -156,6 +157,7 @@ Indhold tilbagerullet Sendt til udgivelse Sendt til oversættelse + Sorteret For at skifte det valgte indholds dokumenttype, skal du først vælge en ny dokumenttype, som er gyldig på denne placering. diff --git a/src/Umbraco.Web.UI/umbraco/config/lang/en.xml b/src/Umbraco.Web.UI/umbraco/config/lang/en.xml index f12d509416..477bce0931 100644 --- a/src/Umbraco.Web.UI/umbraco/config/lang/en.xml +++ b/src/Umbraco.Web.UI/umbraco/config/lang/en.xml @@ -153,6 +153,7 @@ Content rollback performed by user Content Send To Publish performed by user Content Send To Translation performed by user + Sort child items performed by user Copy Publish Move @@ -162,6 +163,7 @@ Rollback Send To Publish Send To Translation + Sort To change the document type for the selected content, first select from the list of valid types for this location. 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 c6a6aadd77..b1fa2b84b3 100644 --- a/src/Umbraco.Web.UI/umbraco/config/lang/en_us.xml +++ b/src/Umbraco.Web.UI/umbraco/config/lang/en_us.xml @@ -153,6 +153,7 @@ Content rollback performed by user Content Send To Publish performed by user Content Send To Translation performed by user + Sort child items performed by user Copy Publish Move @@ -162,6 +163,7 @@ Rollback Send To Publish Send To Translation + Sort diff --git a/src/Umbraco.Web/Editors/ContentController.cs b/src/Umbraco.Web/Editors/ContentController.cs index 1a1957cc28..6268759e29 100644 --- a/src/Umbraco.Web/Editors/ContentController.cs +++ b/src/Umbraco.Web/Editors/ContentController.cs @@ -871,7 +871,7 @@ namespace Umbraco.Web.Editors var contentService = Services.ContentService; // Save content with new sort order and update content xml in db accordingly - if (contentService.Sort(sorted.IdSortOrder) == false) + if (contentService.Sort(sorted.IdSortOrder, Security.CurrentUser.Id) == false) { LogHelper.Warn("Content sorting failed, this was probably caused by an event being cancelled"); return Request.CreateValidationErrorResponse("Content sorting failed, this was probably caused by an event being cancelled"); From 3977d24eb2c8583d3ac2499a582c6d0d9f394412 Mon Sep 17 00:00:00 2001 From: Poornima Nayar Date: Mon, 8 Oct 2018 14:29:09 +0100 Subject: [PATCH 36/98] Button styling on inactive user profile & clean up user view (#3170) --- src/Umbraco.Web.UI.Client/src/less/belle.less | 1 + .../components/users/umb-user-details.less | 122 +++++++++++++++++ .../src/views/users/user.html | 4 +- .../src/views/users/views/user/details.html | 123 +++++++++--------- 4 files changed, 187 insertions(+), 63 deletions(-) create mode 100644 src/Umbraco.Web.UI.Client/src/less/components/users/umb-user-details.less diff --git a/src/Umbraco.Web.UI.Client/src/less/belle.less b/src/Umbraco.Web.UI.Client/src/less/belle.less index 2eaabe7842..eaf0b60707 100644 --- a/src/Umbraco.Web.UI.Client/src/less/belle.less +++ b/src/Umbraco.Web.UI.Client/src/less/belle.less @@ -146,6 +146,7 @@ @import "components/umb-mini-editor.less"; @import "components/users/umb-user-cards.less"; +@import "components/users/umb-user-details.less"; @import "components/users/umb-user-group-picker-list.less"; @import "components/users/umb-user-group-preview.less"; @import "components/users/umb-user-preview.less"; diff --git a/src/Umbraco.Web.UI.Client/src/less/components/users/umb-user-details.less b/src/Umbraco.Web.UI.Client/src/less/components/users/umb-user-details.less new file mode 100644 index 0000000000..837506f312 --- /dev/null +++ b/src/Umbraco.Web.UI.Client/src/less/components/users/umb-user-details.less @@ -0,0 +1,122 @@ +.umb-user-details-avtar { + margin-bottom: 20px; + padding-bottom: 20px; + border-bottom: 1px solid #d8d7d9; +} + +div.umb-user-details-actions > div { + margin-bottom: 20px; +} + +.umb-user-details-actions .umb-button { + margin-bottom: 20px; +} + +.umb-user-details-view-title { + font-size: 20px; + font-weight: bold; + color: @black; + margin-bottom: 30px; +} + +.umb-user-details-view-wrapper { + padding: 20px 60px; +} + +@media (max-width: 768px) { + + .umb-user-details-view-wrapper { + padding: 0; + } +} + +.umb-user-details-section { + margin-bottom: 40px; +} +.umb-user-details-details { + display: flex; +} + +a.umb-user-details-details__back-link { + font-weight: bold; + color: @black; +} + +.umb-user-details-details__back-link:hover { + color: @gray-4; + text-decoration: none; +} + + +@sidebarwidth: 350px; // Width of sidebar. Ugly hack because of old version of Less + +.umb-user-details-details__main-content { + flex: 1 1 auto; + margin-right: 30px; + width: calc(~'100%' - ~'@{sidebarwidth}' - ~'30px'); // Make sure that the main content area doesn't gets affected by inline styling +} + +.umb-user-details-details__main-content .umb-node-preview-add { + max-width: 100%; +} + + +.umb-user-details-details__sidebar { + flex: 0 0 @sidebarwidth; +} + +@media (max-width: 768px) { + + .umb-user-details-details { + flex-direction: column; + } + + .umb-user-details-details__main-content { + flex: 1 1 auto; + width: 100%; + margin-bottom: 30px; + margin-right: 0; + } + + .umb-user-details-details__sidebar { + flex: 1 1 auto; + width: 100%; + } +} + +.umb-user-details-details__section { + background: @gray-10; + padding: 20px; + margin-bottom: 20px; + border-radius: 3px; + border: 1px solid @gray-8; +} + +.umb-user-details-details__section-title { + font-size: 17px; + font-weight: bold; + color: @black; + margin-top: 0; + margin-bottom: 15px; +} + +.umb-user-details-details__section-description { + font-size: 12px; + line-height: 1.6em; + margin-bottom: 15px; +} + +.umb-user-details-details__information-item { + margin-bottom: 10px; + font-size: 13px; +} + +.umb-user-details-details__information-item-label { + color: @black; + font-weight: bold; +} + +.umb-user-details-details__information-item-content { + word-break: break-word; +} + diff --git a/src/Umbraco.Web.UI.Client/src/views/users/user.html b/src/Umbraco.Web.UI.Client/src/views/users/user.html index 32c1c3d641..3e7b2b8d8d 100644 --- a/src/Umbraco.Web.UI.Client/src/views/users/user.html +++ b/src/Umbraco.Web.UI.Client/src/views/users/user.html @@ -15,7 +15,7 @@ -
+
-
\ No newline at end of file +
diff --git a/src/Umbraco.Web.UI.Client/src/views/users/views/user/details.html b/src/Umbraco.Web.UI.Client/src/views/users/views/user/details.html index 7c93f1fd84..15a75c30b2 100644 --- a/src/Umbraco.Web.UI.Client/src/views/users/views/user/details.html +++ b/src/Umbraco.Web.UI.Client/src/views/users/views/user/details.html @@ -1,6 +1,6 @@ -
+
-
+
@@ -95,8 +95,8 @@ Add @@ -121,9 +121,9 @@ Add @@ -165,12 +165,12 @@
-
+
-
+
-
+
-
+
-
+
-
+
- -
+
- - - - - - +
+ + +
+
+ + +
@@ -293,26 +294,26 @@
-
-
+
+
Status:
-
+
{{model.user.userDisplayState.name}}
-
+
+ type="text" + class="input-block-level" + localize="placeholder" + placeholder="@placeholders_enterMessage" + ng-model="model.resendInviteMessage" + rows="4"> +
-
-
+
+
Last login:
-
+
{{ model.user.formattedLastLogin }} {{ model.user.name | umbWordLimit:1 }} has not logged in yet
-
-
+
+
Failed login attempts:
-
+
{{ model.user.failedPasswordAttempts }}
-
-
+
+
Last lockout date:
-
+
{{ model.user.name | umbWordLimit:1 }} hasn't been locked out @@ -354,11 +355,11 @@
-
-
+
+
Password is last changed:
-
+
The password hasn't been changed @@ -366,20 +367,20 @@
-
-
+
+
User is created:
-
+
{{ model.user.formattedCreateDate }}
-
-
+
+
User is last updated:
-
+
{{ model.user.formattedUpdateDate }}
From 94922ccbd2118e0d51088b1751ce50ce1f2df7e2 Mon Sep 17 00:00:00 2001 From: Dave Woestenborghs Date: Tue, 9 Oct 2018 08:51:02 +0200 Subject: [PATCH 37/98] #3141 fixed the problem differently after input from @markadrake --- .../src/common/services/navigation.service.js | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/Umbraco.Web.UI.Client/src/common/services/navigation.service.js b/src/Umbraco.Web.UI.Client/src/common/services/navigation.service.js index 8fb7137e9a..e617f62ed4 100644 --- a/src/Umbraco.Web.UI.Client/src/common/services/navigation.service.js +++ b/src/Umbraco.Web.UI.Client/src/common/services/navigation.service.js @@ -73,6 +73,7 @@ function navigationService($rootScope, $routeParams, $log, $location, $q, $timeo appState.setSectionState("showSearchResults", false); appState.setGlobalState("stickyNavigation", false); appState.setGlobalState("showTray", false); + appState.setMenuState("currentNode", null); if (appState.getGlobalState("isTablet") === true) { appState.setGlobalState("showNavigation", false); @@ -660,10 +661,10 @@ function navigationService($rootScope, $routeParams, $log, $location, $q, $timeo */ hideDialog: function (showMenu) { - setMode("default"); - - if(showMenu){ + if (showMenu) { this.showMenu(undefined, { skipDefault: true, node: appState.getMenuState("currentNode") }); + } else { + setMode("default"); } }, /** From 08818c63588f1e16c993d4ea32518c86dac14d46 Mon Sep 17 00:00:00 2001 From: Nathan Woulfe Date: Fri, 5 Oct 2018 20:15:40 +1000 Subject: [PATCH 38/98] removes ng-show from iframe, make loader background a solid color to hide iframe while it loads --- src/Umbraco.Web.UI.Client/src/less/canvas-designer.less | 4 ++-- src/Umbraco.Web.UI/Umbraco/Views/Preview/Index.cshtml | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/Umbraco.Web.UI.Client/src/less/canvas-designer.less b/src/Umbraco.Web.UI.Client/src/less/canvas-designer.less index 78c1616bc6..cbb38a23b1 100644 --- a/src/Umbraco.Web.UI.Client/src/less/canvas-designer.less +++ b/src/Umbraco.Web.UI.Client/src/less/canvas-designer.less @@ -81,9 +81,9 @@ a, a:hover{ .wait { display: block; - height: 280px; + height: 100%; width: 100%; - background: center center url(../img/loader.gif) no-repeat; + background:#fff center center url(../img/loader.gif) no-repeat; } /****************************/ diff --git a/src/Umbraco.Web.UI/Umbraco/Views/Preview/Index.cshtml b/src/Umbraco.Web.UI/Umbraco/Views/Preview/Index.cshtml index 02209063fd..7f442cc333 100644 --- a/src/Umbraco.Web.UI/Umbraco/Views/Preview/Index.cshtml +++ b/src/Umbraco.Web.UI/Umbraco/Views/Preview/Index.cshtml @@ -20,7 +20,7 @@ @Html.Partial(Model.PreviewExtendedHeaderView) } -
+
From 471e47e11bb64ee4d0386e8937c02315ff1a1f64 Mon Sep 17 00:00:00 2001 From: Jan Skovgaard Date: Tue, 9 Oct 2018 10:41:31 +0200 Subject: [PATCH 39/98] #3163 - Don't overwrite the label name even though labels are disabled in the color picker (#3164) --- .../src/views/components/umb-color-swatches.html | 2 +- .../propertyeditors/colorpicker/colorpicker.prevalues.html | 2 +- src/Umbraco.Web/PropertyEditors/ColorListPreValueEditor.cs | 5 ++--- 3 files changed, 4 insertions(+), 5 deletions(-) diff --git a/src/Umbraco.Web.UI.Client/src/views/components/umb-color-swatches.html b/src/Umbraco.Web.UI.Client/src/views/components/umb-color-swatches.html index a89e51ab32..d038c9973c 100644 --- a/src/Umbraco.Web.UI.Client/src/views/components/umb-color-swatches.html +++ b/src/Umbraco.Web.UI.Client/src/views/components/umb-color-swatches.html @@ -1,6 +1,6 @@ 
-
From 9b4f879b6d051391c1437e0133719b010ef6feb8 Mon Sep 17 00:00:00 2001 From: Anders Bjerner Date: Tue, 9 Oct 2018 12:28:43 +0200 Subject: [PATCH 46/98] Added XML documentation to the DatabaseSchemaHelper class (#3205) --- .../Persistence/DatabaseSchemaHelper.cs | 106 +++++++++++++++++- 1 file changed, 105 insertions(+), 1 deletion(-) diff --git a/src/Umbraco.Core/Persistence/DatabaseSchemaHelper.cs b/src/Umbraco.Core/Persistence/DatabaseSchemaHelper.cs index 304cdc185f..f4cf7b23e9 100644 --- a/src/Umbraco.Core/Persistence/DatabaseSchemaHelper.cs +++ b/src/Umbraco.Core/Persistence/DatabaseSchemaHelper.cs @@ -1,6 +1,5 @@ using System; using System.Linq; -using Umbraco.Core.Configuration; using Umbraco.Core.Logging; using Umbraco.Core.Models.Rdbms; using Umbraco.Core.Persistence.DatabaseModelDefinitions; @@ -11,6 +10,9 @@ using Umbraco.Core.Services; namespace Umbraco.Core.Persistence { + /// + /// Helper class for working with databases and schemas. + /// public class DatabaseSchemaHelper { private readonly Database _db; @@ -18,6 +20,22 @@ namespace Umbraco.Core.Persistence private readonly ISqlSyntaxProvider _syntaxProvider; private readonly BaseDataCreation _baseDataCreation; + /// + /// Intializes a new helper instance. + /// + /// The database to be used. + /// The logger. + /// The syntax provider. + /// + /// A new instance could be initialized like: + /// + /// var schemaHelper = new DatabaseSchemaHelper( + /// ApplicationContext.Current.DatabaseContext.Database, + /// ApplicationContext.Current.ProfilingLogger.Logger, + /// ApplicationContext.Current.DatabaseContext.SqlSyntax + /// ); + /// + /// public DatabaseSchemaHelper(Database db, ILogger logger, ISqlSyntaxProvider syntaxProvider) { _db = db; @@ -26,11 +44,41 @@ namespace Umbraco.Core.Persistence _baseDataCreation = new BaseDataCreation(db, logger); } + /// + /// Returns whether a table with the specified exists in the database. + /// + /// The name of the table. + /// true if the table exists; otherwise false. + /// + /// + /// if (schemaHelper.TableExist("MyTable")) + /// { + /// // do something when the table exists + /// } + /// + /// public bool TableExist(string tableName) { return _syntaxProvider.DoesTableExist(_db, tableName); } + /// + /// Returns whether the table for the specified exists in the database. + /// + /// If has been decorated with an , the name from that + /// attribute will be used for the table name. If the attribute is not present, the name + /// will be used instead. + /// + /// The type representing the DTO/table. + /// true if the table exists; otherwise false. + /// + /// + /// if (schemaHelper.TableExist<MyDto>) + /// { + /// // do something when the table exists + /// } + /// + /// public bool TableExist() { var poco = Database.PocoData.ForType(typeof(T)); @@ -90,6 +138,17 @@ namespace Umbraco.Core.Persistence _logger.Info("Finalized database schema creation"); } + /// Creates a new table in the database based on the type of . + /// + /// If has been decorated with an , the name from that + /// attribute will be used for the table name. If the attribute is not present, the name + /// will be used instead. + /// + /// If a table with the same name already exists, the parameter will determine + /// whether the table is overwritten. If true, the table will be overwritten, whereas this method will + /// not do anything if the parameter is false. + /// The type representing the DTO/table. + /// Whether the table should be overwritten if it already exists. public void CreateTable(bool overwrite) where T : new() { @@ -97,6 +156,16 @@ namespace Umbraco.Core.Persistence CreateTable(overwrite, tableType); } + /// + /// Creates a new table in the database based on the type of . + /// + /// If has been decorated with an , the name from that + /// attribute will be used for the table name. If the attribute is not present, the name + /// will be used instead. + /// + /// If a table with the same name already exists, this method will not do anything. + /// + /// The type representing the DTO/table. public void CreateTable() where T : new() { @@ -104,6 +173,19 @@ namespace Umbraco.Core.Persistence CreateTable(false, tableType); } + /// + /// Creates a new table in the database for the specified . + /// + /// If has been decorated with an , the name from + /// that attribute will be used for the table name. If the attribute is not present, the name + /// will be used instead. + /// + /// If a table with the same name already exists, the parameter will determine + /// whether the table is overwritten. If true, the table will be overwritten, whereas this method will + /// not do anything if the parameter is false. + /// + /// Whether the table should be overwritten if it already exists. + /// The the representing the table. public void CreateTable(bool overwrite, Type modelType) { var tableDefinition = DefinitionFactory.GetTableDefinition(_syntaxProvider, modelType); @@ -189,6 +271,19 @@ namespace Umbraco.Core.Persistence } } + /// + /// Drops the table for the specified . + /// + /// If has been decorated with an , the name from that + /// attribute will be used for the table name. If the attribute is not present, the name + /// will be used instead. + /// + /// The type representing the DTO/table. + /// + /// + /// schemaHelper.DropTable<MyDto>); + /// + /// public void DropTable() where T : new() { @@ -204,6 +299,15 @@ namespace Umbraco.Core.Persistence DropTable(tableName); } + /// + /// Drops the table with the specified . + /// + /// The name of the table. + /// + /// + /// schemaHelper.DropTable("MyTable"); + /// + /// public void DropTable(string tableName) { var sql = new Sql(string.Format( From 9986c10cecbe6c0fd867891815dc5cda05adf724 Mon Sep 17 00:00:00 2001 From: Poornima Nayar Date: Mon, 8 Oct 2018 15:46:17 +0100 Subject: [PATCH 47/98] Cleaned up the view by removing inline styles and style tags on the view itself. Removed inline styles in the code behind files Moved all styles into the modals.less stylesheet --- .../src/less/modals.less | 57 +++++++++++++++++++ .../umbraco/dialogs/rollBack.aspx | 43 +------------- .../umbraco/dialogs/rollBack.aspx | 39 +------------ .../umbraco/dialogs/rollBack.aspx.cs | 10 ++-- 4 files changed, 66 insertions(+), 83 deletions(-) diff --git a/src/Umbraco.Web.UI.Client/src/less/modals.less b/src/Umbraco.Web.UI.Client/src/less/modals.less index d4552c3ac5..d8f188dd53 100644 --- a/src/Umbraco.Web.UI.Client/src/less/modals.less +++ b/src/Umbraco.Web.UI.Client/src/less/modals.less @@ -105,6 +105,63 @@ border-top: 1px solid @purple-l3; } +.umb-dialog .propertyItemheader { + width: 140px !Important; +} + +.umb-dialog .diffDropdown +{ + width:400px; +} + +.umb-dialog .diffPanel { + height: 400px; +} + + +.umb-dialog .diff { + margin-top: 10px; + height: 100%; + overflow: auto; + border-top: 1px solid #ccc; + border-top: 1px solid #ccc; + padding: 5px; +} +.umb-dialog .diff table{ + width:95%; + max-width:95%; + margin: 0 3px; +} +.umb-dialog .diff table th { + padding: 5px; + width: 25%; + border-bottom: 1px solid #ccc; +} + +.umb-dialog .diff table td { + border-bottom: 1px solid #ccc; + padding: 3px; +} + +.umb-dialog .diff del { + background: rgb(255, 230, 230) none repeat scroll 0%; + -moz-background-clip: -moz-initial; + -moz-background-origin: -moz-initial; + -moz-background-inline-policy: -moz-initial; +} + +.umb-dialog .diff ins { + background: rgb(230, 255, 230) none repeat scroll 0%; + -moz-background-clip: -moz-initial; + -moz-background-origin: -moz-initial; + -moz-background-inline-policy: -moz-initial; +} + +.umb-dialog .diff .diffnotice { + text-align: center; + margin-bottom: 10px; +} + /*we will always make sure to wrap iframe dialogs in proper padding*/ .umbracoDialog{ width: auto !Important; diff --git a/src/Umbraco.Web.UI/umbraco/dialogs/rollBack.aspx b/src/Umbraco.Web.UI/umbraco/dialogs/rollBack.aspx index 5709b47d10..f596121627 100644 --- a/src/Umbraco.Web.UI/umbraco/dialogs/rollBack.aspx +++ b/src/Umbraco.Web.UI/umbraco/dialogs/rollBack.aspx @@ -13,43 +13,6 @@ var submitOnEnter = true; - @@ -63,7 +26,7 @@ () - + @@ -76,7 +39,7 @@ - +

@@ -84,7 +47,7 @@

- +
diff --git a/src/Umbraco.Web/umbraco.presentation/umbraco/dialogs/rollBack.aspx b/src/Umbraco.Web/umbraco.presentation/umbraco/dialogs/rollBack.aspx index 6b67e41ecb..ae4c8dd5b5 100644 --- a/src/Umbraco.Web/umbraco.presentation/umbraco/dialogs/rollBack.aspx +++ b/src/Umbraco.Web/umbraco.presentation/umbraco/dialogs/rollBack.aspx @@ -13,44 +13,7 @@ var submitOnEnter = true; - +
diff --git a/src/Umbraco.Web/umbraco.presentation/umbraco/dialogs/rollBack.aspx.cs b/src/Umbraco.Web/umbraco.presentation/umbraco/dialogs/rollBack.aspx.cs index b28e40163b..f6390a9d0b 100644 --- a/src/Umbraco.Web/umbraco.presentation/umbraco/dialogs/rollBack.aspx.cs +++ b/src/Umbraco.Web/umbraco.presentation/umbraco/dialogs/rollBack.aspx.cs @@ -34,8 +34,8 @@ namespace umbraco.presentation.dialogs diffPanel.Visible = true; Document rollback = new Document(currentDoc.Id, new Guid(allVersions.SelectedValue)); - propertiesCompare.Text = "" + ui.Text("general", "name") + ":" + rollback.Text + ""; - propertiesCompare.Text += "" + ui.Text("content", "createDate") + ":" + rollback.VersionDate.ToLongDateString() + " " + rollback.VersionDate.ToLongTimeString() + " " + ui.Text("general", "by") + ": " + rollback.Writer.Name + ""; + propertiesCompare.Text = "" + ui.Text("general", "name") + ":" + rollback.Text + ""; + propertiesCompare.Text += "" + ui.Text("content", "createDate") + ":" + rollback.VersionDate.ToLongDateString() + " " + rollback.VersionDate.ToLongTimeString() + " " + ui.Text("general", "by") + ": " + rollback.Writer.Name + ""; if (rbl_mode.SelectedValue == "diff") lt_notice.Text = ui.Text("rollback", "diffHelp"); @@ -66,14 +66,14 @@ namespace umbraco.presentation.dialogs string cThevalue = library.StripHtml(cP.Value.ToString()); - propertiesCompare.Text += "" + p.PropertyType.Name + ":" + library.ReplaceLineBreaks(cms.businesslogic.utilities.Diff.Diff2Html(cThevalue, thevalue)) + ""; + propertiesCompare.Text += "" + p.PropertyType.Name + ":" + library.ReplaceLineBreaks(cms.businesslogic.utilities.Diff.Diff2Html(cThevalue, thevalue)) + ""; } else { //If no current version of the value... display with no diff. - propertiesCompare.Text += "" + p.PropertyType.Name + ":" + thevalue + ""; + propertiesCompare.Text += "" + p.PropertyType.Name + ":" + thevalue + ""; } @@ -81,7 +81,7 @@ namespace umbraco.presentation.dialogs else { //If display mode is html - propertiesCompare.Text += "" + p.PropertyType.Name + ":" + thevalue + ""; + propertiesCompare.Text += "" + p.PropertyType.Name + ":" + thevalue + ""; } //previewVersionContent.Controls.Add(new LiteralControl("

" + p.PropertyType.Name + "
")); From 7e16cf360a8388db3f030aa00de2c48ab947ab07 Mon Sep 17 00:00:00 2001 From: Poornima Nayar Date: Mon, 8 Oct 2018 23:32:35 +0100 Subject: [PATCH 48/98] Issue with the bottom border looking out of place on the select editor screen fixed --- .../src/less/components/umb-tabs.less | 30 +++++++++---------- 1 file changed, 15 insertions(+), 15 deletions(-) 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 e6773a3eb0..0a243b8978 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 @@ -1,15 +1,15 @@ -.umb-nav-tabs { - position: absolute; - z-index: 999; -} - -.umb-nav-tabs.-padding-left { - padding-left: 20px; -} - -.umb-tab-content { - padding-top: 20px; - position: relative; - top: 22px; - border-top: 1px solid @purple-l3; -} +.umb-nav-tabs { + position: absolute; + z-index: 999; +} + +.umb-nav-tabs.-padding-left { + padding-left: 20px; +} + +.umb-tab-content { + padding-top: 20px; + position: relative; + top: 31px; + border-top: 1px solid @purple-l3; +} From d1b1a1cf6d8e62bbfa148cf9c959309470753987 Mon Sep 17 00:00:00 2001 From: Jan Skovgaard Date: Tue, 9 Oct 2018 14:23:09 +0200 Subject: [PATCH 49/98] #3178 - Make the Checkbox/TrueFalse property editor configurable (#3179) --- .../propertyeditors/boolean/boolean.controller.js | 2 +- .../src/views/propertyeditors/boolean/boolean.html | 6 +++++- .../PropertyEditors/TrueFalsePropertyEditor.cs | 13 ++++++++++++- 3 files changed, 18 insertions(+), 3 deletions(-) diff --git a/src/Umbraco.Web.UI.Client/src/views/propertyeditors/boolean/boolean.controller.js b/src/Umbraco.Web.UI.Client/src/views/propertyeditors/boolean/boolean.controller.js index 7689d78431..c574e1424f 100644 --- a/src/Umbraco.Web.UI.Client/src/views/propertyeditors/boolean/boolean.controller.js +++ b/src/Umbraco.Web.UI.Client/src/views/propertyeditors/boolean/boolean.controller.js @@ -1,4 +1,4 @@ -function booleanEditorController($scope, $rootScope, assetsService) { +function booleanEditorController($scope) { function setupViewModel() { $scope.renderModel = { diff --git a/src/Umbraco.Web.UI.Client/src/views/propertyeditors/boolean/boolean.html b/src/Umbraco.Web.UI.Client/src/views/propertyeditors/boolean/boolean.html index 10f388a0d0..ad6bc43cfe 100644 --- a/src/Umbraco.Web.UI.Client/src/views/propertyeditors/boolean/boolean.html +++ b/src/Umbraco.Web.UI.Client/src/views/propertyeditors/boolean/boolean.html @@ -1,6 +1,10 @@

+ on-click="toggle()" + show-labels="{{model.config.labelOn ? 'true': 'false'}}" + label-position="right" + label-on="{{model.config.labelOn}}" + label-off="{{model.config.labelOn}}">
diff --git a/src/Umbraco.Web/PropertyEditors/TrueFalsePropertyEditor.cs b/src/Umbraco.Web/PropertyEditors/TrueFalsePropertyEditor.cs index 6a8e726911..350e80f4cb 100644 --- a/src/Umbraco.Web/PropertyEditors/TrueFalsePropertyEditor.cs +++ b/src/Umbraco.Web/PropertyEditors/TrueFalsePropertyEditor.cs @@ -15,6 +15,17 @@ namespace Umbraco.Web.PropertyEditors { [PreValueField("default", "Default Value", "boolean")] public string Default { get; set; } + + public TrueFalsePreValueEditor() + { + Fields.Add(new PreValueField() + { + Description = "Write a label text", + Key = "labelOn", + Name = "Label", + View = "textstring" + }); + } } } -} \ No newline at end of file +} From ee4a252b0742fb4d960d3f6bfa26365351ab5068 Mon Sep 17 00:00:00 2001 From: Sebastiaan Janssen Date: Tue, 9 Oct 2018 21:19:55 +0200 Subject: [PATCH 50/98] Revert "Fixed udi's rendered in rte content (#2531)" This reverts commit b0374695b15c4532b3dba1e1f62b2075924ba187. --- .../Configuration/UmbracoConfig.cs | 2 +- .../UmbracoSettings/ContentElement.cs | 22 +++-------- .../UmbracoSettings/IContentSection.cs | 4 +- src/Umbraco.Tests/Umbraco.Tests.csproj | 3 -- .../Web/TemplateUtilitiesTests.cs | 37 ++----------------- src/Umbraco.Tests/packages.config | 1 - .../Templates/TemplateUtilities.cs | 33 +---------------- 7 files changed, 13 insertions(+), 89 deletions(-) diff --git a/src/Umbraco.Core/Configuration/UmbracoConfig.cs b/src/Umbraco.Core/Configuration/UmbracoConfig.cs index 5b6d27b9c5..82d90073e8 100644 --- a/src/Umbraco.Core/Configuration/UmbracoConfig.cs +++ b/src/Umbraco.Core/Configuration/UmbracoConfig.cs @@ -202,4 +202,4 @@ namespace Umbraco.Core.Configuration //TODO: Add other configurations here ! } -} +} \ No newline at end of file diff --git a/src/Umbraco.Core/Configuration/UmbracoSettings/ContentElement.cs b/src/Umbraco.Core/Configuration/UmbracoSettings/ContentElement.cs index 9fe35f7cb5..17523ab3a1 100644 --- a/src/Umbraco.Core/Configuration/UmbracoSettings/ContentElement.cs +++ b/src/Umbraco.Core/Configuration/UmbracoSettings/ContentElement.cs @@ -139,8 +139,8 @@ namespace Umbraco.Core.Configuration.UmbracoSettings internal CommaDelimitedConfigurationElement DisallowedUploadFiles { get { return GetOptionalDelimitedElement("disallowedUploadFiles", new[] {"ashx", "aspx", "ascx", "config", "cshtml", "vbhtml", "asmx", "air", "axd"}); } - } - + } + [ConfigurationProperty("allowedUploadFiles")] internal CommaDelimitedConfigurationElement AllowedUploadFiles { @@ -195,12 +195,6 @@ namespace Umbraco.Core.Configuration.UmbracoSettings get { return GetOptionalTextElement("loginBackgroundImage", string.Empty); } } - [ConfigurationProperty("StripUdiAttributes")] - internal InnerTextConfigurationElement StripUdiAttributes - { - get { return GetOptionalTextElement("StripUdiAttributes", true); } - } - string IContentSection.NotificationEmailAddress { get { return Notifications.NotificationEmailAddress; } @@ -319,8 +313,8 @@ namespace Umbraco.Core.Configuration.UmbracoSettings IEnumerable IContentSection.DisallowedUploadFiles { get { return DisallowedUploadFiles; } - } - + } + IEnumerable IContentSection.AllowedUploadFiles { get { return AllowedUploadFiles; } @@ -363,11 +357,7 @@ namespace Umbraco.Core.Configuration.UmbracoSettings string IContentSection.LoginBackgroundImage { get { return LoginBackgroundImage; } - } - - bool IContentSection.StripUdiAttributes - { - get { return StripUdiAttributes; } - } + } + } } diff --git a/src/Umbraco.Core/Configuration/UmbracoSettings/IContentSection.cs b/src/Umbraco.Core/Configuration/UmbracoSettings/IContentSection.cs index bfcbabaccd..343e6ae9e1 100644 --- a/src/Umbraco.Core/Configuration/UmbracoSettings/IContentSection.cs +++ b/src/Umbraco.Core/Configuration/UmbracoSettings/IContentSection.cs @@ -75,8 +75,6 @@ namespace Umbraco.Core.Configuration.UmbracoSettings bool EnablePropertyValueConverters { get; } string LoginBackgroundImage { get; } - - bool StripUdiAttributes { get; } } -} +} \ No newline at end of file diff --git a/src/Umbraco.Tests/Umbraco.Tests.csproj b/src/Umbraco.Tests/Umbraco.Tests.csproj index abed9b8245..86c36a8d76 100644 --- a/src/Umbraco.Tests/Umbraco.Tests.csproj +++ b/src/Umbraco.Tests/Umbraco.Tests.csproj @@ -65,9 +65,6 @@ ..\packages\Examine.0.1.89\lib\net45\Examine.dll - - ..\packages\HtmlAgilityPack.1.4.9.5\lib\Net45\HtmlAgilityPack.dll - ..\packages\SharpZipLib.0.86.0\lib\20\ICSharpCode.SharpZipLib.dll diff --git a/src/Umbraco.Tests/Web/TemplateUtilitiesTests.cs b/src/Umbraco.Tests/Web/TemplateUtilitiesTests.cs index 96461519d8..f2a04c5f0f 100644 --- a/src/Umbraco.Tests/Web/TemplateUtilitiesTests.cs +++ b/src/Umbraco.Tests/Web/TemplateUtilitiesTests.cs @@ -1,6 +1,6 @@ using System; +using System.Linq; using System.Web; -using HtmlAgilityPack; using Moq; using NUnit.Framework; using Umbraco.Core; @@ -10,6 +10,7 @@ using Umbraco.Core.Models; using Umbraco.Core.Persistence.SqlSyntax; using Umbraco.Core.Profiling; using Umbraco.Core.Scoping; +using Umbraco.Core.Services; using Umbraco.Tests.TestHelpers; using Umbraco.Web; using Umbraco.Web.Routing; @@ -33,14 +34,6 @@ namespace Umbraco.Tests.Web [TestCase("hello href=\"{localLink:umb://document-type/9931BDE0AAC34BABB838909A7B47570E}\" world ", "hello href=\"/my-test-url\" world ")] //this one has an invalid char so won't match [TestCase("hello href=\"{localLink:umb^://document-type/9931BDE0-AAC3-4BAB-B838-909A7B47570E}\" world ", "hello href=\"{localLink:umb^://document-type/9931BDE0-AAC3-4BAB-B838-909A7B47570E}\" world ")] - // with a-tag with data-udi attribute, that needs to be stripped - [TestCase("hello world ", "hello world ")] - // with a-tag with data-udi attribute spelled wrong, so don't need stripping - [TestCase("hello world ", "hello world ")] - // with a img-tag with data-udi id, that needs to be strippde - [TestCase("hello world ", "hello world ")] - // with a img-tag with data-udi id spelled wrong, so don't need stripping - [TestCase("hello world ", "hello world ")] public void ParseLocalLinks(string input, string result) { var serviceCtxMock = MockHelper.GetMockedServiceContext(); @@ -70,7 +63,7 @@ namespace Umbraco.Tests.Web //setup a quick mock of the WebRouting section Mock.Of(section => section.WebRouting == Mock.Of(routingSection => routingSection.UrlProviderMode == "AutoLegacy")), //pass in the custom url provider - new[] { testUrlProvider.Object }, + new[]{ testUrlProvider.Object }, true)) { var output = TemplateUtilities.ParseInternalLinks(input, umbCtx.UrlProvider); @@ -78,27 +71,5 @@ namespace Umbraco.Tests.Web Assert.AreEqual(result, output); } } - - [Test] - public void StripDataUdiAttributesUsingSrtringOnLinks() - { - var input = "hello world "; - var expected = "hello world "; - - var result = TemplateUtilities.StripUdiDataAttributes(input); - - Assert.AreEqual(expected, result); - } - - [Test] - public void StripDataUdiAttributesUsingStringOnImages() - { - var input = "hello world "; - var expected = "hello world "; - - var result = TemplateUtilities.StripUdiDataAttributes(input); - - Assert.AreEqual(expected, result); - } } -} +} \ No newline at end of file diff --git a/src/Umbraco.Tests/packages.config b/src/Umbraco.Tests/packages.config index e458795917..45afd3279c 100644 --- a/src/Umbraco.Tests/packages.config +++ b/src/Umbraco.Tests/packages.config @@ -3,7 +3,6 @@ - diff --git a/src/Umbraco.Web/Templates/TemplateUtilities.cs b/src/Umbraco.Web/Templates/TemplateUtilities.cs index 39ac69989a..a7e6738374 100644 --- a/src/Umbraco.Web/Templates/TemplateUtilities.cs +++ b/src/Umbraco.Web/Templates/TemplateUtilities.cs @@ -1,6 +1,4 @@ -using HtmlAgilityPack; -using System; -using System.Runtime.CompilerServices; +using System; using System.Text.RegularExpressions; using Umbraco.Core; using Umbraco.Core.Configuration; @@ -48,11 +46,6 @@ namespace Umbraco.Web.Templates { if (urlProvider == null) throw new ArgumentNullException("urlProvider"); - if(string.IsNullOrEmpty(text)) - { - return text; - } - // Parse internal links var tags = LocalLinkPattern.Matches(text); foreach (Match tag in tags) @@ -81,11 +74,6 @@ namespace Umbraco.Web.Templates } } - if (UmbracoConfig.For.UmbracoSettings().Content.StripUdiAttributes) - { - text = StripUdiDataAttributes(text); - } - return text; } @@ -114,9 +102,6 @@ namespace Umbraco.Web.Templates private static readonly Regex ResolveUrlPattern = new Regex("(=[\"\']?)(\\W?\\~(?:.(?![\"\']?\\s+(?:\\S+)=|[>\"\']))+.)[\"\']?", RegexOptions.Compiled | RegexOptions.IgnoreCase | RegexOptions.IgnorePatternWhitespace); - private static readonly Regex UdiDataAttributePattern = new Regex("data-udi=\"[^\\\"]*\"", - RegexOptions.IgnoreCase | RegexOptions.Compiled); - /// /// The RegEx matches any HTML attribute values that start with a tilde (~), those that match are passed to ResolveUrl to replace the tilde with the application path. /// @@ -160,21 +145,5 @@ namespace Umbraco.Web.Templates { return text.CleanForXss(ignoreFromClean); } - - /// - /// Strips data-udi attributes from rich text - /// - /// A html string - /// A string stripped from the data-uid attributes - public static string StripUdiDataAttributes(string input) - { - if (string.IsNullOrEmpty(input)) - { - return string.Empty; - } - - - return UdiDataAttributePattern.Replace(input, string.Empty); - } } } From 4d1b361f8fc722ee296fe1fa0b3b96f4c02a604e Mon Sep 17 00:00:00 2001 From: Kenn Jacobsen Date: Tue, 9 Oct 2018 21:32:54 +0200 Subject: [PATCH 51/98] Style Public access dialog (#3194) --- src/Umbraco.Web.UI/umbraco/config/lang/en.xml | 2 +- .../umbraco/config/lang/en_us.xml | 2 +- .../umbraco/dialogs/protectPage.aspx | 114 +++++++++--------- .../umbraco/controls/dualSelectBox.cs | 9 ++ .../umbraco/dialogs/protectPage.aspx.cs | 55 +++++---- 5 files changed, 100 insertions(+), 82 deletions(-) diff --git a/src/Umbraco.Web.UI/umbraco/config/lang/en.xml b/src/Umbraco.Web.UI/umbraco/config/lang/en.xml index 477bce0931..47a3dc74f4 100644 --- a/src/Umbraco.Web.UI/umbraco/config/lang/en.xml +++ b/src/Umbraco.Web.UI/umbraco/config/lang/en.xml @@ -1219,7 +1219,7 @@ To manage your website, simply open the Umbraco back office and start adding con Role based protection - using Umbraco's member groups.]]> + If you wish to control access to the page using role-based authentication, using Umbraco's member groups. You need to create a membergroup before you can use role-based authentication Error Page Used when people are logged on, but do not have access 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 b1fa2b84b3..a9db9768cf 100644 --- a/src/Umbraco.Web.UI/umbraco/config/lang/en_us.xml +++ b/src/Umbraco.Web.UI/umbraco/config/lang/en_us.xml @@ -1217,7 +1217,7 @@ To manage your website, simply open the Umbraco back office and start adding con Role based protection - using Umbraco's member groups.]]> + If you wish to control access to the page using role-based authentication, using Umbraco's member groups. You need to create a membergroup before you can use role-based authentication Error Page Used when people are logged on, but do not have access diff --git a/src/Umbraco.Web.UI/umbraco/dialogs/protectPage.aspx b/src/Umbraco.Web.UI/umbraco/dialogs/protectPage.aspx index 49e1a43ccf..bda6db5be3 100644 --- a/src/Umbraco.Web.UI/umbraco/dialogs/protectPage.aspx +++ b/src/Umbraco.Web.UI/umbraco/dialogs/protectPage.aspx @@ -75,15 +75,19 @@ - - + +
+ +
+ +
-
+
@@ -116,74 +120,72 @@ + +
+ - - -
- - - - -
- -
- - - -
- - -

Member name already exists, click Change to use a different name or Update to continue

-
-
- - - -

<%= umbraco.ui.Text("publicAccess", "paSelectRoles", UmbracoUser)%>

-
- - - -
- - - - - - - <%=umbraco.ui.Text("paLoginPageHelp")%> - -
- +
+ + + +
- - - - - - - <%=umbraco.ui.Text("paErrorPageHelp")%> - -
- +
+ + +
- - - + +

Member name already exists, click Change to use a different name or Update to continue

+
+ + + + +

<%= umbraco.ui.Text("publicAccess", "paSelectRoles", UmbracoUser)%>

+
+ + + +
+ + + + + + <%=umbraco.ui.Text("paLoginPageHelp")%> + +
+ +
+ + +
+ + + <%=umbraco.ui.Text("paErrorPageHelp")%> + +
+ +
+ +
+ +
+
- diff --git a/src/Umbraco.Web/umbraco.presentation/umbraco/controls/dualSelectBox.cs b/src/Umbraco.Web/umbraco.presentation/umbraco/controls/dualSelectBox.cs index 34ad91303e..00bf9d0866 100644 --- a/src/Umbraco.Web/umbraco.presentation/umbraco/controls/dualSelectBox.cs +++ b/src/Umbraco.Web/umbraco.presentation/umbraco/controls/dualSelectBox.cs @@ -41,6 +41,15 @@ namespace umbraco.controls } } + public new int Height + { + set + { + _possibleValues.Height = new Unit(value); + _selectedValues.Height = new Unit(value); + } + } + protected override void CreateChildControls() { _possibleValues.ID = "posVals"; diff --git a/src/Umbraco.Web/umbraco.presentation/umbraco/dialogs/protectPage.aspx.cs b/src/Umbraco.Web/umbraco.presentation/umbraco/dialogs/protectPage.aspx.cs index 04fb9e6bf9..6fe22f0cd3 100644 --- a/src/Umbraco.Web/umbraco.presentation/umbraco/dialogs/protectPage.aspx.cs +++ b/src/Umbraco.Web/umbraco.presentation/umbraco/dialogs/protectPage.aspx.cs @@ -41,7 +41,7 @@ namespace umbraco.presentation.umbraco.dialogs protected void selectMode(object sender, EventArgs e) { p_mode.Visible = false; - p_buttons.Visible = true; + p_setup.Visible = true; if (rb_simple.Checked) { @@ -124,14 +124,15 @@ namespace umbraco.presentation.umbraco.dialogs bt_protect.CommandName = "advanced"; } - p_buttons.Visible = true; p_mode.Visible = false; + p_setup.Visible = true; } } // Load up membergrouops _memberGroups.ID = "Membergroups"; _memberGroups.Width = 175; + _memberGroups.Height = 165; var selectedGroups = ""; // get roles from the membership provider @@ -160,7 +161,8 @@ namespace umbraco.presentation.umbraco.dialogs groupsSelector.Controls.Add(_memberGroups); - bt_protect.Text = ui.Text("update"); + bt_selectMode.Text = ui.Text("buttons", "select"); + bt_protect.Text = ui.Text("save"); bt_buttonRemoveProtection.Text = ui.Text("paRemoveProtection"); // Put user code to initialize the page here @@ -266,37 +268,33 @@ namespace umbraco.presentation.umbraco.dialogs } } - feedback.Text = ui.Text("publicAccess", "paIsProtected", new cms.businesslogic.CMSNode(pageId).Text) + "

" + ui.Text("closeThisWindow") + ""; + feedback_text.Text = ui.Text("publicAccess", "paIsProtected", new cms.businesslogic.CMSNode(pageId).Text); - p_buttons.Visible = false; - pane_advanced.Visible = false; - pane_simple.Visible = false; + p_setup.Visible = false; + p_feedback.Visible = true; var content = ApplicationContext.Current.Services.ContentService.GetById(pageId); //reloads the current node in the tree ClientTools.SyncTree(content.Path, true); //reloads the current node's children in the tree ClientTools.ReloadActionNode(false, true); - feedback.type = global::umbraco.uicontrols.Feedback.feedbacktype.success; } protected void buttonRemoveProtection_Click(object sender, System.EventArgs e) { int pageId = int.Parse(helper.Request("nodeId")); - p_buttons.Visible = false; - pane_advanced.Visible = false; - pane_simple.Visible = false; + p_setup.Visible = false; Access.RemoveProtection(pageId); - feedback.Text = ui.Text("publicAccess", "paIsRemoved", new cms.businesslogic.CMSNode(pageId).Text) + "

" + ui.Text("closeThisWindow") + ""; + feedback_text.Text = ui.Text("publicAccess", "paIsRemoved", new cms.businesslogic.CMSNode(pageId).Text); + p_feedback.Visible = true; var content = ApplicationContext.Current.Services.ContentService.GetById(pageId); //reloads the current node in the tree ClientTools.SyncTree(content.Path, true); //reloads the current node's children in the tree ClientTools.ReloadActionNode(false, true); - feedback.type = global::umbraco.uicontrols.Feedback.feedbacktype.success; } protected CustomValidator SimpleLoginNameValidator; @@ -312,13 +310,13 @@ namespace umbraco.presentation.umbraco.dialogs protected global::System.Web.UI.HtmlControls.HtmlInputHidden tempFile; ///

- /// feedback control. + /// p_feedback control. /// /// /// Auto-generated field. /// To modify move field declaration from designer file to code-behind file. /// - protected global::umbraco.uicontrols.Feedback feedback; + protected global::System.Web.UI.WebControls.Panel p_feedback; /// /// p_mode control. @@ -329,6 +327,15 @@ namespace umbraco.presentation.umbraco.dialogs /// protected global::System.Web.UI.WebControls.Panel p_mode; + /// + /// p_setup control. + /// + /// + /// Auto-generated field. + /// To modify move field declaration from designer file to code-behind file. + /// + protected global::System.Web.UI.WebControls.Panel p_setup; + /// /// pane_chooseMode control. /// @@ -464,15 +471,6 @@ namespace umbraco.presentation.umbraco.dialogs /// protected global::System.Web.UI.WebControls.PlaceHolder groupsSelector; - /// - /// p_buttons control. - /// - /// - /// Auto-generated field. - /// To modify move field declaration from designer file to code-behind file. - /// - protected global::System.Web.UI.WebControls.Panel p_buttons; - /// /// pane_pages control. /// @@ -581,6 +579,15 @@ namespace umbraco.presentation.umbraco.dialogs /// protected global::System.Web.UI.WebControls.PlaceHolder js; + /// + /// feedback_text control. + /// + /// + /// Auto-generated field. + /// To modify move field declaration from designer file to code-behind file. + /// + protected global::System.Web.UI.WebControls.Literal feedback_text; + } } From fd1a9bb3656739dcacc86095e43844d6ecc09ab0 Mon Sep 17 00:00:00 2001 From: Dave Woestenborghs Date: Tue, 9 Oct 2018 21:51:04 +0200 Subject: [PATCH 52/98] #3214 - umbracoUrlAlias with uppercase characters (#3220) --- .../Routing/ContentFinderByUrlAlias.cs | 27 ++++++++++++------- 1 file changed, 17 insertions(+), 10 deletions(-) diff --git a/src/Umbraco.Web/Routing/ContentFinderByUrlAlias.cs b/src/Umbraco.Web/Routing/ContentFinderByUrlAlias.cs index e0121a4b3c..a27b9bd5b4 100644 --- a/src/Umbraco.Web/Routing/ContentFinderByUrlAlias.cs +++ b/src/Umbraco.Web/Routing/ContentFinderByUrlAlias.cs @@ -54,10 +54,17 @@ namespace Umbraco.Web.Routing alias = alias.TrimStart('/'); var xpathBuilder = new StringBuilder(); - xpathBuilder.Append(XPathStringsDefinition.Root); + if (rootNodeId > 0) + { xpathBuilder.AppendFormat(XPathStrings.DescendantDocumentById, rootNodeId); + } + else + { + xpathBuilder.Append(XPathStringsDefinition.Root); + } + XPathVariable var = null; if (alias.Contains('\'') || alias.Contains('"')) @@ -92,20 +99,20 @@ namespace Umbraco.Web.Routing { // legacy XML schema case 0: - DescendantDocumentById = "//node [@id={0}]"; + DescendantDocumentById = "id({0})"; DescendantDocumentByAlias = "//node[(" - + "contains(concat(',',translate(data [@alias='umbracoUrlAlias'], ' ', ''),','),',{0},')" - + " or contains(concat(',',translate(data [@alias='umbracoUrlAlias'], ' ', ''),','),',/{0},')" - + ")]"; + + "contains(concat(',',translate(translate(data [@alias='umbracoUrlAlias'], ' ', ''),'ABCDEFGHIJKLMNOPQRSTUVWXYZ', 'abcdefghijklmnopqrstuvwxyz'),','),',{0},')" + + " or contains(concat(',',translate(translate(data [@alias='umbracoUrlAlias'], ' ', ''),'ABCDEFGHIJKLMNOPQRSTUVWXYZ', 'abcdefghijklmnopqrstuvwxyz'),','),',/{0},')" + + ")]"; break; // default XML schema as of 4.10 case 1: - DescendantDocumentById = "//* [@isDoc and @id={0}]"; + DescendantDocumentById = "id({0})[@isDoc]"; DescendantDocumentByAlias = "//* [@isDoc and (" - + "contains(concat(',',translate(umbracoUrlAlias, ' ', ''),','),',{0},')" - + " or contains(concat(',',translate(umbracoUrlAlias, ' ', ''),','),',/{0},')" - + ")]"; + + "contains(concat(',',translate(translate(umbracoUrlAlias, ' ', ''),'ABCDEFGHIJKLMNOPQRSTUVWXYZ', 'abcdefghijklmnopqrstuvwxyz'),','),',{0},')" + + " or contains(concat(',',translate(translate(umbracoUrlAlias, ' ', ''),'ABCDEFGHIJKLMNOPQRSTUVWXYZ', 'abcdefghijklmnopqrstuvwxyz'),','),',/{0},')" + + ")]"; break; default: @@ -133,4 +140,4 @@ namespace Umbraco.Web.Routing #endregion } -} \ No newline at end of file +} From 3aece09e09564c3b7ba75f1e14b2a29cdbf6f89b Mon Sep 17 00:00:00 2001 From: Jan Skovgaard Date: Tue, 9 Oct 2018 22:25:42 +0200 Subject: [PATCH 53/98] 3223 - Minor tweaks and code alignment for the checkbox and color picker styling (#3224) * Make the focus effect on the toggle use the same box-shadow as is already being used in the color picker instead of doing it differently * Use the color variables instead of hard coded color and also make use of LESS' fade function outputting an rgba() color --- .../src/less/components/buttons/umb-toggle.less | 4 ++-- .../src/less/components/umb-color-swatches.less | 6 +++--- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/Umbraco.Web.UI.Client/src/less/components/buttons/umb-toggle.less b/src/Umbraco.Web.UI.Client/src/less/components/buttons/umb-toggle.less index 2ca03e2c79..150963cbb2 100644 --- a/src/Umbraco.Web.UI.Client/src/less/components/buttons/umb-toggle.less +++ b/src/Umbraco.Web.UI.Client/src/less/components/buttons/umb-toggle.less @@ -11,8 +11,7 @@ } .umb-toggle:focus .umb-toggle__toggle{ - outline: 0; - box-shadow: 0 0 5px fade(@black, 30%); + box-shadow: 0 1px 3px fade(@black, 12%), 0 1px 2px fade(@black, 24%); } .umb-toggle__handler { @@ -35,6 +34,7 @@ background: @gray-8; border-radius: 90px; position: relative; + transition: box-shadow .3s; } .umb-toggle--checked .umb-toggle__toggle { diff --git a/src/Umbraco.Web.UI.Client/src/less/components/umb-color-swatches.less b/src/Umbraco.Web.UI.Client/src/less/components/umb-color-swatches.less index d8e67444a1..43e62780a3 100644 --- a/src/Umbraco.Web.UI.Client/src/less/components/umb-color-swatches.less +++ b/src/Umbraco.Web.UI.Client/src/less/components/umb-color-swatches.less @@ -4,7 +4,7 @@ .umb-color-box { border: 1px solid @gray-8; - color: white; + color: @white; cursor: pointer; padding: 1px; text-align: center; @@ -19,7 +19,7 @@ justify-content: center; &:hover, &:focus { - box-shadow: 0 1px 3px rgba(0,0,0,0.12), 0 1px 2px rgba(0,0,0,0.24); + box-shadow: 0 1px 3px fade(@black, 12%), 0 1px 2px fade(@black, 24%); } &.active { @@ -56,7 +56,7 @@ padding-top: 10px; .umb-color-box__label { - background: #fff; + background: @white; font-size: 14px; display: flex; flex-flow: column wrap; From afa3e9b5ebbbed65479443011e6b2962913e5c66 Mon Sep 17 00:00:00 2001 From: Kenn Jacobsen Date: Tue, 9 Oct 2018 22:54:51 +0200 Subject: [PATCH 54/98] Improve image cropper UX (#3149) --- .../src/less/property-editors.less | 12 +++++++++- .../imagecropper/imagecropper.controller.js | 22 ++++++++++++++++++- .../imagecropper/imagecropper.html | 11 +++++----- src/Umbraco.Web.UI/umbraco/config/lang/da.xml | 2 ++ src/Umbraco.Web.UI/umbraco/config/lang/en.xml | 4 +++- .../umbraco/config/lang/en_us.xml | 4 +++- 6 files changed, 45 insertions(+), 10 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 d14a1abae9..e3a8128671 100644 --- a/src/Umbraco.Web.UI.Client/src/less/property-editors.less +++ b/src/Umbraco.Web.UI.Client/src/less/property-editors.less @@ -315,7 +315,7 @@ div.umb-codeeditor .umb-btn-toolbar { .umb-mediapicker .umb-sortable-thumbnails li { flex-direction: column; - margin: 0 5px 5px 0; + margin: 0 0 5px 5px; padding: 5px; } @@ -574,6 +574,16 @@ div.umb-codeeditor .umb-btn-toolbar { } } + .imagecropper .umb-cropper__container .button-drawer { + display: flex; + justify-content: flex-end; + padding: 10px; + + button { + margin-left: 4px; + } + } + .umb-close-cropper { position: absolute; top: 3px; diff --git a/src/Umbraco.Web.UI.Client/src/views/propertyeditors/imagecropper/imagecropper.controller.js b/src/Umbraco.Web.UI.Client/src/views/propertyeditors/imagecropper/imagecropper.controller.js index bc2dd91722..47442495f7 100644 --- a/src/Umbraco.Web.UI.Client/src/views/propertyeditors/imagecropper/imagecropper.controller.js +++ b/src/Umbraco.Web.UI.Client/src/views/propertyeditors/imagecropper/imagecropper.controller.js @@ -36,12 +36,32 @@ angular.module('umbraco') //crop a specific crop $scope.crop = function (crop) { - $scope.currentCrop = crop; + // clone the crop so we can discard the changes + $scope.currentCrop = angular.copy(crop); $scope.currentPoint = undefined; }; //done cropping $scope.done = function () { + if (!$scope.currentCrop) { + return; + } + // find the original crop by crop alias and update its coordinates + var editedCrop = _.find($scope.model.value.crops, function(crop) { + return crop.alias === $scope.currentCrop.alias; + }); + editedCrop.coordinates = $scope.currentCrop.coordinates; + $scope.close(); + }; + + //reset the current crop + $scope.reset = function() { + $scope.currentCrop.coordinates = undefined; + $scope.done(); + } + + //close crop overlay + $scope.close = function (crop) { $scope.currentCrop = undefined; $scope.currentPoint = undefined; }; diff --git a/src/Umbraco.Web.UI.Client/src/views/propertyeditors/imagecropper/imagecropper.html b/src/Umbraco.Web.UI.Client/src/views/propertyeditors/imagecropper/imagecropper.html index 18f528fbd2..a8f513f006 100644 --- a/src/Umbraco.Web.UI.Client/src/views/propertyeditors/imagecropper/imagecropper.html +++ b/src/Umbraco.Web.UI.Client/src/views/propertyeditors/imagecropper/imagecropper.html @@ -18,8 +18,6 @@
- -
- - Reset - +
+ + + +
diff --git a/src/Umbraco.Web.UI/umbraco/config/lang/da.xml b/src/Umbraco.Web.UI/umbraco/config/lang/da.xml index 0e9fc09bcd..2ce6a31786 100644 --- a/src/Umbraco.Web.UI/umbraco/config/lang/da.xml +++ b/src/Umbraco.Web.UI/umbraco/config/lang/da.xml @@ -991,6 +991,8 @@ Mange hilsner fra Umbraco robotten Nulstil + Acceptér + Fortryd diff --git a/src/Umbraco.Web.UI/umbraco/config/lang/en.xml b/src/Umbraco.Web.UI/umbraco/config/lang/en.xml index 47a3dc74f4..89ba5e0828 100644 --- a/src/Umbraco.Web.UI/umbraco/config/lang/en.xml +++ b/src/Umbraco.Web.UI/umbraco/config/lang/en.xml @@ -1296,11 +1296,13 @@ To manage your website, simply open the Umbraco back office and start adding con Enter the link - Reset + Reset crop Define crop Give the crop an alias and its default width and height Save crop Add new crop + Done + Undo edits Current version 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 a9db9768cf..a42d4d0c60 100644 --- a/src/Umbraco.Web.UI/umbraco/config/lang/en_us.xml +++ b/src/Umbraco.Web.UI/umbraco/config/lang/en_us.xml @@ -1294,11 +1294,13 @@ To manage your website, simply open the Umbraco back office and start adding con Enter the link - Reset + Reset crop Define crop Give the crop an alias and its default width and height Save crop Add new crop + Done + Undo edits Current version From fb277d80e788b9edd59413b2b9f70c46f7f441d2 Mon Sep 17 00:00:00 2001 From: Jamie Townsend Date: Sun, 14 Oct 2018 12:34:16 +0100 Subject: [PATCH 55/98] Fix for old password not showing/hiding correctly on admin users page #3069 (#3273) --- .../src/views/users/user.controller.js | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) 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 1569b5979b..e32d331d0a 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 @@ -93,8 +93,14 @@ //in the ASP.NET Identity world, this config option will allow an admin user to change another user's password //if the user has access to the user section. So if this editor is being access, the user of course has access to this section. //the authorization check is also done on the server side when submitted. - vm.changePasswordModel.config.allowManuallyChangingPassword = !vm.user.isCurrentUser; - + + // only update the setting if not the current logged in user, otherwise leave the value as it is + // currently set in the web.config + if (!vm.user.isCurrentUser) + { + vm.changePasswordModel.config.allowManuallyChangingPassword = true; + } + vm.loading = false; }); }); From 7a474c6fa44adbb4498069a7895f3d38595d0f5f Mon Sep 17 00:00:00 2001 From: Kim Holzmann Date: Wed, 10 Oct 2018 23:06:18 +0200 Subject: [PATCH 56/98] #3219 Validation error on templates when clicking "save" Error with use of savebutton fixed, use the suppressNotification value to check state. --- .../src/views/templates/edit.controller.js | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/src/Umbraco.Web.UI.Client/src/views/templates/edit.controller.js b/src/Umbraco.Web.UI.Client/src/views/templates/edit.controller.js index b23d11dea1..7017054904 100644 --- a/src/Umbraco.Web.UI.Client/src/views/templates/edit.controller.js +++ b/src/Umbraco.Web.UI.Client/src/views/templates/edit.controller.js @@ -91,15 +91,15 @@ }, function (err) { + if (suppressNotification) { + vm.page.saveButtonState = "error"; - vm.page.saveButtonState = "error"; - - localizationService.localizeMany(["speechBubbles_validationFailedHeader", "speechBubbles_validationFailedMessage"]).then(function(data){ - var header = data[0]; - var message = data[1]; - notificationsService.error(header, message); - }); - + localizationService.localizeMany(["speechBubbles_validationFailedHeader", "speechBubbles_validationFailedMessage"]).then(function (data) { + var header = data[0]; + var message = data[1]; + notificationsService.error(header, message); + }); + } }); }; From 1b0581bfce66cb89e0fd405669b10e5c5e1b986b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=B8ren=20Kottal?= Date: Tue, 16 Oct 2018 13:53:29 +0200 Subject: [PATCH 57/98] xml comments for ImageCropMode --- src/Umbraco.Web/Models/ImageCropMode.cs | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/src/Umbraco.Web/Models/ImageCropMode.cs b/src/Umbraco.Web/Models/ImageCropMode.cs index e36f079c02..03fe6676cb 100644 --- a/src/Umbraco.Web/Models/ImageCropMode.cs +++ b/src/Umbraco.Web/Models/ImageCropMode.cs @@ -2,11 +2,34 @@ namespace Umbraco.Web.Models { public enum ImageCropMode { + /// + /// Resizes the image to the given dimensions. If the set dimensions do not match the aspect ratio of the original image then the output is cropped to match the new aspect ratio. + /// Crop, + + /// + /// Resizes the image to the given dimensions. If the set dimensions do not match the aspect ratio of the original image then the output is resized to the maximum possible value in each direction while aintaining the original aspect ratio. + /// Max, + + /// + /// Resizes the image to the given dimensions. If the set dimensions do not match the aspect ratio of the original image then the output is stretched to match the new aspect ratio. + /// Stretch, + + /// + /// Passing a single dimension will automatically preserve the aspect ratio of the original image. If the requested aspect ratio is different then the image will be padded to fit. + /// Pad, + + /// + /// When upscaling an image the image pixels themselves are not resized, rather the image is padded to fit the given dimensions. + /// BoxPad, + + /// + /// Resizes the image until the shortest side reaches the set given dimension. This will maintain the aspect ratio of the original image. Upscaling is disabled in this mode and the original image will be returned if attempted. + /// Min } } From df2ee8e3e1bef9a5ee3414b75151d8de1f38adec Mon Sep 17 00:00:00 2001 From: Poornima Nayar Date: Wed, 10 Oct 2018 10:21:02 +0100 Subject: [PATCH 58/98] Moved the css rules for the rollback modal to a new stylesheet --- src/Umbraco.Web.UI.Client/src/less/belle.less | 373 +++++++-------- .../src/less/legacydialog.less | 58 +++ .../src/less/modals.less | 451 ++++++++---------- 3 files changed, 442 insertions(+), 440 deletions(-) create mode 100644 src/Umbraco.Web.UI.Client/src/less/legacydialog.less diff --git a/src/Umbraco.Web.UI.Client/src/less/belle.less b/src/Umbraco.Web.UI.Client/src/less/belle.less index eaf0b60707..7f10c3d4d7 100644 --- a/src/Umbraco.Web.UI.Client/src/less/belle.less +++ b/src/Umbraco.Web.UI.Client/src/less/belle.less @@ -1,186 +1,187 @@ - -// Core variables and mixins -@import "fonts.less"; // Loading fonts -@import "variables.less"; // Modify this for custom colors, font-sizes, etc -@import "mixins.less"; - -// CSS Reset -@import "../../lib/bootstrap/less/reset.less"; - -// Grid system and page structure -@import "../../lib/bootstrap/less/scaffolding.less"; -@import "../../lib/bootstrap/less/grid.less"; -@import "../../lib/bootstrap/less/layouts.less"; - -// Base CSS -@import "../../lib/bootstrap/less/type.less"; -@import "../../lib/bootstrap/less/code.less"; -@import "tables.less"; - - -// Components: common -@import "../../lib/bootstrap/less/dropdowns.less"; -@import "../../lib/bootstrap/less/wells.less"; -@import "../../lib/bootstrap/less/component-animations.less"; -@import "../../lib/bootstrap/less/close.less"; - -// Components: Buttons & Alerts -@import "../../lib/bootstrap/less/button-groups.less"; -@import "alerts.less"; // Note: alerts share common CSS with buttons and thus have styles in buttons.less - -// Components: Nav -@import "navs.less"; -@import "../../lib/bootstrap/less/navbar.less"; -@import "../../lib/bootstrap/less/breadcrumbs.less"; -@import "../../lib/bootstrap/less/pagination.less"; -@import "../../lib/bootstrap/less/pager.less"; - -// Components: Popovers -@import "../../lib/bootstrap/less/modals.less"; -@import "../../lib/bootstrap/less/tooltip.less"; -@import "../../lib/bootstrap/less/popovers.less"; -@import "tipmenu.less"; - -// Components: Misc -@import "../../lib/bootstrap/less/thumbnails.less"; -@import "../../lib/bootstrap/less/media.less"; -@import "../../lib/bootstrap/less/labels-badges.less"; -@import "../../lib/bootstrap/less/progress-bars.less"; -@import "../../lib/bootstrap/less/accordion.less"; -@import "../../lib/bootstrap/less/carousel.less"; -@import "../../lib/bootstrap/less/hero-unit.less"; - - -// Utility classes -@import "../../lib/bootstrap/less/utilities.less"; // Has to be last to override when necessary - - -// Application wide styles (refactor is WIP) -@import "application/grid.less"; -@import "application/shadows.less"; -@import "application/animations.less"; - -// Utilities -@import "utilities/_font-weight.less"; - -// Belle styles -@import "buttons.less"; -@import "forms.less"; -@import "modals.less"; -@import "panel.less"; -@import "sections.less"; -@import "helveticons.less"; -@import "main.less"; -@import "tree.less"; -@import "listview.less"; -@import "gridview.less"; -@import "footer.less"; -@import "dragdrop.less"; -@import "dashboards.less"; - -@import "forms/umb-validation-label.less"; - -// Umbraco Components -@import "components/application/umb-tour.less"; -@import "components/application/umb-backdrop.less"; -@import "components/application/umb-drawer.less"; - -@import "components/editor.less"; -@import "components/overlays.less"; -@import "components/card.less"; -@import "components/umb-sub-views.less"; -@import "components/umb-editor-navigation.less"; -@import "components/umb-editor-sub-views.less"; -@import "components/editor/subheader/umb-editor-sub-header.less"; -@import "components/umb-grid-selector.less"; -@import "components/umb-child-selector.less"; -@import "components/umb-group-builder.less"; -@import "components/umb-list-view-settings.less"; -@import "components/umb-table.less"; -@import "components/umb-confirm-action.less"; -@import "components/umb-keyboard-shortcuts-overview.less"; -@import "components/umb-checkbox-list.less"; -@import "components/umb-locked-field.less"; -@import "components/umb-tabs.less"; -@import "components/umb-load-indicator.less"; -@import "components/umb-breadcrumbs.less"; -@import "components/umb-media-grid.less"; -@import "components/umb-folder-grid.less"; -@import "components/umb-content-grid.less"; -@import "components/umb-layout-selector.less"; -@import "components/tooltip/umb-tooltip.less"; -@import "components/tooltip/umb-tooltip-list.less"; -@import "components/overlays/umb-overlay-backdrop.less"; -@import "components/umb-grid.less"; -@import "components/umb-empty-state.less"; -@import "components/umb-property-editor.less"; -@import "components/umb-color-swatches.less"; -@import "components/check-circle.less"; -@import "components/umb-iconpicker.less"; -@import "components/umb-insert-code-box.less"; -@import "components/umb-packages.less"; -@import "components/umb-package-local-install.less"; -@import "components/umb-lightbox.less"; -@import "components/umb-avatar.less"; -@import "components/umb-progress-bar.less"; -@import "components/umb-querybuilder.less"; -@import "components/umb-pagination.less"; -@import "components/umb-mini-list-view.less"; -@import "components/umb-multiple-textbox.less"; -@import "components/umb-badge.less"; -@import "components/umb-nested-content.less"; -@import "components/umb-checkmark.less"; -@import "components/umb-list.less"; -@import "components/umb-box.less"; -@import "components/umb-number-badge.less"; -@import "components/umb-progress-circle.less"; - -@import "components/buttons/umb-button.less"; -@import "components/buttons/umb-button-group.less"; -@import "components/buttons/umb-era-button.less"; -@import "components/buttons/umb-toggle.less"; - -@import "components/notifications/umb-notifications.less"; -@import "components/umb-file-dropzone.less"; -@import "components/umb-node-preview.less"; -@import "components/umb-mini-editor.less"; - -@import "components/users/umb-user-cards.less"; -@import "components/users/umb-user-details.less"; -@import "components/users/umb-user-group-picker-list.less"; -@import "components/users/umb-user-group-preview.less"; -@import "components/users/umb-user-preview.less"; -@import "components/users/umb-user-picker-list.less"; -@import "components/users/umb-permission.less"; - - -// Utilities -@import "utilities/layout/_display.less"; -@import "utilities/typography/_text-decoration.less"; -@import "utilities/typography/_white-space.less"; -@import "utilities/_flexbox.less"; -@import "utilities/_spacing.less"; -@import "utilities/_text-align.less"; -@import "utilities/_width.less"; - -//page specific styles -@import "pages/document-type-editor.less"; -@import "pages/login.less"; -@import "pages/welcome-dashboard.less"; - - -//used for property editors -@import "property-editors.less"; - -//used for prevalue editors -@import "components/prevalues/multivalues.less"; - - -@import "typeahead.less"; -@import "hacks.less"; - -@import "healthcheck.less"; -@import "getstarted.less"; - -// cleanup properties.less when it is done -@import "properties.less"; + +// Core variables and mixins +@import "fonts.less"; // Loading fonts +@import "variables.less"; // Modify this for custom colors, font-sizes, etc +@import "mixins.less"; + +// CSS Reset +@import "../../lib/bootstrap/less/reset.less"; + +// Grid system and page structure +@import "../../lib/bootstrap/less/scaffolding.less"; +@import "../../lib/bootstrap/less/grid.less"; +@import "../../lib/bootstrap/less/layouts.less"; + +// Base CSS +@import "../../lib/bootstrap/less/type.less"; +@import "../../lib/bootstrap/less/code.less"; +@import "tables.less"; + + +// Components: common +@import "../../lib/bootstrap/less/dropdowns.less"; +@import "../../lib/bootstrap/less/wells.less"; +@import "../../lib/bootstrap/less/component-animations.less"; +@import "../../lib/bootstrap/less/close.less"; + +// Components: Buttons & Alerts +@import "../../lib/bootstrap/less/button-groups.less"; +@import "alerts.less"; // Note: alerts share common CSS with buttons and thus have styles in buttons.less + +// Components: Nav +@import "navs.less"; +@import "../../lib/bootstrap/less/navbar.less"; +@import "../../lib/bootstrap/less/breadcrumbs.less"; +@import "../../lib/bootstrap/less/pagination.less"; +@import "../../lib/bootstrap/less/pager.less"; + +// Components: Popovers +@import "../../lib/bootstrap/less/modals.less"; +@import "../../lib/bootstrap/less/tooltip.less"; +@import "../../lib/bootstrap/less/popovers.less"; +@import "tipmenu.less"; + +// Components: Misc +@import "../../lib/bootstrap/less/thumbnails.less"; +@import "../../lib/bootstrap/less/media.less"; +@import "../../lib/bootstrap/less/labels-badges.less"; +@import "../../lib/bootstrap/less/progress-bars.less"; +@import "../../lib/bootstrap/less/accordion.less"; +@import "../../lib/bootstrap/less/carousel.less"; +@import "../../lib/bootstrap/less/hero-unit.less"; + + +// Utility classes +@import "../../lib/bootstrap/less/utilities.less"; // Has to be last to override when necessary + + +// Application wide styles (refactor is WIP) +@import "application/grid.less"; +@import "application/shadows.less"; +@import "application/animations.less"; + +// Utilities +@import "utilities/_font-weight.less"; + +// Belle styles +@import "buttons.less"; +@import "forms.less"; +@import "legacydialog.less"; +@import "modals.less"; +@import "panel.less"; +@import "sections.less"; +@import "helveticons.less"; +@import "main.less"; +@import "tree.less"; +@import "listview.less"; +@import "gridview.less"; +@import "footer.less"; +@import "dragdrop.less"; +@import "dashboards.less"; + +@import "forms/umb-validation-label.less"; + +// Umbraco Components +@import "components/application/umb-tour.less"; +@import "components/application/umb-backdrop.less"; +@import "components/application/umb-drawer.less"; + +@import "components/editor.less"; +@import "components/overlays.less"; +@import "components/card.less"; +@import "components/umb-sub-views.less"; +@import "components/umb-editor-navigation.less"; +@import "components/umb-editor-sub-views.less"; +@import "components/editor/subheader/umb-editor-sub-header.less"; +@import "components/umb-grid-selector.less"; +@import "components/umb-child-selector.less"; +@import "components/umb-group-builder.less"; +@import "components/umb-list-view-settings.less"; +@import "components/umb-table.less"; +@import "components/umb-confirm-action.less"; +@import "components/umb-keyboard-shortcuts-overview.less"; +@import "components/umb-checkbox-list.less"; +@import "components/umb-locked-field.less"; +@import "components/umb-tabs.less"; +@import "components/umb-load-indicator.less"; +@import "components/umb-breadcrumbs.less"; +@import "components/umb-media-grid.less"; +@import "components/umb-folder-grid.less"; +@import "components/umb-content-grid.less"; +@import "components/umb-layout-selector.less"; +@import "components/tooltip/umb-tooltip.less"; +@import "components/tooltip/umb-tooltip-list.less"; +@import "components/overlays/umb-overlay-backdrop.less"; +@import "components/umb-grid.less"; +@import "components/umb-empty-state.less"; +@import "components/umb-property-editor.less"; +@import "components/umb-color-swatches.less"; +@import "components/check-circle.less"; +@import "components/umb-iconpicker.less"; +@import "components/umb-insert-code-box.less"; +@import "components/umb-packages.less"; +@import "components/umb-package-local-install.less"; +@import "components/umb-lightbox.less"; +@import "components/umb-avatar.less"; +@import "components/umb-progress-bar.less"; +@import "components/umb-querybuilder.less"; +@import "components/umb-pagination.less"; +@import "components/umb-mini-list-view.less"; +@import "components/umb-multiple-textbox.less"; +@import "components/umb-badge.less"; +@import "components/umb-nested-content.less"; +@import "components/umb-checkmark.less"; +@import "components/umb-list.less"; +@import "components/umb-box.less"; +@import "components/umb-number-badge.less"; +@import "components/umb-progress-circle.less"; + +@import "components/buttons/umb-button.less"; +@import "components/buttons/umb-button-group.less"; +@import "components/buttons/umb-era-button.less"; +@import "components/buttons/umb-toggle.less"; + +@import "components/notifications/umb-notifications.less"; +@import "components/umb-file-dropzone.less"; +@import "components/umb-node-preview.less"; +@import "components/umb-mini-editor.less"; + +@import "components/users/umb-user-cards.less"; +@import "components/users/umb-user-details.less"; +@import "components/users/umb-user-group-picker-list.less"; +@import "components/users/umb-user-group-preview.less"; +@import "components/users/umb-user-preview.less"; +@import "components/users/umb-user-picker-list.less"; +@import "components/users/umb-permission.less"; + + +// Utilities +@import "utilities/layout/_display.less"; +@import "utilities/typography/_text-decoration.less"; +@import "utilities/typography/_white-space.less"; +@import "utilities/_flexbox.less"; +@import "utilities/_spacing.less"; +@import "utilities/_text-align.less"; +@import "utilities/_width.less"; + +//page specific styles +@import "pages/document-type-editor.less"; +@import "pages/login.less"; +@import "pages/welcome-dashboard.less"; + + +//used for property editors +@import "property-editors.less"; + +//used for prevalue editors +@import "components/prevalues/multivalues.less"; + + +@import "typeahead.less"; +@import "hacks.less"; + +@import "healthcheck.less"; +@import "getstarted.less"; + +// cleanup properties.less when it is done +@import "properties.less"; diff --git a/src/Umbraco.Web.UI.Client/src/less/legacydialog.less b/src/Umbraco.Web.UI.Client/src/less/legacydialog.less new file mode 100644 index 0000000000..ca920d22c2 --- /dev/null +++ b/src/Umbraco.Web.UI.Client/src/less/legacydialog.less @@ -0,0 +1,58 @@ + +.umb-dialog .propertyItemheader { + width: 140px !Important; +} + +.umb-dialog .diffDropdown { + width: 400px; +} + +.umb-dialog .diffPanel { + height: 400px; +} + + +.umb-dialog .diff { + margin-top: 10px; + height: 100%; + overflow: auto; + border-top: 1px solid #ccc; + border-top: 1px solid #ccc; + padding: 5px; +} + +.umb-dialog .diff table { + width: 95%; + max-width: 95%; + margin: 0 3px; +} + +.umb-dialog .diff table th { + padding: 5px; + width: 25%; + border-bottom: 1px solid #ccc; +} + +.umb-dialog .diff table td { + border-bottom: 1px solid #ccc; + padding: 3px; +} + +.umb-dialog .diff del { + background: rgb(255, 230, 230) none repeat scroll 0%; + -moz-background-clip: -moz-initial; + -moz-background-origin: -moz-initial; + -moz-background-inline-policy: -moz-initial; +} + +.umb-dialog .diff ins { + background: rgb(230, 255, 230) none repeat scroll 0%; + -moz-background-clip: -moz-initial; + -moz-background-origin: -moz-initial; + -moz-background-inline-policy: -moz-initial; +} + +.umb-dialog .diff .diffnotice { + text-align: center; + margin-bottom: 10px; +} diff --git a/src/Umbraco.Web.UI.Client/src/less/modals.less b/src/Umbraco.Web.UI.Client/src/less/modals.less index d8f188dd53..48a79d01b0 100644 --- a/src/Umbraco.Web.UI.Client/src/less/modals.less +++ b/src/Umbraco.Web.UI.Client/src/less/modals.less @@ -1,254 +1,197 @@ -/* Modals -// -------------------------*/ - -/* Modalcolumn is used for menu panels */ -.umb-modalcolumn { - background: @white; -} - -.umb-modalcolumn-header { - background: @gray-10; - border-bottom: 1px solid @purple-l3; - height: 94px; - padding: 5px 20px 0px 20px; - white-space: nowrap -} - -.umb-modalcolumn-header h1{ - margin: 0; - white-space: nowrap; - font-size: @fontSizeLarge; - font-weight: 400; - padding-top: 10px !important; -} - -.umb-modalcolumn-body { - padding: 0px; - background: @white; - top: 100px; - position: absolute; - left: 0px; - right: 0px; - bottom: 0px; - overflow: auto; -} - -.no-padding .umb-modalcolumn-body { - padding: 0px -} - -.umb-modalcolumn .umb-modalcolumn-header .btn { - position: absolute; - top: 13px; - right: 15px -} - -.umb-modalcolumn iframe.auto-expand, .umb-modal iframe.auto-expand { - border: none; - padding: 0px; - margin: 0px; - top: 0px; - bottom: 0px; - left: 0px; - right: 0px; - position: absolute;; -} - -/* re-align loader */ -.umb-modal .umb-loader-wrapper, .umb-modalcolumn .umb-loader-wrapper, .umb-dialog .umb-loader-wrapper{ - position:relative; - margin: 20px -20px; -} - -.umb-modal-left .umb-panel-header .umb-headline, .umb-modal-left .umb-panel-header h1 { - width: auto; - padding-left: 0; -} - -/* umb.dialog is used for the dialogs on the conent tree*/ -.umb-dialog { - outline: none; - top: 0px; - left: 0px; - right: 0px; - bottom: 0px; - position: absolute; - padding: 0px; -} - -.umb-dialog .umb-btn-toolbar .umb-control-group{ - border: none; - padding: none; -} - -.umb-dialog-body{ - position: absolute; - overflow:auto; - top: 0px; - left: 0px; - right: 0px; - bottom: 52px; -} -.umb-dialog-body .umb-pane{margin-top: 15px;} - -.umb-dialog-footer{ - position: absolute; - overflow:auto; - text-align: right; - height: 32px; - left: 0px; - right: 0px; - bottom: 0px; - padding: 10px 20px; - margin: 0; - background: @gray-10; - border-top: 1px solid @purple-l3; -} - -.umb-dialog .propertyItemheader { - width: 140px !Important; -} - -.umb-dialog .diffDropdown -{ - width:400px; -} - -.umb-dialog .diffPanel { - height: 400px; -} - - -.umb-dialog .diff { - margin-top: 10px; - height: 100%; - overflow: auto; - border-top: 1px solid #ccc; - border-top: 1px solid #ccc; - padding: 5px; -} -.umb-dialog .diff table{ - width:95%; - max-width:95%; - margin: 0 3px; -} -.umb-dialog .diff table th { - padding: 5px; - width: 25%; - border-bottom: 1px solid #ccc; -} - -.umb-dialog .diff table td { - border-bottom: 1px solid #ccc; - padding: 3px; -} - -.umb-dialog .diff del { - background: rgb(255, 230, 230) none repeat scroll 0%; - -moz-background-clip: -moz-initial; - -moz-background-origin: -moz-initial; - -moz-background-inline-policy: -moz-initial; -} - -.umb-dialog .diff ins { - background: rgb(230, 255, 230) none repeat scroll 0%; - -moz-background-clip: -moz-initial; - -moz-background-origin: -moz-initial; - -moz-background-inline-policy: -moz-initial; -} - -.umb-dialog .diff .diffnotice { - text-align: center; - margin-bottom: 10px; -} - -/*we will always make sure to wrap iframe dialogs in proper padding*/ -.umbracoDialog{ - width: auto !Important; - height: auto !Important; - padding: 20px; -} -.umbracoDialog .umb-pane{margin-left: 0px; margin-right: 0px; margin-top: 0px;} -.umbracoDialog .umb-dialog-body .umb-pane{margin-left: 20px; margin-right: 20px; margin-top: 20px;} -.umbracoDialog form{height: 100%;} - -/*ensures dialogs doesnt have side-by-side labels*/ -.umbracoDialog .controls-row, -.umb-modal .controls-row{margin-left: 0px !important;} - -/* modal and umb-modal are used for right.hand dialogs */ -.modal { - border-radius: 0 !important; - - &.fade.in{border: none !important;} -} -.umb-modal.fade { - outline: none; - top: 0 !important; - left: -100% !important; - width: 0px !important; - -webkit-transition: left 0.3s linear, left 0.3s ease-out; - -moz-transition: opacity 0.3s linear, top 0.3s ease-out; - -o-transition: opacity 0.3s linear, top 0.3s ease-out; - transition: opacity 0.3s linear, top 0.3s ease-out; - height: 100% !important; -} - -.umb-modal.fade.in { - top: 0 !important; - left: 100% !important; - margin-left: -440px; - width: 440px !important; - height: 100% !important; - display: block; -} - -.umb-modal-left.fade { - top: 0 !important; - left: -100% !important; - width: 0px !important; - -webkit-transition: left 0.3s linear, left 0.3s ease-out; - -moz-transition: opacity 0.3s linear, top 0.3s ease-out; - -o-transition: opacity 0.3s linear, top 0.3s ease-out; - transition: opacity 0.3s linear, top 0.3s ease-out; - height: 100% !important; -} -.umb-modal-left.fade.in { - top: 0 !important; - left: 0 !important; - margin-left: 80px; - width: 440px !important; - height: 100% !important; - display: block; -} - -/*Modal default panel styles*/ -.umb-modal .umb-panel-header { - padding: 20px; - background: @white; - border: none; - height: auto; -} -.umb-modal .umb-panel-body{ - padding: 0px 20px 0px 20px; -} - -.umb-modal.fade.in.wide { - margin-left: -640px; - width: 640px !important; -} -.umb-modal i { - font-size: 20px; -} -.umb-modal .breadcrumb { - background: none; - padding: 0 -} - -.umb-modal .breadcrumb input { - height: 12px -} - -.umb-modal.ysod { - z-index: 10000; -} +/* Modals +// -------------------------*/ + +/* Modalcolumn is used for menu panels */ +.umb-modalcolumn { + background: @white; +} + +.umb-modalcolumn-header { + background: @gray-10; + border-bottom: 1px solid @purple-l3; + height: 94px; + padding: 5px 20px 0px 20px; + white-space: nowrap +} + +.umb-modalcolumn-header h1{ + margin: 0; + white-space: nowrap; + font-size: @fontSizeLarge; + font-weight: 400; + padding-top: 10px !important; +} + +.umb-modalcolumn-body { + padding: 0px; + background: @white; + top: 100px; + position: absolute; + left: 0px; + right: 0px; + bottom: 0px; + overflow: auto; +} + +.no-padding .umb-modalcolumn-body { + padding: 0px +} + +.umb-modalcolumn .umb-modalcolumn-header .btn { + position: absolute; + top: 13px; + right: 15px +} + +.umb-modalcolumn iframe.auto-expand, .umb-modal iframe.auto-expand { + border: none; + padding: 0px; + margin: 0px; + top: 0px; + bottom: 0px; + left: 0px; + right: 0px; + position: absolute;; +} + +/* re-align loader */ +.umb-modal .umb-loader-wrapper, .umb-modalcolumn .umb-loader-wrapper, .umb-dialog .umb-loader-wrapper{ + position:relative; + margin: 20px -20px; +} + +.umb-modal-left .umb-panel-header .umb-headline, .umb-modal-left .umb-panel-header h1 { + width: auto; + padding-left: 0; +} + +/* umb.dialog is used for the dialogs on the conent tree*/ +.umb-dialog { + outline: none; + top: 0px; + left: 0px; + right: 0px; + bottom: 0px; + position: absolute; + padding: 0px; +} + +.umb-dialog .umb-btn-toolbar .umb-control-group{ + border: none; + padding: none; +} + +.umb-dialog-body{ + position: absolute; + overflow:auto; + top: 0px; + left: 0px; + right: 0px; + bottom: 52px; +} +.umb-dialog-body .umb-pane{margin-top: 15px;} + +.umb-dialog-footer{ + position: absolute; + overflow:auto; + text-align: right; + height: 32px; + left: 0px; + right: 0px; + bottom: 0px; + padding: 10px 20px; + margin: 0; + background: @gray-10; + border-top: 1px solid @purple-l3; +} + +/*we will always make sure to wrap iframe dialogs in proper padding*/ +.umbracoDialog{ + width: auto !Important; + height: auto !Important; + padding: 20px; +} +.umbracoDialog .umb-pane{margin-left: 0px; margin-right: 0px; margin-top: 0px;} +.umbracoDialog .umb-dialog-body .umb-pane{margin-left: 20px; margin-right: 20px; margin-top: 20px;} +.umbracoDialog form{height: 100%;} + +/*ensures dialogs doesnt have side-by-side labels*/ +.umbracoDialog .controls-row, +.umb-modal .controls-row{margin-left: 0px !important;} + +/* modal and umb-modal are used for right.hand dialogs */ +.modal { + border-radius: 0 !important; + + &.fade.in{border: none !important;} +} +.umb-modal.fade { + outline: none; + top: 0 !important; + left: -100% !important; + width: 0px !important; + -webkit-transition: left 0.3s linear, left 0.3s ease-out; + -moz-transition: opacity 0.3s linear, top 0.3s ease-out; + -o-transition: opacity 0.3s linear, top 0.3s ease-out; + transition: opacity 0.3s linear, top 0.3s ease-out; + height: 100% !important; +} + +.umb-modal.fade.in { + top: 0 !important; + left: 100% !important; + margin-left: -440px; + width: 440px !important; + height: 100% !important; + display: block; +} + +.umb-modal-left.fade { + top: 0 !important; + left: -100% !important; + width: 0px !important; + -webkit-transition: left 0.3s linear, left 0.3s ease-out; + -moz-transition: opacity 0.3s linear, top 0.3s ease-out; + -o-transition: opacity 0.3s linear, top 0.3s ease-out; + transition: opacity 0.3s linear, top 0.3s ease-out; + height: 100% !important; +} +.umb-modal-left.fade.in { + top: 0 !important; + left: 0 !important; + margin-left: 80px; + width: 440px !important; + height: 100% !important; + display: block; +} + +/*Modal default panel styles*/ +.umb-modal .umb-panel-header { + padding: 20px; + background: @white; + border: none; + height: auto; +} +.umb-modal .umb-panel-body{ + padding: 0px 20px 0px 20px; +} + +.umb-modal.fade.in.wide { + margin-left: -640px; + width: 640px !important; +} +.umb-modal i { + font-size: 20px; +} +.umb-modal .breadcrumb { + background: none; + padding: 0 +} + +.umb-modal .breadcrumb input { + height: 12px +} + +.umb-modal.ysod { + z-index: 10000; +} From a23901c07a748dce1d2e1ef372447b4ed1950cb5 Mon Sep 17 00:00:00 2001 From: Bjarne Fyrstenborg Date: Wed, 10 Oct 2018 00:58:32 +0200 Subject: [PATCH 59/98] Enable email address as macro parameter editor --- src/Umbraco.Web/PropertyEditors/EmailAddressPropertyEditor.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Umbraco.Web/PropertyEditors/EmailAddressPropertyEditor.cs b/src/Umbraco.Web/PropertyEditors/EmailAddressPropertyEditor.cs index 8d141fd1e9..8f01aa06f0 100644 --- a/src/Umbraco.Web/PropertyEditors/EmailAddressPropertyEditor.cs +++ b/src/Umbraco.Web/PropertyEditors/EmailAddressPropertyEditor.cs @@ -3,7 +3,7 @@ using Umbraco.Core.PropertyEditors; namespace Umbraco.Web.PropertyEditors { - [PropertyEditor(Constants.PropertyEditors.EmailAddressAlias, "Email address", "email", Icon="icon-message")] + [PropertyEditor(Constants.PropertyEditors.EmailAddressAlias, "Email address", "email", IsParameterEditor = true, Icon ="icon-message")] public class EmailAddressPropertyEditor : PropertyEditor { protected override PropertyValueEditor CreateValueEditor() @@ -28,4 +28,4 @@ namespace Umbraco.Web.PropertyEditors } } -} \ No newline at end of file +} From 25d9e432c320226b2a6a9fce04ee91fd5edeccc2 Mon Sep 17 00:00:00 2001 From: Bjarne Fyrstenborg Date: Wed, 10 Oct 2018 01:12:33 +0200 Subject: [PATCH 60/98] Remove space --- src/Umbraco.Web/PropertyEditors/EmailAddressPropertyEditor.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Umbraco.Web/PropertyEditors/EmailAddressPropertyEditor.cs b/src/Umbraco.Web/PropertyEditors/EmailAddressPropertyEditor.cs index 8f01aa06f0..f03b58e005 100644 --- a/src/Umbraco.Web/PropertyEditors/EmailAddressPropertyEditor.cs +++ b/src/Umbraco.Web/PropertyEditors/EmailAddressPropertyEditor.cs @@ -3,7 +3,7 @@ using Umbraco.Core.PropertyEditors; namespace Umbraco.Web.PropertyEditors { - [PropertyEditor(Constants.PropertyEditors.EmailAddressAlias, "Email address", "email", IsParameterEditor = true, Icon ="icon-message")] + [PropertyEditor(Constants.PropertyEditors.EmailAddressAlias, "Email address", "email", IsParameterEditor = true, Icon="icon-message")] public class EmailAddressPropertyEditor : PropertyEditor { protected override PropertyValueEditor CreateValueEditor() From 8036af958f7216368235cd6f4d3ad173c14970b1 Mon Sep 17 00:00:00 2001 From: Kenn Jacobsen Date: Fri, 19 Oct 2018 14:19:47 +0200 Subject: [PATCH 61/98] Allow video feeds to load over HTTPS + fix a few feeds (#3256) --- .../dashboard/media/mediadashboardvideos.html | 26 ++++++++++--------- .../members/membersdashboardvideos.html | 24 +++++++++-------- .../settings/settingsdashboardvideos.html | 26 ++++++++++--------- .../umbraco/dashboard/FeedProxy.aspx.cs | 2 +- 4 files changed, 42 insertions(+), 36 deletions(-) diff --git a/src/Umbraco.Web.UI.Client/src/views/dashboard/media/mediadashboardvideos.html b/src/Umbraco.Web.UI.Client/src/views/dashboard/media/mediadashboardvideos.html index ec55790bd9..5f315a047d 100644 --- a/src/Umbraco.Web.UI.Client/src/views/dashboard/media/mediadashboardvideos.html +++ b/src/Umbraco.Web.UI.Client/src/views/dashboard/media/mediadashboardvideos.html @@ -1,18 +1,20 @@

Hours of Umbraco training videos are only a click away

Want to master Umbraco? Spend a couple of minutes learning some best practices by watching one of these videos about using Umbraco. And visit umbraco.tv for even more Umbraco videos

-

To get you started:

- -
\ No newline at end of file +
+

To get you started:

+ +
+
diff --git a/src/Umbraco.Web.UI.Client/src/views/dashboard/members/membersdashboardvideos.html b/src/Umbraco.Web.UI.Client/src/views/dashboard/members/membersdashboardvideos.html index f04aff24c1..9889d5a063 100644 --- a/src/Umbraco.Web.UI.Client/src/views/dashboard/members/membersdashboardvideos.html +++ b/src/Umbraco.Web.UI.Client/src/views/dashboard/members/membersdashboardvideos.html @@ -1,18 +1,20 @@

Hours of Umbraco training videos are only a click away

Want to master Umbraco? Spend a couple of minutes learning some best practices by watching one of these videos about using Umbraco. And visit umbraco.tv for even more Umbraco videos

-

To get you started:

- +
+

To get you started:

+ +
diff --git a/src/Umbraco.Web.UI.Client/src/views/dashboard/settings/settingsdashboardvideos.html b/src/Umbraco.Web.UI.Client/src/views/dashboard/settings/settingsdashboardvideos.html index ec55790bd9..5f315a047d 100644 --- a/src/Umbraco.Web.UI.Client/src/views/dashboard/settings/settingsdashboardvideos.html +++ b/src/Umbraco.Web.UI.Client/src/views/dashboard/settings/settingsdashboardvideos.html @@ -1,18 +1,20 @@

Hours of Umbraco training videos are only a click away

Want to master Umbraco? Spend a couple of minutes learning some best practices by watching one of these videos about using Umbraco. And visit umbraco.tv for even more Umbraco videos

-

To get you started:

- -
\ No newline at end of file +
+

To get you started:

+ +
+
diff --git a/src/Umbraco.Web/umbraco.presentation/umbraco/dashboard/FeedProxy.aspx.cs b/src/Umbraco.Web/umbraco.presentation/umbraco/dashboard/FeedProxy.aspx.cs index 49539b0264..2d2b0ec66c 100644 --- a/src/Umbraco.Web/umbraco.presentation/umbraco/dashboard/FeedProxy.aspx.cs +++ b/src/Umbraco.Web/umbraco.presentation/umbraco/dashboard/FeedProxy.aspx.cs @@ -30,7 +30,7 @@ namespace dashboardUtilities return; var feedProxyXml = XmlHelper.OpenAsXmlDocument(IOHelper.MapPath(SystemFiles.FeedProxyConfig)); - if (feedProxyXml?.SelectSingleNode($"//allow[@host = '{requestUri.Host}']") != null && requestUri.Port == 80) + if (feedProxyXml?.SelectSingleNode($"//allow[@host = '{requestUri.Host}']") != null && (requestUri.Port == 80 || requestUri.Port == 443)) { if (_httpClient == null) _httpClient = new HttpClient(); From d9efc2a40164ea28674ebc0c06dd72c5fb97b042 Mon Sep 17 00:00:00 2001 From: Pritesh Tailor Date: Sun, 14 Oct 2018 14:48:36 +0100 Subject: [PATCH 62/98] Fixed broken link in detailed contrib doc The link to the the issues was broken (Your first code code contribution section). I've updated to the readonly issue tracker and added a reference to new issue tracker. Removed a line on upvotes, as i don't believe that's relevant anymore. --- .github/CONTRIBUTING_DETAILED.md | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/.github/CONTRIBUTING_DETAILED.md b/.github/CONTRIBUTING_DETAILED.md index 3b42ba4e4c..a07539da6a 100644 --- a/.github/CONTRIBUTING_DETAILED.md +++ b/.github/CONTRIBUTING_DETAILED.md @@ -69,9 +69,7 @@ Some additional hints that may be helpful: ### Your First Code Contribution -Unsure where to begin contributing to Umbraco? You can start by looking through [these `Up for grabs` and issues](http://issues.umbraco.org/issues/U4?q=%28project%3A+%7BU4%7D+Difficulty%3A+%7BVery+Easy%7D+%23Easy+%23Unresolved+Priority%3A+Normal+%23Major+%23Show-stopper+State%3A+-%7BIn+Progress%7D+sort+by%3A+votes+Affected+versions%3A+-6.*+Affected+versions%3A+-4.*%29+OR+%28tag%3A+%7BUp+For+Grabs%7D+%23Unresolved+%29). - -The issue list is sorted by total number of upvotes. While not perfect, number of upvotes is a reasonable proxy for impact a given change will have. +Unsure where to begin contributing to Umbraco? You can start by looking through [these `Up for grabs` and issues](https://issues.umbraco.org/issues?q=&project=U4&tagValue=upforgrabs&release=&issueType=&search=search) or on the [new issue tracker](https://github.com/umbraco/Umbraco-CMS/issues?q=is%3Aopen+is%3Aissue+label%3Acommunity%2Fup-for-grabs). ### Pull Requests From c5ea0ea3a932dbfdc5d4969606987c78fd985404 Mon Sep 17 00:00:00 2001 From: Andy Robinson Date: Sun, 14 Oct 2018 17:52:29 +0100 Subject: [PATCH 63/98] fixing issue in #3292 --- src/Umbraco.Web.UI.Client/src/less/components/card.less | 1 + 1 file changed, 1 insertion(+) diff --git a/src/Umbraco.Web.UI.Client/src/less/components/card.less b/src/Umbraco.Web.UI.Client/src/less/components/card.less index ecbd36e1e4..0c6ec16a8f 100644 --- a/src/Umbraco.Web.UI.Client/src/less/components/card.less +++ b/src/Umbraco.Web.UI.Client/src/less/components/card.less @@ -107,6 +107,7 @@ .umb-card-grid li.-three-in-row { flex: 0 0 33.33%; + max-width:33.33%; } .umb-card-grid .umb-card-grid-item { From 6b90d62bd17a79bc7b7960957a7ffdd9bef92098 Mon Sep 17 00:00:00 2001 From: Andy Robinson Date: Mon, 15 Oct 2018 08:29:58 +0100 Subject: [PATCH 64/98] update to issue #3292 to fix 4 col grid cards. --- src/Umbraco.Web.UI.Client/src/less/components/card.less | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/Umbraco.Web.UI.Client/src/less/components/card.less b/src/Umbraco.Web.UI.Client/src/less/components/card.less index 0c6ec16a8f..43327bb94f 100644 --- a/src/Umbraco.Web.UI.Client/src/less/components/card.less +++ b/src/Umbraco.Web.UI.Client/src/less/components/card.less @@ -102,7 +102,8 @@ } .umb-card-grid li.-four-in-row { - flex: 0 0 25%; + flex: 0 0 25%; + max-width: 25%; } .umb-card-grid li.-three-in-row { From d95ec9eb147bd6594d5031c63baf9f0b01438f0f Mon Sep 17 00:00:00 2001 From: fer22f Date: Mon, 15 Oct 2018 23:19:58 -0300 Subject: [PATCH 65/98] Fix documentation of container styling of nodes --- src/Umbraco.Web/Models/Trees/TreeNodeExtensions.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Umbraco.Web/Models/Trees/TreeNodeExtensions.cs b/src/Umbraco.Web/Models/Trees/TreeNodeExtensions.cs index ec95098f7b..c26e8be51e 100644 --- a/src/Umbraco.Web/Models/Trees/TreeNodeExtensions.cs +++ b/src/Umbraco.Web/Models/Trees/TreeNodeExtensions.cs @@ -15,7 +15,7 @@ } /// - /// Sets the node style to show that it is currently protected publicly + /// Sets the node style to show that it is a container type /// /// public static void SetContainerStyle(this TreeNode treeNode) From ecf9c0adb47160d590d628360e9ccbd8ce3ee0c4 Mon Sep 17 00:00:00 2001 From: Mike Chambers Date: Thu, 11 Oct 2018 10:13:47 +0100 Subject: [PATCH 66/98] Update datepickerController to add onValueChanged function adding onValueChanged method to capture serverside Model Changes, clearing flag using c# System.DateTime.MinValue. --- .../datepicker/datepicker.controller.js | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/src/Umbraco.Web.UI.Client/src/views/propertyeditors/datepicker/datepicker.controller.js b/src/Umbraco.Web.UI.Client/src/views/propertyeditors/datepicker/datepicker.controller.js index 1e0493e8f1..70c6bb4531 100644 --- a/src/Umbraco.Web.UI.Client/src/views/propertyeditors/datepicker/datepicker.controller.js +++ b/src/Umbraco.Web.UI.Client/src/views/propertyeditors/datepicker/datepicker.controller.js @@ -38,6 +38,22 @@ function dateTimePickerController($scope, notificationsService, assetsService, a }; $(document).bind("click", $scope.hidePicker); + //here we declare a special method which will be called whenever the value has changed from the server + //this is instead of doing a watch on the model.value = faster + $scope.model.onValueChanged = function (newVal, oldVal) { + if (newVal != oldVal) { + //check for c# System.DateTime.MinValue being passed as the clear indicator + var minDate = moment('0001-01-01'); + var newDate = moment(newVal); + + if (newDate.isAfter(minDate)) { + applyDate({ date: moment(newVal) }); + } else { + $scope.clearDate(); + } + } + }; + //handles the date changing via the api function applyDate(e) { angularHelper.safeApply($scope, function() { From 201a2cd7b1bdd4d9c40e33c23df681983bd73e39 Mon Sep 17 00:00:00 2001 From: Ed Parry Date: Fri, 19 Oct 2018 14:13:07 +0100 Subject: [PATCH 67/98] Added the user ID and GUID to the user details view. (#3279) --- .../idwithguid/idwithguid.controller.js | 25 +++++++++++++++++++ .../idwithguid/idwithguid.html | 4 +++ .../src/views/users/views/user/details.html | 14 ++++++++++- src/Umbraco.Web.UI/umbraco/config/lang/da.xml | 1 + src/Umbraco.Web.UI/umbraco/config/lang/en.xml | 1 + .../umbraco/config/lang/en_us.xml | 1 + .../Models/Mapping/MemberModelMapper.cs | 8 +++++- 7 files changed, 52 insertions(+), 2 deletions(-) create mode 100644 src/Umbraco.Web.UI.Client/src/views/propertyeditors/idwithguid/idwithguid.controller.js create mode 100644 src/Umbraco.Web.UI.Client/src/views/propertyeditors/idwithguid/idwithguid.html diff --git a/src/Umbraco.Web.UI.Client/src/views/propertyeditors/idwithguid/idwithguid.controller.js b/src/Umbraco.Web.UI.Client/src/views/propertyeditors/idwithguid/idwithguid.controller.js new file mode 100644 index 0000000000..1402226f78 --- /dev/null +++ b/src/Umbraco.Web.UI.Client/src/views/propertyeditors/idwithguid/idwithguid.controller.js @@ -0,0 +1,25 @@ +/** + * @ngdoc controller + * @name Umbraco.Editors.IdWithGuidValueController + * @function + * + * @description + * The controller for the idwithguid property editor, which formats the ID as normal + * with the GUID in smaller text below, as used across the backoffice. +*/ +function IdWithGuidValueController($rootScope, $scope, $filter) { + + function formatDisplayValue() { + if ($scope.model.value.length > 1) { + $scope.displayid = $scope.model.value[0]; + $scope.displayguid = $scope.model.value[1]; + } else { + $scope.displayid = $scope.model.value; + } + } + + //format the display value on init: + formatDisplayValue(); +} + +angular.module('umbraco').controller("Umbraco.PropertyEditors.IdWithGuidValueController", IdWithGuidValueController); diff --git a/src/Umbraco.Web.UI.Client/src/views/propertyeditors/idwithguid/idwithguid.html b/src/Umbraco.Web.UI.Client/src/views/propertyeditors/idwithguid/idwithguid.html new file mode 100644 index 0000000000..a3d9970cd0 --- /dev/null +++ b/src/Umbraco.Web.UI.Client/src/views/propertyeditors/idwithguid/idwithguid.html @@ -0,0 +1,4 @@ +
+
{{ displayid }}
+ {{ displayguid }} +
diff --git a/src/Umbraco.Web.UI.Client/src/views/users/views/user/details.html b/src/Umbraco.Web.UI.Client/src/views/users/views/user/details.html index 15a75c30b2..d0acec1522 100644 --- a/src/Umbraco.Web.UI.Client/src/views/users/views/user/details.html +++ b/src/Umbraco.Web.UI.Client/src/views/users/views/user/details.html @@ -385,7 +385,19 @@
-
+
+
+ Id: +
+
+ {{ model.user.id }} +
+
+ {{ model.user.key }} +
+
+ +
diff --git a/src/Umbraco.Web.UI/umbraco/config/lang/da.xml b/src/Umbraco.Web.UI/umbraco/config/lang/da.xml index 2ce6a31786..e68365ddb8 100644 --- a/src/Umbraco.Web.UI/umbraco/config/lang/da.xml +++ b/src/Umbraco.Web.UI/umbraco/config/lang/da.xml @@ -564,6 +564,7 @@ Skjul Historik Ikon + Id Importer Indre margen Indsæt diff --git a/src/Umbraco.Web.UI/umbraco/config/lang/en.xml b/src/Umbraco.Web.UI/umbraco/config/lang/en.xml index 89ba5e0828..f1b415f3c5 100644 --- a/src/Umbraco.Web.UI/umbraco/config/lang/en.xml +++ b/src/Umbraco.Web.UI/umbraco/config/lang/en.xml @@ -597,6 +597,7 @@ Hide History Icon + Id Import Info Inner margin 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 a42d4d0c60..31d157f54c 100644 --- a/src/Umbraco.Web.UI/umbraco/config/lang/en_us.xml +++ b/src/Umbraco.Web.UI/umbraco/config/lang/en_us.xml @@ -597,6 +597,7 @@ Hide History Icon + Id Import Info Inner margin diff --git a/src/Umbraco.Web/Models/Mapping/MemberModelMapper.cs b/src/Umbraco.Web/Models/Mapping/MemberModelMapper.cs index 5b53f1ef8d..e7d048545d 100644 --- a/src/Umbraco.Web/Models/Mapping/MemberModelMapper.cs +++ b/src/Umbraco.Web/Models/Mapping/MemberModelMapper.cs @@ -328,11 +328,17 @@ namespace Umbraco.Web.Models.Mapping var genericProperties = new List { + new ContentPropertyDisplay + { + Alias = string.Format("{0}id", Constants.PropertyEditors.InternalGenericPropertiesPrefix), + Label = _localizedTextService.Localize("general/id"), + Value = new List {member.Id.ToString(), member.Key.ToString()}, + View = "idwithguid" + }, new ContentPropertyDisplay { Alias = string.Format("{0}doctype", Constants.PropertyEditors.InternalGenericPropertiesPrefix), Label = _localizedTextService.Localize("content/membertype"), - //Value = localizedText.UmbracoDictionaryTranslate(display.ContentTypeName), Value = _localizedTextService.UmbracoDictionaryTranslate(member.ContentType.Name), View = PropertyEditorResolver.Current.GetByAlias(Constants.PropertyEditors.NoEditAlias).ValueEditor.View }, From f993869482a5ee4dc671e69398eac96db7b52b7f Mon Sep 17 00:00:00 2001 From: Kenn Jacobsen Date: Tue, 16 Oct 2018 09:19:25 +0200 Subject: [PATCH 68/98] Remove the default SMTP configuration --- src/Umbraco.Core/Configuration/GlobalSettings.cs | 3 ++- src/Umbraco.Web.UI/web.Template.config | 5 +++++ 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/src/Umbraco.Core/Configuration/GlobalSettings.cs b/src/Umbraco.Core/Configuration/GlobalSettings.cs index 7b209a15cd..11e6b2595f 100644 --- a/src/Umbraco.Core/Configuration/GlobalSettings.cs +++ b/src/Umbraco.Core/Configuration/GlobalSettings.cs @@ -70,7 +70,8 @@ namespace Umbraco.Core.Configuration var config = WebConfigurationManager.OpenWebConfiguration(appPath); var settings = (MailSettingsSectionGroup)config.GetSectionGroup("system.net/mailSettings"); - if (settings == null || settings.Smtp == null) return false; + // note: "noreply@example.com" is/was the sample SMTP from email - we'll regard that as "not configured" + if (settings == null || settings.Smtp == null || "noreply@example.com".Equals(settings.Smtp.From, StringComparison.OrdinalIgnoreCase)) return false; if (settings.Smtp.SpecifiedPickupDirectory != null && string.IsNullOrEmpty(settings.Smtp.SpecifiedPickupDirectory.PickupDirectoryLocation) == false) return true; if (settings.Smtp.Network != null && string.IsNullOrEmpty(settings.Smtp.Network.Host) == false) diff --git a/src/Umbraco.Web.UI/web.Template.config b/src/Umbraco.Web.UI/web.Template.config index 10794e6aa2..84b398f7e2 100644 --- a/src/Umbraco.Web.UI/web.Template.config +++ b/src/Umbraco.Web.UI/web.Template.config @@ -80,9 +80,14 @@ + From 6996a06d64b270268267d655760e057fa82bfcd4 Mon Sep 17 00:00:00 2001 From: Rasmus John Pedersen Date: Thu, 11 Oct 2018 19:46:43 +0200 Subject: [PATCH 69/98] Only add "Move" action once --- .../Trees/ContentTypeTreeController.cs | 16 +++------------- 1 file changed, 3 insertions(+), 13 deletions(-) diff --git a/src/Umbraco.Web/Trees/ContentTypeTreeController.cs b/src/Umbraco.Web/Trees/ContentTypeTreeController.cs index 33ae50dbbf..1544e5d2d0 100644 --- a/src/Umbraco.Web/Trees/ContentTypeTreeController.cs +++ b/src/Umbraco.Web/Trees/ContentTypeTreeController.cs @@ -117,21 +117,11 @@ namespace Umbraco.Web.Trees if (enableInheritedDocumentTypes) { menu.Items.Add(Services.TextService.Localize(string.Format("actions/{0}", ActionNew.Instance.Alias))); - - //no move action if this is a child doc type - if (parent == null) - { - menu.Items.Add(Services.TextService.Localize(string.Format("actions/{0}", ActionMove.Instance.Alias)), true); - } } - else + //no move action if this is a child doc type + if (parent == null) { - menu.Items.Add(Services.TextService.Localize(string.Format("actions/{0}", ActionMove.Instance.Alias))); - //no move action if this is a child doc type - if (parent == null) - { - menu.Items.Add(Services.TextService.Localize(string.Format("actions/{0}", ActionMove.Instance.Alias)), true); - } + menu.Items.Add(Services.TextService.Localize(string.Format("actions/{0}", ActionMove.Instance.Alias)), true); } menu.Items.Add(Services.TextService.Localize(string.Format("actions/{0}", ActionCopy.Instance.Alias))); menu.Items.Add(Services.TextService.Localize(string.Format("actions/{0}", ActionExport.Instance.Alias)), true).ConvertLegacyMenuItem(new UmbracoEntity From 5dc67deeecde39a5f3fe5b6e70f485d45b5ca89d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=B8ren=20Kottal?= Date: Wed, 17 Oct 2018 11:22:55 +0200 Subject: [PATCH 70/98] adds the right description to UmbracoHelper.Concatenate --- src/Umbraco.Web/UmbracoHelper.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Umbraco.Web/UmbracoHelper.cs b/src/Umbraco.Web/UmbracoHelper.cs index b06b786104..bb9bd2d50e 100644 --- a/src/Umbraco.Web/UmbracoHelper.cs +++ b/src/Umbraco.Web/UmbracoHelper.cs @@ -1411,7 +1411,7 @@ namespace Umbraco.Web } /// - /// Will take the first non-null value in the collection and return the value of it. + /// Joins any number of int/string/objects into one string /// public string Concatenate(params object[] args) { From ef343f04a8e847a128e965733b34523819ab412d Mon Sep 17 00:00:00 2001 From: Rasmus John Pedersen Date: Thu, 11 Oct 2018 20:19:49 +0200 Subject: [PATCH 71/98] Only hide icons if hideIcons is set to 'true' --- .../src/views/components/buttons/umb-toggle.html | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Umbraco.Web.UI.Client/src/views/components/buttons/umb-toggle.html b/src/Umbraco.Web.UI.Client/src/views/components/buttons/umb-toggle.html index 670b6c64f2..bc5c114bb6 100644 --- a/src/Umbraco.Web.UI.Client/src/views/components/buttons/umb-toggle.html +++ b/src/Umbraco.Web.UI.Client/src/views/components/buttons/umb-toggle.html @@ -6,9 +6,9 @@
- +
- +
From 00cf8dcf05393e15f8a743763d8f9059f2a6979f Mon Sep 17 00:00:00 2001 From: Kenn Jacobsen Date: Thu, 11 Oct 2018 14:28:22 +0200 Subject: [PATCH 72/98] Reload the node when publishing all unpublished children --- .../lib/umbraco/LegacyUmbClientMgr.js | 3 ++- .../umbraco_client/Dialogs/PublishDialog.js | 13 ++++++++++--- 2 files changed, 12 insertions(+), 4 deletions(-) diff --git a/src/Umbraco.Web.UI.Client/lib/umbraco/LegacyUmbClientMgr.js b/src/Umbraco.Web.UI.Client/lib/umbraco/LegacyUmbClientMgr.js index 9fe887d0b6..223695322f 100644 --- a/src/Umbraco.Web.UI.Client/lib/umbraco/LegacyUmbClientMgr.js +++ b/src/Umbraco.Web.UI.Client/lib/umbraco/LegacyUmbClientMgr.js @@ -150,7 +150,8 @@ Umbraco.Sys.registerNamespace("Umbraco.Application"); sourceUrl: currentMenuNode.childNodesUrl, updateDefinition: function() { throw "'updateDefinition' method is not supported in Umbraco 7, consider upgrading to the new v7 APIs"; - } + }, + expanded: currentMenuNode.expanded === true }; //defined getters that will throw a not implemented/supported exception Object.defineProperty(legacyNode, "menu", { diff --git a/src/Umbraco.Web.UI/umbraco_client/Dialogs/PublishDialog.js b/src/Umbraco.Web.UI/umbraco_client/Dialogs/PublishDialog.js index d034a07a4a..1781f71b27 100644 --- a/src/Umbraco.Web.UI/umbraco_client/Dialogs/PublishDialog.js +++ b/src/Umbraco.Web.UI/umbraco_client/Dialogs/PublishDialog.js @@ -37,12 +37,13 @@ }, startPublish: function() { this.processStatus("publishing"); - + + var includeUnpublished = self._koViewModel.includeUnpublished(); $.post(self._opts.restServiceLocation + "PublishDocument", JSON.stringify({ documentId: self._opts.documentId, publishDescendants: self._koViewModel.publishAll(), - includeUnpublished: self._koViewModel.includeUnpublished() + includeUnpublished: includeUnpublished }), function (e) { self._koViewModel.processStatus("complete"); @@ -59,7 +60,13 @@ //sync the tree UmbClientMgr.mainTree().setActiveTreeType('content'); - UmbClientMgr.mainTree().syncTree(self._opts.documentPath, true); + UmbClientMgr.mainTree().syncTree(self._opts.documentPath, true) + if (includeUnpublished) { + var node = UmbClientMgr.mainTree().getActionNode(); + if (node.expanded === true) { + UmbClientMgr.mainTree().reloadActionNode(); + } + } }); } }; From 5efb079f5623cfafcd251498b013076bc60ba44d Mon Sep 17 00:00:00 2001 From: sebastien-sougnez Date: Thu, 18 Oct 2018 17:18:53 +0200 Subject: [PATCH 73/98] Changed font-awesome verison from 4.2 to 4.7 --- src/Umbraco.Web.UI.Client/bower.json | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/Umbraco.Web.UI.Client/bower.json b/src/Umbraco.Web.UI.Client/bower.json index 80d7d9366b..5f94ecf629 100644 --- a/src/Umbraco.Web.UI.Client/bower.json +++ b/src/Umbraco.Web.UI.Client/bower.json @@ -31,7 +31,7 @@ "moment": "~2.10.3", "ace-builds": "^1.2.3", "clipboard": "1.7.1", - "font-awesome": "~4.2" + "font-awesome": "~4.7" }, "install": { "path": "lib-bower", @@ -43,11 +43,11 @@ ], "sources": { "moment": [ - "bower_components/moment/min/moment.min.js", - "bower_components/moment/min/moment-with-locales.js", - "bower_components/moment/min/moment-with-locales.min.js", - "bower_components/moment/locale/*.js" - ], + "bower_components/moment/min/moment.min.js", + "bower_components/moment/min/moment-with-locales.js", + "bower_components/moment/min/moment-with-locales.min.js", + "bower_components/moment/locale/*.js" + ], "underscore": [ "bower_components/underscore/underscore-min.js", "bower_components/underscore/underscore-min.map" From f4a9617487fee6043966aa8510855e661ddca568 Mon Sep 17 00:00:00 2001 From: Anders Bjerner Date: Thu, 18 Oct 2018 19:35:59 +0200 Subject: [PATCH 74/98] Improved the description for the "Icon" property --- src/Umbraco.Core/Models/IContentTypeBase.cs | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/src/Umbraco.Core/Models/IContentTypeBase.cs b/src/Umbraco.Core/Models/IContentTypeBase.cs index 80e62f50cf..f1e10b03a2 100644 --- a/src/Umbraco.Core/Models/IContentTypeBase.cs +++ b/src/Umbraco.Core/Models/IContentTypeBase.cs @@ -21,7 +21,12 @@ namespace Umbraco.Core.Models string Description { get; set; } /// - /// Gets or Sets the Icon for the ContentType + /// Gets or sets the icon for the content type. The value is a CSS class name representing + /// the icon (eg. icon-home) along with an optional CSS class name representing the + /// color (eg. icon-blue). Put together, the value for this scenario would be + /// icon-home color-blue. + /// + /// If a class name for the color isn't specified, the icon color will default to black. /// string Icon { get; set; } @@ -119,4 +124,4 @@ namespace Umbraco.Core.Models /// bool MovePropertyType(string propertyTypeAlias, string propertyGroupName); } -} \ No newline at end of file +} From e1919e0c5253df9a6aa94df0df8a811499c80f35 Mon Sep 17 00:00:00 2001 From: Anders Bjerner Date: Sun, 21 Oct 2018 13:54:17 +0200 Subject: [PATCH 75/98] Added keys for "enterAlias" and "generatingAlias" --- src/Umbraco.Web.UI/umbraco/config/lang/en.xml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/Umbraco.Web.UI/umbraco/config/lang/en.xml b/src/Umbraco.Web.UI/umbraco/config/lang/en.xml index f1b415f3c5..ff234c71da 100644 --- a/src/Umbraco.Web.UI/umbraco/config/lang/en.xml +++ b/src/Umbraco.Web.UI/umbraco/config/lang/en.xml @@ -464,6 +464,8 @@ Enter a message... Your username is usually your email #value or ?key=value + Enter alias... + Generating alias... Allow at root From 6f359b3d18d3231dd79a74358273605c2144336c Mon Sep 17 00:00:00 2001 From: Anders Bjerner Date: Sun, 21 Oct 2018 13:57:01 +0200 Subject: [PATCH 76/98] Added keys for "enterAlias" and "generatingAlias" --- src/Umbraco.Web.UI/umbraco/config/lang/en_us.xml | 2 ++ 1 file changed, 2 insertions(+) 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 31d157f54c..ed3a261979 100644 --- a/src/Umbraco.Web.UI/umbraco/config/lang/en_us.xml +++ b/src/Umbraco.Web.UI/umbraco/config/lang/en_us.xml @@ -464,6 +464,8 @@ Enter a message... Your username is usually your email #value or ?key=value + Enter alias... + Generating alias... Allow at root From 39edf4c6dd4dd0fc5c2b530f3b6577aa959ba44c Mon Sep 17 00:00:00 2001 From: Anders Bjerner Date: Sun, 21 Oct 2018 13:58:45 +0200 Subject: [PATCH 77/98] Added keys for "enterAlias" and "generatingAlias" --- src/Umbraco.Web.UI/umbraco/config/lang/da.xml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/Umbraco.Web.UI/umbraco/config/lang/da.xml b/src/Umbraco.Web.UI/umbraco/config/lang/da.xml index e68365ddb8..886662d17f 100644 --- a/src/Umbraco.Web.UI/umbraco/config/lang/da.xml +++ b/src/Umbraco.Web.UI/umbraco/config/lang/da.xml @@ -443,6 +443,8 @@ Indtast din e-mail Indtast en besked... Dit brugernavn er typisk din e-mailadresse + Indtast alias... + Genererer alias... Tillad på rodniveau From 827bc19f6a4db824acf4af5161a6b234bcd7bc0a Mon Sep 17 00:00:00 2001 From: Anders Bjerner Date: Sun, 21 Oct 2018 14:03:22 +0200 Subject: [PATCH 78/98] Localized umb-generate-alias placeholder texts --- .../components/umbGenerateAlias.directive.js | 22 +++++++++++++++---- 1 file changed, 18 insertions(+), 4 deletions(-) diff --git a/src/Umbraco.Web.UI.Client/src/common/directives/components/umbGenerateAlias.directive.js b/src/Umbraco.Web.UI.Client/src/common/directives/components/umbGenerateAlias.directive.js index 66e93d70d8..b3accc18b4 100644 --- a/src/Umbraco.Web.UI.Client/src/common/directives/components/umbGenerateAlias.directive.js +++ b/src/Umbraco.Web.UI.Client/src/common/directives/components/umbGenerateAlias.directive.js @@ -48,7 +48,7 @@ the directive will use {@link umbraco.directives.directive:umbLockedField umbLoc **/ angular.module("umbraco.directives") - .directive('umbGenerateAlias', function ($timeout, entityResource) { + .directive('umbGenerateAlias', function ($timeout, entityResource, localizationService) { return { restrict: 'E', templateUrl: 'views/components/umb-generate-alias.html', @@ -67,7 +67,21 @@ angular.module("umbraco.directives") var updateAlias = false; scope.locked = true; - scope.placeholderText = "Enter alias..."; + + scope.labels = { + idle: "Enter alias...", + busy: "Generating alias...", + }; + + scope.placeholderText = scope.labels.idle; + + localizationService.localize('placeholders_enterAlias').then(function (value) { + scope.labels.idle = scope.placeholderText = value; + }); + + localizationService.localize('placeholders_generatingAlias').then(function (value) { + scope.labels.busy = value; + }); function generateAlias(value) { @@ -78,7 +92,7 @@ angular.module("umbraco.directives") if( value !== undefined && value !== "" && value !== null) { scope.alias = ""; - scope.placeholderText = "Generating Alias..."; + scope.placeholderText = scope.labels.busy; generateAliasTimeout = $timeout(function () { updateAlias = true; @@ -92,7 +106,7 @@ angular.module("umbraco.directives") } else { updateAlias = true; scope.alias = ""; - scope.placeholderText = "Enter alias..."; + scope.placeholderText = scope.labels.idle; } } From 90416a4d879e93f2c7dc69532597a6cb67c10b3f Mon Sep 17 00:00:00 2001 From: Kenn Jacobsen Date: Fri, 12 Oct 2018 08:34:33 +0200 Subject: [PATCH 79/98] Add a custom content item binder for saving blueprints (fixes #2985) --- src/Umbraco.Web/Editors/ContentController.cs | 2 +- src/Umbraco.Web/Umbraco.Web.csproj | 1 + .../WebApi/Binders/BlueprintItemBinder.cs | 28 +++++++++++++++++++ 3 files changed, 30 insertions(+), 1 deletion(-) create mode 100644 src/Umbraco.Web/WebApi/Binders/BlueprintItemBinder.cs diff --git a/src/Umbraco.Web/Editors/ContentController.cs b/src/Umbraco.Web/Editors/ContentController.cs index 6268759e29..4643cb2a1e 100644 --- a/src/Umbraco.Web/Editors/ContentController.cs +++ b/src/Umbraco.Web/Editors/ContentController.cs @@ -576,7 +576,7 @@ namespace Umbraco.Web.Editors [FileUploadCleanupFilter] [ContentPostValidate] public ContentItemDisplay PostSaveBlueprint( - [ModelBinder(typeof(ContentItemBinder))] ContentItemSave contentItem) + [ModelBinder(typeof(BlueprintItemBinder))] ContentItemSave contentItem) { var contentItemDisplay = PostSaveInternal(contentItem, content => diff --git a/src/Umbraco.Web/Umbraco.Web.csproj b/src/Umbraco.Web/Umbraco.Web.csproj index 66cce9b1bf..e021de0011 100644 --- a/src/Umbraco.Web/Umbraco.Web.csproj +++ b/src/Umbraco.Web/Umbraco.Web.csproj @@ -823,6 +823,7 @@ + diff --git a/src/Umbraco.Web/WebApi/Binders/BlueprintItemBinder.cs b/src/Umbraco.Web/WebApi/Binders/BlueprintItemBinder.cs new file mode 100644 index 0000000000..825c5b01c3 --- /dev/null +++ b/src/Umbraco.Web/WebApi/Binders/BlueprintItemBinder.cs @@ -0,0 +1,28 @@ +using System; +using Umbraco.Core; +using Umbraco.Core.Models; +using Umbraco.Web.Models.ContentEditing; + +namespace Umbraco.Web.WebApi.Binders +{ + internal class BlueprintItemBinder : ContentItemBinder + { + public BlueprintItemBinder(ApplicationContext applicationContext) + : base(applicationContext) + { + } + + /// + /// Constructor + /// + public BlueprintItemBinder() + : this(ApplicationContext.Current) + { + } + + protected override IContent GetExisting(ContentItemSave model) + { + return ApplicationContext.Services.ContentService.GetBlueprintById(Convert.ToInt32(model.Id)); + } + } +} \ No newline at end of file From 5da5df5bf9e9584d1675e38219bcd4f5f399f304 Mon Sep 17 00:00:00 2001 From: Kenn Jacobsen Date: Tue, 16 Oct 2018 13:25:44 +0200 Subject: [PATCH 80/98] Hide "reset password" on the login screen if system emails can't be sent. --- .../src/views/common/dialogs/login.controller.js | 2 +- src/Umbraco.Web/Editors/BackOfficeServerVariables.cs | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/src/Umbraco.Web.UI.Client/src/views/common/dialogs/login.controller.js b/src/Umbraco.Web.UI.Client/src/views/common/dialogs/login.controller.js index 9b703a0987..771718ac11 100644 --- a/src/Umbraco.Web.UI.Client/src/views/common/dialogs/login.controller.js +++ b/src/Umbraco.Web.UI.Client/src/views/common/dialogs/login.controller.js @@ -207,7 +207,7 @@ } } - $scope.allowPasswordReset = Umbraco.Sys.ServerVariables.umbracoSettings.allowPasswordReset; + $scope.allowPasswordReset = Umbraco.Sys.ServerVariables.umbracoSettings.canSendRequiredEmail && Umbraco.Sys.ServerVariables.umbracoSettings.allowPasswordReset; $scope.showLogin = function () { $scope.errorMsg = ""; diff --git a/src/Umbraco.Web/Editors/BackOfficeServerVariables.cs b/src/Umbraco.Web/Editors/BackOfficeServerVariables.cs index 0444820bc4..6e27a8f8e5 100644 --- a/src/Umbraco.Web/Editors/BackOfficeServerVariables.cs +++ b/src/Umbraco.Web/Editors/BackOfficeServerVariables.cs @@ -52,7 +52,7 @@ namespace Umbraco.Web.Editors var keepOnlyKeys = new Dictionary { {"umbracoUrls", new[] {"authenticationApiBaseUrl", "serverVarsJs", "externalLoginsUrl", "currentUserApiBaseUrl"}}, - {"umbracoSettings", new[] {"allowPasswordReset", "imageFileTypes", "maxFileSize", "loginBackgroundImage"}}, + {"umbracoSettings", new[] {"allowPasswordReset", "imageFileTypes", "maxFileSize", "loginBackgroundImage", "canSendRequiredEmail"}}, {"application", new[] {"applicationPath", "cacheBuster"}}, {"isDebuggingEnabled", new string[] { }}, {"features", new [] {"disabledFeatures"}} @@ -311,6 +311,7 @@ namespace Umbraco.Web.Editors {"allowPasswordReset", UmbracoConfig.For.UmbracoSettings().Security.AllowPasswordReset}, {"loginBackgroundImage", UmbracoConfig.For.UmbracoSettings().Content.LoginBackgroundImage}, {"showUserInvite", EmailSender.CanSendRequiredEmail}, + {"canSendRequiredEmail", EmailSender.CanSendRequiredEmail}, } }, { From 01d9785097ec0dd9d55e274866f314a4af034b17 Mon Sep 17 00:00:00 2001 From: Jan Skovgaard Date: Sun, 21 Oct 2018 16:00:11 +0200 Subject: [PATCH 81/98] 3364 - Suggestion: Make use of confirm action directive on repeatable textstring when deleting (#3365) --- .../less/components/umb-multiple-textbox.less | 17 ++++++++++++-- .../multipletextbox.controller.js | 22 ++++++++++++++++++- .../multipletextbox/multipletextbox.html | 19 +++++++++++----- 3 files changed, 50 insertions(+), 8 deletions(-) diff --git a/src/Umbraco.Web.UI.Client/src/less/components/umb-multiple-textbox.less b/src/Umbraco.Web.UI.Client/src/less/components/umb-multiple-textbox.less index 21f59a3e2d..52cc7a9aaf 100644 --- a/src/Umbraco.Web.UI.Client/src/less/components/umb-multiple-textbox.less +++ b/src/Umbraco.Web.UI.Client/src/less/components/umb-multiple-textbox.less @@ -1,4 +1,17 @@ -.umb-multiple-textbox .textbox-wrapper { +.umb-multiple-textbox{ + &__confirm{ + position: relative; + + &-action{ + margin: 0; + padding: 2px; + background: transparent; + border: 0 none; + } + } +} + +.umb-multiple-textbox .textbox-wrapper { align-items: center; margin-bottom: 15px; } @@ -7,7 +20,7 @@ margin-bottom: 0; } -.umb-multiple-textbox .textbox-wrapper i { +.umb-multiple-textbox .textbox-wrapper i:not(.icon-delete, .icon-check) { margin-right: 5px; } diff --git a/src/Umbraco.Web.UI.Client/src/views/propertyeditors/multipletextbox/multipletextbox.controller.js b/src/Umbraco.Web.UI.Client/src/views/propertyeditors/multipletextbox/multipletextbox.controller.js index acee0f5ce9..9f190aab41 100644 --- a/src/Umbraco.Web.UI.Client/src/views/propertyeditors/multipletextbox/multipletextbox.controller.js +++ b/src/Umbraco.Web.UI.Client/src/views/propertyeditors/multipletextbox/multipletextbox.controller.js @@ -2,6 +2,9 @@ var backspaceHits = 0; + // Set the visible prompt to -1 to ensure it will not be visible + $scope.promptIsVisible = "-1"; + $scope.sortableOptions = { axis: 'y', containment: 'parent', @@ -89,6 +92,9 @@ }; $scope.remove = function (index) { + // Make sure not to trigger other prompts when remove is triggered + $scope.hidePrompt(); + var remainder = []; for (var x = 0; x < $scope.model.value.length; x++) { if (x !== index) { @@ -98,6 +104,20 @@ $scope.model.value = remainder; }; + $scope.showPrompt = function (idx, item){ + + var i = $scope.model.value.indexOf(item); + + // Make the prompt visible for the clicked tag only + if (i === idx) { + $scope.promptIsVisible = i; + } + } + + $scope.hidePrompt = function(){ + $scope.promptIsVisible = "-1"; + } + } -angular.module("umbraco").controller("Umbraco.PropertyEditors.MultipleTextBoxController", MultipleTextBoxController); \ No newline at end of file +angular.module("umbraco").controller("Umbraco.PropertyEditors.MultipleTextBoxController", MultipleTextBoxController); diff --git a/src/Umbraco.Web.UI.Client/src/views/propertyeditors/multipletextbox/multipletextbox.html b/src/Umbraco.Web.UI.Client/src/views/propertyeditors/multipletextbox/multipletextbox.html index 123385d681..db98225e5f 100644 --- a/src/Umbraco.Web.UI.Client/src/views/propertyeditors/multipletextbox/multipletextbox.html +++ b/src/Umbraco.Web.UI.Client/src/views/propertyeditors/multipletextbox/multipletextbox.html @@ -5,11 +5,20 @@ - - - + +
+ + + + +
+
Date: Sat, 20 Oct 2018 12:16:24 +0200 Subject: [PATCH 82/98] Border color for .add-on should be @purple-l3 --- src/Umbraco.Web.UI.Client/src/less/forms.less | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Umbraco.Web.UI.Client/src/less/forms.less b/src/Umbraco.Web.UI.Client/src/less/forms.less index 5926ea2163..bbedfe1a0b 100644 --- a/src/Umbraco.Web.UI.Client/src/less/forms.less +++ b/src/Umbraco.Web.UI.Client/src/less/forms.less @@ -594,7 +594,7 @@ div.help { text-align: center; text-shadow: 0 1px 0 @white; background-color: @gray-10; - border: 1px solid @gray-8; + border: 1px solid @purple-l3; } .add-on, .btn, From 1de7b8f10fecdb37b45aab60cdc0ae3d0eff1b78 Mon Sep 17 00:00:00 2001 From: Anders Bjerner Date: Sat, 20 Oct 2018 12:26:16 +0200 Subject: [PATCH 83/98]
 elements should at least have white-space:
 pre-wrap

---
 src/Umbraco.Web.UI.Client/src/less/hacks.less | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/src/Umbraco.Web.UI.Client/src/less/hacks.less b/src/Umbraco.Web.UI.Client/src/less/hacks.less
index 18439b554c..6505dc6e62 100644
--- a/src/Umbraco.Web.UI.Client/src/less/hacks.less
+++ b/src/Umbraco.Web.UI.Client/src/less/hacks.less
@@ -202,7 +202,7 @@ pre {
   //font-size: @baseFontSize - 1; // 14px to 13px
   color: @gray-2;
   line-height: @baseLineHeight;
-  white-space: pre-line; // 1
+  white-space: pre-wrap; // 1
   overflow-x: auto; // 1
   background-color: @gray-10;
   border: 1px solid @gray-8;
@@ -222,4 +222,4 @@ pre {
     background-color: transparent;
     border: 0;
   }
-}
\ No newline at end of file
+}

From df2313f7ec0e8a1189f01243d4c5fddf35841715 Mon Sep 17 00:00:00 2001
From: Anders Bjerner 
Date: Sun, 21 Oct 2018 15:36:17 +0200
Subject: [PATCH 84/98] umbRequestHelper.resourcePromise not supports the error
 message being a promise

---
 .../services/umbrequesthelper.service.js      | 919 +++++++++---------
 1 file changed, 464 insertions(+), 455 deletions(-)

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 d950d39619..fa6099b226 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
@@ -1,455 +1,464 @@
-/**
-* @ngdoc service
-* @name umbraco.services.umbRequestHelper
-* @description A helper object used for sending requests to the server
-**/
-function umbRequestHelper($http, $q, umbDataFormatter, angularHelper, dialogService, notificationsService, eventsService) {
-    return {
-
-        /**
-         * @ngdoc method
-         * @name umbraco.services.umbRequestHelper#convertVirtualToAbsolutePath
-         * @methodOf umbraco.services.umbRequestHelper
-         * @function
-         *
-         * @description
-         * This will convert a virtual path (i.e. ~/App_Plugins/Blah/Test.html ) to an absolute path
-         * 
-         * @param {string} a virtual path, if this is already an absolute path it will just be returned, if this is a relative path an exception will be thrown
-         */
-        convertVirtualToAbsolutePath: function(virtualPath) {
-            if (virtualPath.startsWith("/")) {
-                return virtualPath;
-            }
-            if (!virtualPath.startsWith("~/")) {
-                throw "The path " + virtualPath + " is not a virtual path";
-            }
-            if (!Umbraco.Sys.ServerVariables.application.applicationPath) { 
-                throw "No applicationPath defined in Umbraco.ServerVariables.application.applicationPath";
-            }
-            return Umbraco.Sys.ServerVariables.application.applicationPath + virtualPath.trimStart("~/");
-        },
-
-        /**
-         * @ngdoc method
-         * @name umbraco.services.umbRequestHelper#dictionaryToQueryString
-         * @methodOf umbraco.services.umbRequestHelper
-         * @function
-         *
-         * @description
-         * This will turn an array of key/value pairs or a standard dictionary into a query string
-         * 
-         * @param {Array} queryStrings An array of key/value pairs
-         */
-        dictionaryToQueryString: function (queryStrings) {
-            
-            if (angular.isArray(queryStrings)) {
-                return _.map(queryStrings, function (item) {
-                    var key = null;
-                    var val = null;
-                    for (var k in item) {
-                        key = k;
-                        val = item[k];
-                        break;
-                    }
-                    if (key === null || val === null) {
-                        throw "The object in the array was not formatted as a key/value pair";
-                    }
-                    return encodeURIComponent(key) + "=" + encodeURIComponent(val);
-                }).join("&");
-            }
-            else if (angular.isObject(queryStrings)) {
-
-                //this allows for a normal object to be passed in (ie. a dictionary)
-                return decodeURIComponent($.param(queryStrings));
-            }
-            
-            throw "The queryString parameter is not an array or object of key value pairs";
-        },
-
-        /**
-         * @ngdoc method
-         * @name umbraco.services.umbRequestHelper#getApiUrl
-         * @methodOf umbraco.services.umbRequestHelper
-         * @function
-         *
-         * @description
-         * This will return the webapi Url for the requested key based on the servervariables collection
-         * 
-         * @param {string} apiName The webapi name that is found in the servervariables["umbracoUrls"] dictionary
-         * @param {string} actionName The webapi action name 
-         * @param {object} queryStrings Can be either a string or an array containing key/value pairs
-         */
-        getApiUrl: function (apiName, actionName, queryStrings) {
-            if (!Umbraco || !Umbraco.Sys || !Umbraco.Sys.ServerVariables || !Umbraco.Sys.ServerVariables["umbracoUrls"]) {
-                throw "No server variables defined!";
-            }
-
-            if (!Umbraco.Sys.ServerVariables["umbracoUrls"][apiName]) {
-                throw "No url found for api name " + apiName;
-            }
-
-            return Umbraco.Sys.ServerVariables["umbracoUrls"][apiName] + actionName +
-                (!queryStrings ? "" : "?" + (angular.isString(queryStrings) ? queryStrings : this.dictionaryToQueryString(queryStrings)));
-
-        },
-
-        /**
-         * @ngdoc function
-         * @name umbraco.services.umbRequestHelper#resourcePromise
-         * @methodOf umbraco.services.umbRequestHelper
-         * @function
-         *
-         * @description
-         * This returns a promise with an underlying http call, it is a helper method to reduce
-         *  the amount of duplicate code needed to query http resources and automatically handle any 
-         *  Http errors. See /docs/source/using-promises-resources.md
-         *
-         * @param {object} opts A mixed object which can either be a string representing the error message to be
-         *   returned OR an object containing either:
-         *     { success: successCallback, errorMsg: errorMessage }
-         *          OR
-         *     { success: successCallback, error: errorCallback }
-         *   In both of the above, the successCallback must accept these parameters: data, status, headers, config
-         *   If using the errorCallback it must accept these parameters: data, status, headers, config
-         *   The success callback must return the data which will be resolved by the deferred object.
-         *   The error callback must return an object containing: {errorMsg: errorMessage, data: originalData, status: status }
-         */
-        resourcePromise: function (httpPromise, opts) {
-            var deferred = $q.defer();
-
-            /** The default success callback used if one is not supplied in the opts */
-            function defaultSuccess(data, status, headers, config) {
-                //when it's successful, just return the data
-                return data;
-            }
-
-            /** The default error callback used if one is not supplied in the opts */
-            function defaultError(data, status, headers, config) {
-                return {
-                    //NOTE: the default error message here should never be used based on the above docs!
-                    errorMsg: (angular.isString(opts) ? opts : 'An error occurred!'),
-                    data: data,
-                    status: status
-                };
-            }
-
-            //create the callbacs based on whats been passed in.
-            var callbacks = {
-                success: ((!opts || !opts.success) ? defaultSuccess : opts.success),
-                error: ((!opts || !opts.error) ? defaultError : opts.error)
-            };
-
-            httpPromise.success(function (data, status, headers, config) {
-
-                //invoke the callback 
-                var result = callbacks.success.apply(this, [data, status, headers, config]);
-
-                //when it's successful, just return the data
-                deferred.resolve(result);
-
-            }).error(function (data, status, headers, config) {
-
-                //invoke the callback
-                var result = callbacks.error.apply(this, [data, status, headers, config]);
-
-                //when there's a 500 (unhandled) error show a YSOD overlay if debugging is enabled.
-                if (status >= 500 && status < 600) {
-
-                    //show a ysod dialog
-                    if (Umbraco.Sys.ServerVariables["isDebuggingEnabled"] === true) {
-                        eventsService.emit('app.ysod',
-                        {
-                            errorMsg: 'An error occured',
-                            data: data
-                        });
-                    }
-                    else {
-                        //show a simple error notification                         
-                        notificationsService.error("Server error", "Contact administrator, see log for full details.
" + result.errorMsg + ""); - } - - } - - //return an error object including the error message for UI - deferred.reject({ - errorMsg: result.errorMsg, - data: result.data, - status: result.status - }); - - - }); - - return deferred.promise; - - }, - - /** Used for saving media/content specifically */ - postSaveContent: function (args) { - - if (!args.restApiUrl) { - throw "args.restApiUrl is a required argument"; - } - if (!args.content) { - throw "args.content is a required argument"; - } - if (!args.action) { - throw "args.action is a required argument"; - } - if (!args.files) { - throw "args.files is a required argument"; - } - if (!args.dataFormatter) { - throw "args.dataFormatter is a required argument"; - } - - - var deferred = $q.defer(); - - //save the active tab id so we can set it when the data is returned. - var activeTab = _.find(args.content.tabs, function (item) { - return item.active; - }); - var activeTabIndex = (activeTab === undefined ? 0 : _.indexOf(args.content.tabs, activeTab)); - - //save the data - this.postMultiPartRequest( - args.restApiUrl, - { key: "contentItem", value: args.dataFormatter(args.content, args.action) }, - function (data, formData) { - //now add all of the assigned files - 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 - formData.append("file_" + args.files[f].alias, args.files[f].file); - } - - }, - function (data, status, headers, config) { - //success callback - - //reset the tabs and set the active one - if(data.tabs && data.tabs.length > 0) { - _.each(data.tabs, function (item) { - item.active = false; - }); - data.tabs[activeTabIndex].active = true; - } - - //the data returned is the up-to-date data so the UI will refresh - deferred.resolve(data); - }, - function (data, status, headers, config) { - //failure callback - - //when there's a 500 (unhandled) error show a YSOD overlay if debugging is enabled. - if (status >= 500 && status < 600) { - - //This is a bit of a hack to check if the error is due to a file being uploaded that is too large, - // we have to just check for the existence of a string value but currently that is the best way to - // do this since it's very hacky/difficult to catch this on the server - if (typeof data !== "undefined" && typeof data.indexOf === "function" && data.indexOf("Maximum request length exceeded") >= 0) { - notificationsService.error("Server error", "The uploaded file was too large, check with your site administrator to adjust the maximum size allowed"); - } - else if (Umbraco.Sys.ServerVariables["isDebuggingEnabled"] === true) { - //show a ysod dialog - eventsService.emit('app.ysod', - { - errorMsg: 'An error occured', - data: data - }); - } - else { - //show a simple error notification - notificationsService.error("Server error", "Contact administrator, see log for full details.
" + data.ExceptionMessage + ""); - } - - } - - //return an error object including the error message for UI - deferred.reject({ - errorMsg: 'An error occurred', - data: data, - status: status - }); - - - }); - - return deferred.promise; - }, - - /** Posts a multi-part mime request to the server */ - postMultiPartRequest: function (url, jsonData, transformCallback, successCallback, failureCallback) { - - //validate input, jsonData can be an array of key/value pairs or just one key/value pair. - if (!jsonData) { throw "jsonData cannot be null"; } - - if (angular.isArray(jsonData)) { - _.each(jsonData, function (item) { - if (!item.key || !item.value) { throw "jsonData array item must have both a key and a value property"; } - }); - } - else if (!jsonData.key || !jsonData.value) { throw "jsonData object must have both a key and a value property"; } - - - $http({ - method: 'POST', - url: url, - //IMPORTANT!!! You might think this should be set to 'multipart/form-data' but this is not true because when we are sending up files - // the request needs to include a 'boundary' parameter which identifies the boundary name between parts in this multi-part request - // and setting the Content-type manually will not set this boundary parameter. For whatever reason, setting the Content-type to 'false' - // will force the request to automatically populate the headers properly including the boundary parameter. - headers: { 'Content-Type': false }, - transformRequest: function (data) { - var formData = new FormData(); - //add the json data - if (angular.isArray(data)) { - _.each(data, function (item) { - formData.append(item.key, !angular.isString(item.value) ? angular.toJson(item.value) : item.value); - }); - } - else { - formData.append(data.key, !angular.isString(data.value) ? angular.toJson(data.value) : data.value); - } - - //call the callback - if (transformCallback) { - transformCallback.apply(this, [data, formData]); - } - - return formData; - }, - data: jsonData - }). - success(function (data, status, headers, config) { - if (successCallback) { - successCallback.apply(this, [data, status, headers, config]); - } - }). - error(function (data, status, headers, config) { - if (failureCallback) { - failureCallback.apply(this, [data, status, headers, config]); - } - }); - }, - - /** - * Downloads a file to the client using AJAX/XHR - * Based on an implementation here: web.student.tuwien.ac.at/~e0427417/jsdownload.html - * See https://stackoverflow.com/a/24129082/694494 - */ - downloadFile : function (httpPath) { - - var deferred = $q.defer(); - - // Use an arraybuffer - $http.get(httpPath, { responseType: 'arraybuffer' }) - .success(function (data, status, headers) { - - var octetStreamMime = 'application/octet-stream'; - var success = false; - - // Get the headers - headers = headers(); - - // Get the filename from the x-filename header or default to "download.bin" - var filename = headers['x-filename'] || 'download.bin'; - - // Determine the content type from the header or default to "application/octet-stream" - var contentType = headers['content-type'] || octetStreamMime; - - try { - // Try using msSaveBlob if supported - console.log("Trying saveBlob method ..."); - var blob = new Blob([data], { type: contentType }); - if (navigator.msSaveBlob) - navigator.msSaveBlob(blob, filename); - else { - // Try using other saveBlob implementations, if available - var saveBlob = navigator.webkitSaveBlob || navigator.mozSaveBlob || navigator.saveBlob; - if (saveBlob === undefined) throw "Not supported"; - saveBlob(blob, filename); - } - console.log("saveBlob succeeded"); - success = true; - } catch (ex) { - console.log("saveBlob method failed with the following exception:"); - console.log(ex); - } - - if (!success) { - // Get the blob url creator - var urlCreator = window.URL || window.webkitURL || window.mozURL || window.msURL; - if (urlCreator) { - // Try to use a download link - var link = document.createElement('a'); - if ('download' in link) { - // Try to simulate a click - try { - // Prepare a blob URL - console.log("Trying download link method with simulated click ..."); - var blob = new Blob([data], { type: contentType }); - var url = urlCreator.createObjectURL(blob); - link.setAttribute('href', url); - - // Set the download attribute (Supported in Chrome 14+ / Firefox 20+) - link.setAttribute("download", filename); - - // Simulate clicking the download link - var event = document.createEvent('MouseEvents'); - event.initMouseEvent('click', true, true, window, 1, 0, 0, 0, 0, false, false, false, false, 0, null); - link.dispatchEvent(event); - console.log("Download link method with simulated click succeeded"); - success = true; - - } catch (ex) { - console.log("Download link method with simulated click failed with the following exception:"); - console.log(ex); - } - } - - if (!success) { - // Fallback to window.location method - try { - // Prepare a blob URL - // Use application/octet-stream when using window.location to force download - console.log("Trying download link method with window.location ..."); - var blob = new Blob([data], { type: octetStreamMime }); - var url = urlCreator.createObjectURL(blob); - window.location = url; - console.log("Download link method with window.location succeeded"); - success = true; - } catch (ex) { - console.log("Download link method with window.location failed with the following exception:"); - console.log(ex); - } - } - - } - } - - if (!success) { - // Fallback to window.open method - console.log("No methods worked for saving the arraybuffer, using last resort window.open"); - window.open(httpPath, '_blank', ''); - } - - deferred.resolve(); - }) - .error(function (data, status) { - console.log("Request failed with status: " + status); - - deferred.reject({ - errorMsg: "An error occurred downloading the file", - data: data, - status: status - }); - }); - - return deferred.promise; - } - }; -} -angular.module('umbraco.services').factory('umbRequestHelper', umbRequestHelper); +/** +* @ngdoc service +* @name umbraco.services.umbRequestHelper +* @description A helper object used for sending requests to the server +**/ +function umbRequestHelper($http, $q, umbDataFormatter, angularHelper, dialogService, notificationsService, eventsService) { + return { + + /** + * @ngdoc method + * @name umbraco.services.umbRequestHelper#convertVirtualToAbsolutePath + * @methodOf umbraco.services.umbRequestHelper + * @function + * + * @description + * This will convert a virtual path (i.e. ~/App_Plugins/Blah/Test.html ) to an absolute path + * + * @param {string} a virtual path, if this is already an absolute path it will just be returned, if this is a relative path an exception will be thrown + */ + convertVirtualToAbsolutePath: function(virtualPath) { + if (virtualPath.startsWith("/")) { + return virtualPath; + } + if (!virtualPath.startsWith("~/")) { + throw "The path " + virtualPath + " is not a virtual path"; + } + if (!Umbraco.Sys.ServerVariables.application.applicationPath) { + throw "No applicationPath defined in Umbraco.ServerVariables.application.applicationPath"; + } + return Umbraco.Sys.ServerVariables.application.applicationPath + virtualPath.trimStart("~/"); + }, + + /** + * @ngdoc method + * @name umbraco.services.umbRequestHelper#dictionaryToQueryString + * @methodOf umbraco.services.umbRequestHelper + * @function + * + * @description + * This will turn an array of key/value pairs or a standard dictionary into a query string + * + * @param {Array} queryStrings An array of key/value pairs + */ + dictionaryToQueryString: function (queryStrings) { + + if (angular.isArray(queryStrings)) { + return _.map(queryStrings, function (item) { + var key = null; + var val = null; + for (var k in item) { + key = k; + val = item[k]; + break; + } + if (key === null || val === null) { + throw "The object in the array was not formatted as a key/value pair"; + } + return encodeURIComponent(key) + "=" + encodeURIComponent(val); + }).join("&"); + } + else if (angular.isObject(queryStrings)) { + + //this allows for a normal object to be passed in (ie. a dictionary) + return decodeURIComponent($.param(queryStrings)); + } + + throw "The queryString parameter is not an array or object of key value pairs"; + }, + + /** + * @ngdoc method + * @name umbraco.services.umbRequestHelper#getApiUrl + * @methodOf umbraco.services.umbRequestHelper + * @function + * + * @description + * This will return the webapi Url for the requested key based on the servervariables collection + * + * @param {string} apiName The webapi name that is found in the servervariables["umbracoUrls"] dictionary + * @param {string} actionName The webapi action name + * @param {object} queryStrings Can be either a string or an array containing key/value pairs + */ + getApiUrl: function (apiName, actionName, queryStrings) { + if (!Umbraco || !Umbraco.Sys || !Umbraco.Sys.ServerVariables || !Umbraco.Sys.ServerVariables["umbracoUrls"]) { + throw "No server variables defined!"; + } + + if (!Umbraco.Sys.ServerVariables["umbracoUrls"][apiName]) { + throw "No url found for api name " + apiName; + } + + return Umbraco.Sys.ServerVariables["umbracoUrls"][apiName] + actionName + + (!queryStrings ? "" : "?" + (angular.isString(queryStrings) ? queryStrings : this.dictionaryToQueryString(queryStrings))); + + }, + + /** + * @ngdoc function + * @name umbraco.services.umbRequestHelper#resourcePromise + * @methodOf umbraco.services.umbRequestHelper + * @function + * + * @description + * This returns a promise with an underlying http call, it is a helper method to reduce + * the amount of duplicate code needed to query http resources and automatically handle any + * Http errors. See /docs/source/using-promises-resources.md + * + * @param {object} opts A mixed object which can either be a string representing the error message to be + * returned OR an object containing either: + * { success: successCallback, errorMsg: errorMessage } + * OR + * { success: successCallback, error: errorCallback } + * In both of the above, the successCallback must accept these parameters: data, status, headers, config + * If using the errorCallback it must accept these parameters: data, status, headers, config + * The success callback must return the data which will be resolved by the deferred object. + * The error callback must return an object containing: {errorMsg: errorMessage, data: originalData, status: status } + */ + resourcePromise: function (httpPromise, opts) { + var deferred = $q.defer(); + + /** The default success callback used if one is not supplied in the opts */ + function defaultSuccess(data, status, headers, config) { + //when it's successful, just return the data + return data; + } + + /** The default error callback used if one is not supplied in the opts */ + function defaultError(data, status, headers, config) { + + var err = { + //NOTE: the default error message here should never be used based on the above docs! + errorMsg: (angular.isString(opts) ? opts : 'An error occurred!'), + data: data, + status: status + }; + + // if "opts" is a promise, we set "err.errorMsg" to be that promise + if (typeof(opts) == "object" && typeof(opts.then) == "function") { + err.errorMsg = opts; + } + + return err; + + } + + //create the callbacs based on whats been passed in. + var callbacks = { + success: ((!opts || !opts.success) ? defaultSuccess : opts.success), + error: ((!opts || !opts.error) ? defaultError : opts.error) + }; + + httpPromise.success(function (data, status, headers, config) { + + //invoke the callback + var result = callbacks.success.apply(this, [data, status, headers, config]); + + //when it's successful, just return the data + deferred.resolve(result); + + }).error(function (data, status, headers, config) { + + //invoke the callback + var result = callbacks.error.apply(this, [data, status, headers, config]); + + //when there's a 500 (unhandled) error show a YSOD overlay if debugging is enabled. + if (status >= 500 && status < 600) { + + //show a ysod dialog + if (Umbraco.Sys.ServerVariables["isDebuggingEnabled"] === true) { + eventsService.emit('app.ysod', + { + errorMsg: 'An error occured', + data: data + }); + } + else { + //show a simple error notification + notificationsService.error("Server error", "Contact administrator, see log for full details.
" + result.errorMsg + ""); + } + + } + + //return an error object including the error message for UI + deferred.reject({ + errorMsg: result.errorMsg, + data: result.data, + status: result.status + }); + + + }); + + return deferred.promise; + + }, + + /** Used for saving media/content specifically */ + postSaveContent: function (args) { + + if (!args.restApiUrl) { + throw "args.restApiUrl is a required argument"; + } + if (!args.content) { + throw "args.content is a required argument"; + } + if (!args.action) { + throw "args.action is a required argument"; + } + if (!args.files) { + throw "args.files is a required argument"; + } + if (!args.dataFormatter) { + throw "args.dataFormatter is a required argument"; + } + + + var deferred = $q.defer(); + + //save the active tab id so we can set it when the data is returned. + var activeTab = _.find(args.content.tabs, function (item) { + return item.active; + }); + var activeTabIndex = (activeTab === undefined ? 0 : _.indexOf(args.content.tabs, activeTab)); + + //save the data + this.postMultiPartRequest( + args.restApiUrl, + { key: "contentItem", value: args.dataFormatter(args.content, args.action) }, + function (data, formData) { + //now add all of the assigned files + 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 + formData.append("file_" + args.files[f].alias, args.files[f].file); + } + + }, + function (data, status, headers, config) { + //success callback + + //reset the tabs and set the active one + if(data.tabs && data.tabs.length > 0) { + _.each(data.tabs, function (item) { + item.active = false; + }); + data.tabs[activeTabIndex].active = true; + } + + //the data returned is the up-to-date data so the UI will refresh + deferred.resolve(data); + }, + function (data, status, headers, config) { + //failure callback + + //when there's a 500 (unhandled) error show a YSOD overlay if debugging is enabled. + if (status >= 500 && status < 600) { + + //This is a bit of a hack to check if the error is due to a file being uploaded that is too large, + // we have to just check for the existence of a string value but currently that is the best way to + // do this since it's very hacky/difficult to catch this on the server + if (typeof data !== "undefined" && typeof data.indexOf === "function" && data.indexOf("Maximum request length exceeded") >= 0) { + notificationsService.error("Server error", "The uploaded file was too large, check with your site administrator to adjust the maximum size allowed"); + } + else if (Umbraco.Sys.ServerVariables["isDebuggingEnabled"] === true) { + //show a ysod dialog + eventsService.emit('app.ysod', + { + errorMsg: 'An error occured', + data: data + }); + } + else { + //show a simple error notification + notificationsService.error("Server error", "Contact administrator, see log for full details.
" + data.ExceptionMessage + ""); + } + + } + + //return an error object including the error message for UI + deferred.reject({ + errorMsg: 'An error occurred', + data: data, + status: status + }); + + + }); + + return deferred.promise; + }, + + /** Posts a multi-part mime request to the server */ + postMultiPartRequest: function (url, jsonData, transformCallback, successCallback, failureCallback) { + + //validate input, jsonData can be an array of key/value pairs or just one key/value pair. + if (!jsonData) { throw "jsonData cannot be null"; } + + if (angular.isArray(jsonData)) { + _.each(jsonData, function (item) { + if (!item.key || !item.value) { throw "jsonData array item must have both a key and a value property"; } + }); + } + else if (!jsonData.key || !jsonData.value) { throw "jsonData object must have both a key and a value property"; } + + + $http({ + method: 'POST', + url: url, + //IMPORTANT!!! You might think this should be set to 'multipart/form-data' but this is not true because when we are sending up files + // the request needs to include a 'boundary' parameter which identifies the boundary name between parts in this multi-part request + // and setting the Content-type manually will not set this boundary parameter. For whatever reason, setting the Content-type to 'false' + // will force the request to automatically populate the headers properly including the boundary parameter. + headers: { 'Content-Type': false }, + transformRequest: function (data) { + var formData = new FormData(); + //add the json data + if (angular.isArray(data)) { + _.each(data, function (item) { + formData.append(item.key, !angular.isString(item.value) ? angular.toJson(item.value) : item.value); + }); + } + else { + formData.append(data.key, !angular.isString(data.value) ? angular.toJson(data.value) : data.value); + } + + //call the callback + if (transformCallback) { + transformCallback.apply(this, [data, formData]); + } + + return formData; + }, + data: jsonData + }). + success(function (data, status, headers, config) { + if (successCallback) { + successCallback.apply(this, [data, status, headers, config]); + } + }). + error(function (data, status, headers, config) { + if (failureCallback) { + failureCallback.apply(this, [data, status, headers, config]); + } + }); + }, + + /** + * Downloads a file to the client using AJAX/XHR + * Based on an implementation here: web.student.tuwien.ac.at/~e0427417/jsdownload.html + * See https://stackoverflow.com/a/24129082/694494 + */ + downloadFile : function (httpPath) { + + var deferred = $q.defer(); + + // Use an arraybuffer + $http.get(httpPath, { responseType: 'arraybuffer' }) + .success(function (data, status, headers) { + + var octetStreamMime = 'application/octet-stream'; + var success = false; + + // Get the headers + headers = headers(); + + // Get the filename from the x-filename header or default to "download.bin" + var filename = headers['x-filename'] || 'download.bin'; + + // Determine the content type from the header or default to "application/octet-stream" + var contentType = headers['content-type'] || octetStreamMime; + + try { + // Try using msSaveBlob if supported + console.log("Trying saveBlob method ..."); + var blob = new Blob([data], { type: contentType }); + if (navigator.msSaveBlob) + navigator.msSaveBlob(blob, filename); + else { + // Try using other saveBlob implementations, if available + var saveBlob = navigator.webkitSaveBlob || navigator.mozSaveBlob || navigator.saveBlob; + if (saveBlob === undefined) throw "Not supported"; + saveBlob(blob, filename); + } + console.log("saveBlob succeeded"); + success = true; + } catch (ex) { + console.log("saveBlob method failed with the following exception:"); + console.log(ex); + } + + if (!success) { + // Get the blob url creator + var urlCreator = window.URL || window.webkitURL || window.mozURL || window.msURL; + if (urlCreator) { + // Try to use a download link + var link = document.createElement('a'); + if ('download' in link) { + // Try to simulate a click + try { + // Prepare a blob URL + console.log("Trying download link method with simulated click ..."); + var blob = new Blob([data], { type: contentType }); + var url = urlCreator.createObjectURL(blob); + link.setAttribute('href', url); + + // Set the download attribute (Supported in Chrome 14+ / Firefox 20+) + link.setAttribute("download", filename); + + // Simulate clicking the download link + var event = document.createEvent('MouseEvents'); + event.initMouseEvent('click', true, true, window, 1, 0, 0, 0, 0, false, false, false, false, 0, null); + link.dispatchEvent(event); + console.log("Download link method with simulated click succeeded"); + success = true; + + } catch (ex) { + console.log("Download link method with simulated click failed with the following exception:"); + console.log(ex); + } + } + + if (!success) { + // Fallback to window.location method + try { + // Prepare a blob URL + // Use application/octet-stream when using window.location to force download + console.log("Trying download link method with window.location ..."); + var blob = new Blob([data], { type: octetStreamMime }); + var url = urlCreator.createObjectURL(blob); + window.location = url; + console.log("Download link method with window.location succeeded"); + success = true; + } catch (ex) { + console.log("Download link method with window.location failed with the following exception:"); + console.log(ex); + } + } + + } + } + + if (!success) { + // Fallback to window.open method + console.log("No methods worked for saving the arraybuffer, using last resort window.open"); + window.open(httpPath, '_blank', ''); + } + + deferred.resolve(); + }) + .error(function (data, status) { + console.log("Request failed with status: " + status); + + deferred.reject({ + errorMsg: "An error occurred downloading the file", + data: data, + status: status + }); + }); + + return deferred.promise; + } + }; +} +angular.module('umbraco.services').factory('umbRequestHelper', umbRequestHelper); From d16bc7a4659009a37ca7aab9d567cfff6c2d94d2 Mon Sep 17 00:00:00 2001 From: Kenn Jacobsen Date: Fri, 12 Oct 2018 08:34:33 +0200 Subject: [PATCH 85/98] Add a custom content item binder for saving blueprints (fixes #2985) --- src/Umbraco.Web/Editors/ContentController.cs | 2 +- src/Umbraco.Web/Umbraco.Web.csproj | 1 + .../WebApi/Binders/BlueprintItemBinder.cs | 28 +++++++++++++++++++ 3 files changed, 30 insertions(+), 1 deletion(-) create mode 100644 src/Umbraco.Web/WebApi/Binders/BlueprintItemBinder.cs diff --git a/src/Umbraco.Web/Editors/ContentController.cs b/src/Umbraco.Web/Editors/ContentController.cs index 6268759e29..4643cb2a1e 100644 --- a/src/Umbraco.Web/Editors/ContentController.cs +++ b/src/Umbraco.Web/Editors/ContentController.cs @@ -576,7 +576,7 @@ namespace Umbraco.Web.Editors [FileUploadCleanupFilter] [ContentPostValidate] public ContentItemDisplay PostSaveBlueprint( - [ModelBinder(typeof(ContentItemBinder))] ContentItemSave contentItem) + [ModelBinder(typeof(BlueprintItemBinder))] ContentItemSave contentItem) { var contentItemDisplay = PostSaveInternal(contentItem, content => diff --git a/src/Umbraco.Web/Umbraco.Web.csproj b/src/Umbraco.Web/Umbraco.Web.csproj index 66cce9b1bf..e021de0011 100644 --- a/src/Umbraco.Web/Umbraco.Web.csproj +++ b/src/Umbraco.Web/Umbraco.Web.csproj @@ -823,6 +823,7 @@ + diff --git a/src/Umbraco.Web/WebApi/Binders/BlueprintItemBinder.cs b/src/Umbraco.Web/WebApi/Binders/BlueprintItemBinder.cs new file mode 100644 index 0000000000..825c5b01c3 --- /dev/null +++ b/src/Umbraco.Web/WebApi/Binders/BlueprintItemBinder.cs @@ -0,0 +1,28 @@ +using System; +using Umbraco.Core; +using Umbraco.Core.Models; +using Umbraco.Web.Models.ContentEditing; + +namespace Umbraco.Web.WebApi.Binders +{ + internal class BlueprintItemBinder : ContentItemBinder + { + public BlueprintItemBinder(ApplicationContext applicationContext) + : base(applicationContext) + { + } + + /// + /// Constructor + /// + public BlueprintItemBinder() + : this(ApplicationContext.Current) + { + } + + protected override IContent GetExisting(ContentItemSave model) + { + return ApplicationContext.Services.ContentService.GetBlueprintById(Convert.ToInt32(model.Id)); + } + } +} \ No newline at end of file From 44fbff4410191068dec508d9b55bbef2a2894836 Mon Sep 17 00:00:00 2001 From: Kenn Jacobsen Date: Tue, 16 Oct 2018 13:25:44 +0200 Subject: [PATCH 86/98] Hide "reset password" on the login screen if system emails can't be sent. --- .../src/views/common/dialogs/login.controller.js | 2 +- src/Umbraco.Web/Editors/BackOfficeServerVariables.cs | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/src/Umbraco.Web.UI.Client/src/views/common/dialogs/login.controller.js b/src/Umbraco.Web.UI.Client/src/views/common/dialogs/login.controller.js index 9b703a0987..771718ac11 100644 --- a/src/Umbraco.Web.UI.Client/src/views/common/dialogs/login.controller.js +++ b/src/Umbraco.Web.UI.Client/src/views/common/dialogs/login.controller.js @@ -207,7 +207,7 @@ } } - $scope.allowPasswordReset = Umbraco.Sys.ServerVariables.umbracoSettings.allowPasswordReset; + $scope.allowPasswordReset = Umbraco.Sys.ServerVariables.umbracoSettings.canSendRequiredEmail && Umbraco.Sys.ServerVariables.umbracoSettings.allowPasswordReset; $scope.showLogin = function () { $scope.errorMsg = ""; diff --git a/src/Umbraco.Web/Editors/BackOfficeServerVariables.cs b/src/Umbraco.Web/Editors/BackOfficeServerVariables.cs index 0444820bc4..6e27a8f8e5 100644 --- a/src/Umbraco.Web/Editors/BackOfficeServerVariables.cs +++ b/src/Umbraco.Web/Editors/BackOfficeServerVariables.cs @@ -52,7 +52,7 @@ namespace Umbraco.Web.Editors var keepOnlyKeys = new Dictionary { {"umbracoUrls", new[] {"authenticationApiBaseUrl", "serverVarsJs", "externalLoginsUrl", "currentUserApiBaseUrl"}}, - {"umbracoSettings", new[] {"allowPasswordReset", "imageFileTypes", "maxFileSize", "loginBackgroundImage"}}, + {"umbracoSettings", new[] {"allowPasswordReset", "imageFileTypes", "maxFileSize", "loginBackgroundImage", "canSendRequiredEmail"}}, {"application", new[] {"applicationPath", "cacheBuster"}}, {"isDebuggingEnabled", new string[] { }}, {"features", new [] {"disabledFeatures"}} @@ -311,6 +311,7 @@ namespace Umbraco.Web.Editors {"allowPasswordReset", UmbracoConfig.For.UmbracoSettings().Security.AllowPasswordReset}, {"loginBackgroundImage", UmbracoConfig.For.UmbracoSettings().Content.LoginBackgroundImage}, {"showUserInvite", EmailSender.CanSendRequiredEmail}, + {"canSendRequiredEmail", EmailSender.CanSendRequiredEmail}, } }, { From 7eecf230afacd0908140d4a82fb969734af069c9 Mon Sep 17 00:00:00 2001 From: Jan Skovgaard Date: Sun, 21 Oct 2018 16:00:11 +0200 Subject: [PATCH 87/98] 3364 - Suggestion: Make use of confirm action directive on repeatable textstring when deleting (#3365) --- .../less/components/umb-multiple-textbox.less | 17 ++++++++++++-- .../multipletextbox.controller.js | 22 ++++++++++++++++++- .../multipletextbox/multipletextbox.html | 19 +++++++++++----- 3 files changed, 50 insertions(+), 8 deletions(-) diff --git a/src/Umbraco.Web.UI.Client/src/less/components/umb-multiple-textbox.less b/src/Umbraco.Web.UI.Client/src/less/components/umb-multiple-textbox.less index 21f59a3e2d..52cc7a9aaf 100644 --- a/src/Umbraco.Web.UI.Client/src/less/components/umb-multiple-textbox.less +++ b/src/Umbraco.Web.UI.Client/src/less/components/umb-multiple-textbox.less @@ -1,4 +1,17 @@ -.umb-multiple-textbox .textbox-wrapper { +.umb-multiple-textbox{ + &__confirm{ + position: relative; + + &-action{ + margin: 0; + padding: 2px; + background: transparent; + border: 0 none; + } + } +} + +.umb-multiple-textbox .textbox-wrapper { align-items: center; margin-bottom: 15px; } @@ -7,7 +20,7 @@ margin-bottom: 0; } -.umb-multiple-textbox .textbox-wrapper i { +.umb-multiple-textbox .textbox-wrapper i:not(.icon-delete, .icon-check) { margin-right: 5px; } diff --git a/src/Umbraco.Web.UI.Client/src/views/propertyeditors/multipletextbox/multipletextbox.controller.js b/src/Umbraco.Web.UI.Client/src/views/propertyeditors/multipletextbox/multipletextbox.controller.js index acee0f5ce9..9f190aab41 100644 --- a/src/Umbraco.Web.UI.Client/src/views/propertyeditors/multipletextbox/multipletextbox.controller.js +++ b/src/Umbraco.Web.UI.Client/src/views/propertyeditors/multipletextbox/multipletextbox.controller.js @@ -2,6 +2,9 @@ var backspaceHits = 0; + // Set the visible prompt to -1 to ensure it will not be visible + $scope.promptIsVisible = "-1"; + $scope.sortableOptions = { axis: 'y', containment: 'parent', @@ -89,6 +92,9 @@ }; $scope.remove = function (index) { + // Make sure not to trigger other prompts when remove is triggered + $scope.hidePrompt(); + var remainder = []; for (var x = 0; x < $scope.model.value.length; x++) { if (x !== index) { @@ -98,6 +104,20 @@ $scope.model.value = remainder; }; + $scope.showPrompt = function (idx, item){ + + var i = $scope.model.value.indexOf(item); + + // Make the prompt visible for the clicked tag only + if (i === idx) { + $scope.promptIsVisible = i; + } + } + + $scope.hidePrompt = function(){ + $scope.promptIsVisible = "-1"; + } + } -angular.module("umbraco").controller("Umbraco.PropertyEditors.MultipleTextBoxController", MultipleTextBoxController); \ No newline at end of file +angular.module("umbraco").controller("Umbraco.PropertyEditors.MultipleTextBoxController", MultipleTextBoxController); diff --git a/src/Umbraco.Web.UI.Client/src/views/propertyeditors/multipletextbox/multipletextbox.html b/src/Umbraco.Web.UI.Client/src/views/propertyeditors/multipletextbox/multipletextbox.html index 123385d681..db98225e5f 100644 --- a/src/Umbraco.Web.UI.Client/src/views/propertyeditors/multipletextbox/multipletextbox.html +++ b/src/Umbraco.Web.UI.Client/src/views/propertyeditors/multipletextbox/multipletextbox.html @@ -5,11 +5,20 @@ -
- - + +
+ + + + +
+
Date: Sat, 20 Oct 2018 12:16:24 +0200 Subject: [PATCH 88/98] Border color for .add-on should be @purple-l3 --- src/Umbraco.Web.UI.Client/src/less/forms.less | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Umbraco.Web.UI.Client/src/less/forms.less b/src/Umbraco.Web.UI.Client/src/less/forms.less index 5926ea2163..bbedfe1a0b 100644 --- a/src/Umbraco.Web.UI.Client/src/less/forms.less +++ b/src/Umbraco.Web.UI.Client/src/less/forms.less @@ -594,7 +594,7 @@ div.help { text-align: center; text-shadow: 0 1px 0 @white; background-color: @gray-10; - border: 1px solid @gray-8; + border: 1px solid @purple-l3; } .add-on, .btn, From bb3beb406d4e76e4a37124d09c0e6a37a92deea0 Mon Sep 17 00:00:00 2001 From: Anders Bjerner Date: Sat, 20 Oct 2018 12:26:16 +0200 Subject: [PATCH 89/98]
 elements should at least have white-space:
 pre-wrap

---
 src/Umbraco.Web.UI.Client/src/less/hacks.less | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/src/Umbraco.Web.UI.Client/src/less/hacks.less b/src/Umbraco.Web.UI.Client/src/less/hacks.less
index 18439b554c..6505dc6e62 100644
--- a/src/Umbraco.Web.UI.Client/src/less/hacks.less
+++ b/src/Umbraco.Web.UI.Client/src/less/hacks.less
@@ -202,7 +202,7 @@ pre {
   //font-size: @baseFontSize - 1; // 14px to 13px
   color: @gray-2;
   line-height: @baseLineHeight;
-  white-space: pre-line; // 1
+  white-space: pre-wrap; // 1
   overflow-x: auto; // 1
   background-color: @gray-10;
   border: 1px solid @gray-8;
@@ -222,4 +222,4 @@ pre {
     background-color: transparent;
     border: 0;
   }
-}
\ No newline at end of file
+}

From 954893cf2b81acfd7805ca4c9bd2d4cf78eb00a6 Mon Sep 17 00:00:00 2001
From: Anders Bjerner 
Date: Sun, 21 Oct 2018 15:36:17 +0200
Subject: [PATCH 90/98] umbRequestHelper.resourcePromise not supports the error
 message being a promise

---
 .../services/umbrequesthelper.service.js      | 919 +++++++++---------
 1 file changed, 464 insertions(+), 455 deletions(-)

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 d950d39619..fa6099b226 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
@@ -1,455 +1,464 @@
-/**
-* @ngdoc service
-* @name umbraco.services.umbRequestHelper
-* @description A helper object used for sending requests to the server
-**/
-function umbRequestHelper($http, $q, umbDataFormatter, angularHelper, dialogService, notificationsService, eventsService) {
-    return {
-
-        /**
-         * @ngdoc method
-         * @name umbraco.services.umbRequestHelper#convertVirtualToAbsolutePath
-         * @methodOf umbraco.services.umbRequestHelper
-         * @function
-         *
-         * @description
-         * This will convert a virtual path (i.e. ~/App_Plugins/Blah/Test.html ) to an absolute path
-         * 
-         * @param {string} a virtual path, if this is already an absolute path it will just be returned, if this is a relative path an exception will be thrown
-         */
-        convertVirtualToAbsolutePath: function(virtualPath) {
-            if (virtualPath.startsWith("/")) {
-                return virtualPath;
-            }
-            if (!virtualPath.startsWith("~/")) {
-                throw "The path " + virtualPath + " is not a virtual path";
-            }
-            if (!Umbraco.Sys.ServerVariables.application.applicationPath) { 
-                throw "No applicationPath defined in Umbraco.ServerVariables.application.applicationPath";
-            }
-            return Umbraco.Sys.ServerVariables.application.applicationPath + virtualPath.trimStart("~/");
-        },
-
-        /**
-         * @ngdoc method
-         * @name umbraco.services.umbRequestHelper#dictionaryToQueryString
-         * @methodOf umbraco.services.umbRequestHelper
-         * @function
-         *
-         * @description
-         * This will turn an array of key/value pairs or a standard dictionary into a query string
-         * 
-         * @param {Array} queryStrings An array of key/value pairs
-         */
-        dictionaryToQueryString: function (queryStrings) {
-            
-            if (angular.isArray(queryStrings)) {
-                return _.map(queryStrings, function (item) {
-                    var key = null;
-                    var val = null;
-                    for (var k in item) {
-                        key = k;
-                        val = item[k];
-                        break;
-                    }
-                    if (key === null || val === null) {
-                        throw "The object in the array was not formatted as a key/value pair";
-                    }
-                    return encodeURIComponent(key) + "=" + encodeURIComponent(val);
-                }).join("&");
-            }
-            else if (angular.isObject(queryStrings)) {
-
-                //this allows for a normal object to be passed in (ie. a dictionary)
-                return decodeURIComponent($.param(queryStrings));
-            }
-            
-            throw "The queryString parameter is not an array or object of key value pairs";
-        },
-
-        /**
-         * @ngdoc method
-         * @name umbraco.services.umbRequestHelper#getApiUrl
-         * @methodOf umbraco.services.umbRequestHelper
-         * @function
-         *
-         * @description
-         * This will return the webapi Url for the requested key based on the servervariables collection
-         * 
-         * @param {string} apiName The webapi name that is found in the servervariables["umbracoUrls"] dictionary
-         * @param {string} actionName The webapi action name 
-         * @param {object} queryStrings Can be either a string or an array containing key/value pairs
-         */
-        getApiUrl: function (apiName, actionName, queryStrings) {
-            if (!Umbraco || !Umbraco.Sys || !Umbraco.Sys.ServerVariables || !Umbraco.Sys.ServerVariables["umbracoUrls"]) {
-                throw "No server variables defined!";
-            }
-
-            if (!Umbraco.Sys.ServerVariables["umbracoUrls"][apiName]) {
-                throw "No url found for api name " + apiName;
-            }
-
-            return Umbraco.Sys.ServerVariables["umbracoUrls"][apiName] + actionName +
-                (!queryStrings ? "" : "?" + (angular.isString(queryStrings) ? queryStrings : this.dictionaryToQueryString(queryStrings)));
-
-        },
-
-        /**
-         * @ngdoc function
-         * @name umbraco.services.umbRequestHelper#resourcePromise
-         * @methodOf umbraco.services.umbRequestHelper
-         * @function
-         *
-         * @description
-         * This returns a promise with an underlying http call, it is a helper method to reduce
-         *  the amount of duplicate code needed to query http resources and automatically handle any 
-         *  Http errors. See /docs/source/using-promises-resources.md
-         *
-         * @param {object} opts A mixed object which can either be a string representing the error message to be
-         *   returned OR an object containing either:
-         *     { success: successCallback, errorMsg: errorMessage }
-         *          OR
-         *     { success: successCallback, error: errorCallback }
-         *   In both of the above, the successCallback must accept these parameters: data, status, headers, config
-         *   If using the errorCallback it must accept these parameters: data, status, headers, config
-         *   The success callback must return the data which will be resolved by the deferred object.
-         *   The error callback must return an object containing: {errorMsg: errorMessage, data: originalData, status: status }
-         */
-        resourcePromise: function (httpPromise, opts) {
-            var deferred = $q.defer();
-
-            /** The default success callback used if one is not supplied in the opts */
-            function defaultSuccess(data, status, headers, config) {
-                //when it's successful, just return the data
-                return data;
-            }
-
-            /** The default error callback used if one is not supplied in the opts */
-            function defaultError(data, status, headers, config) {
-                return {
-                    //NOTE: the default error message here should never be used based on the above docs!
-                    errorMsg: (angular.isString(opts) ? opts : 'An error occurred!'),
-                    data: data,
-                    status: status
-                };
-            }
-
-            //create the callbacs based on whats been passed in.
-            var callbacks = {
-                success: ((!opts || !opts.success) ? defaultSuccess : opts.success),
-                error: ((!opts || !opts.error) ? defaultError : opts.error)
-            };
-
-            httpPromise.success(function (data, status, headers, config) {
-
-                //invoke the callback 
-                var result = callbacks.success.apply(this, [data, status, headers, config]);
-
-                //when it's successful, just return the data
-                deferred.resolve(result);
-
-            }).error(function (data, status, headers, config) {
-
-                //invoke the callback
-                var result = callbacks.error.apply(this, [data, status, headers, config]);
-
-                //when there's a 500 (unhandled) error show a YSOD overlay if debugging is enabled.
-                if (status >= 500 && status < 600) {
-
-                    //show a ysod dialog
-                    if (Umbraco.Sys.ServerVariables["isDebuggingEnabled"] === true) {
-                        eventsService.emit('app.ysod',
-                        {
-                            errorMsg: 'An error occured',
-                            data: data
-                        });
-                    }
-                    else {
-                        //show a simple error notification                         
-                        notificationsService.error("Server error", "Contact administrator, see log for full details.
" + result.errorMsg + ""); - } - - } - - //return an error object including the error message for UI - deferred.reject({ - errorMsg: result.errorMsg, - data: result.data, - status: result.status - }); - - - }); - - return deferred.promise; - - }, - - /** Used for saving media/content specifically */ - postSaveContent: function (args) { - - if (!args.restApiUrl) { - throw "args.restApiUrl is a required argument"; - } - if (!args.content) { - throw "args.content is a required argument"; - } - if (!args.action) { - throw "args.action is a required argument"; - } - if (!args.files) { - throw "args.files is a required argument"; - } - if (!args.dataFormatter) { - throw "args.dataFormatter is a required argument"; - } - - - var deferred = $q.defer(); - - //save the active tab id so we can set it when the data is returned. - var activeTab = _.find(args.content.tabs, function (item) { - return item.active; - }); - var activeTabIndex = (activeTab === undefined ? 0 : _.indexOf(args.content.tabs, activeTab)); - - //save the data - this.postMultiPartRequest( - args.restApiUrl, - { key: "contentItem", value: args.dataFormatter(args.content, args.action) }, - function (data, formData) { - //now add all of the assigned files - 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 - formData.append("file_" + args.files[f].alias, args.files[f].file); - } - - }, - function (data, status, headers, config) { - //success callback - - //reset the tabs and set the active one - if(data.tabs && data.tabs.length > 0) { - _.each(data.tabs, function (item) { - item.active = false; - }); - data.tabs[activeTabIndex].active = true; - } - - //the data returned is the up-to-date data so the UI will refresh - deferred.resolve(data); - }, - function (data, status, headers, config) { - //failure callback - - //when there's a 500 (unhandled) error show a YSOD overlay if debugging is enabled. - if (status >= 500 && status < 600) { - - //This is a bit of a hack to check if the error is due to a file being uploaded that is too large, - // we have to just check for the existence of a string value but currently that is the best way to - // do this since it's very hacky/difficult to catch this on the server - if (typeof data !== "undefined" && typeof data.indexOf === "function" && data.indexOf("Maximum request length exceeded") >= 0) { - notificationsService.error("Server error", "The uploaded file was too large, check with your site administrator to adjust the maximum size allowed"); - } - else if (Umbraco.Sys.ServerVariables["isDebuggingEnabled"] === true) { - //show a ysod dialog - eventsService.emit('app.ysod', - { - errorMsg: 'An error occured', - data: data - }); - } - else { - //show a simple error notification - notificationsService.error("Server error", "Contact administrator, see log for full details.
" + data.ExceptionMessage + ""); - } - - } - - //return an error object including the error message for UI - deferred.reject({ - errorMsg: 'An error occurred', - data: data, - status: status - }); - - - }); - - return deferred.promise; - }, - - /** Posts a multi-part mime request to the server */ - postMultiPartRequest: function (url, jsonData, transformCallback, successCallback, failureCallback) { - - //validate input, jsonData can be an array of key/value pairs or just one key/value pair. - if (!jsonData) { throw "jsonData cannot be null"; } - - if (angular.isArray(jsonData)) { - _.each(jsonData, function (item) { - if (!item.key || !item.value) { throw "jsonData array item must have both a key and a value property"; } - }); - } - else if (!jsonData.key || !jsonData.value) { throw "jsonData object must have both a key and a value property"; } - - - $http({ - method: 'POST', - url: url, - //IMPORTANT!!! You might think this should be set to 'multipart/form-data' but this is not true because when we are sending up files - // the request needs to include a 'boundary' parameter which identifies the boundary name between parts in this multi-part request - // and setting the Content-type manually will not set this boundary parameter. For whatever reason, setting the Content-type to 'false' - // will force the request to automatically populate the headers properly including the boundary parameter. - headers: { 'Content-Type': false }, - transformRequest: function (data) { - var formData = new FormData(); - //add the json data - if (angular.isArray(data)) { - _.each(data, function (item) { - formData.append(item.key, !angular.isString(item.value) ? angular.toJson(item.value) : item.value); - }); - } - else { - formData.append(data.key, !angular.isString(data.value) ? angular.toJson(data.value) : data.value); - } - - //call the callback - if (transformCallback) { - transformCallback.apply(this, [data, formData]); - } - - return formData; - }, - data: jsonData - }). - success(function (data, status, headers, config) { - if (successCallback) { - successCallback.apply(this, [data, status, headers, config]); - } - }). - error(function (data, status, headers, config) { - if (failureCallback) { - failureCallback.apply(this, [data, status, headers, config]); - } - }); - }, - - /** - * Downloads a file to the client using AJAX/XHR - * Based on an implementation here: web.student.tuwien.ac.at/~e0427417/jsdownload.html - * See https://stackoverflow.com/a/24129082/694494 - */ - downloadFile : function (httpPath) { - - var deferred = $q.defer(); - - // Use an arraybuffer - $http.get(httpPath, { responseType: 'arraybuffer' }) - .success(function (data, status, headers) { - - var octetStreamMime = 'application/octet-stream'; - var success = false; - - // Get the headers - headers = headers(); - - // Get the filename from the x-filename header or default to "download.bin" - var filename = headers['x-filename'] || 'download.bin'; - - // Determine the content type from the header or default to "application/octet-stream" - var contentType = headers['content-type'] || octetStreamMime; - - try { - // Try using msSaveBlob if supported - console.log("Trying saveBlob method ..."); - var blob = new Blob([data], { type: contentType }); - if (navigator.msSaveBlob) - navigator.msSaveBlob(blob, filename); - else { - // Try using other saveBlob implementations, if available - var saveBlob = navigator.webkitSaveBlob || navigator.mozSaveBlob || navigator.saveBlob; - if (saveBlob === undefined) throw "Not supported"; - saveBlob(blob, filename); - } - console.log("saveBlob succeeded"); - success = true; - } catch (ex) { - console.log("saveBlob method failed with the following exception:"); - console.log(ex); - } - - if (!success) { - // Get the blob url creator - var urlCreator = window.URL || window.webkitURL || window.mozURL || window.msURL; - if (urlCreator) { - // Try to use a download link - var link = document.createElement('a'); - if ('download' in link) { - // Try to simulate a click - try { - // Prepare a blob URL - console.log("Trying download link method with simulated click ..."); - var blob = new Blob([data], { type: contentType }); - var url = urlCreator.createObjectURL(blob); - link.setAttribute('href', url); - - // Set the download attribute (Supported in Chrome 14+ / Firefox 20+) - link.setAttribute("download", filename); - - // Simulate clicking the download link - var event = document.createEvent('MouseEvents'); - event.initMouseEvent('click', true, true, window, 1, 0, 0, 0, 0, false, false, false, false, 0, null); - link.dispatchEvent(event); - console.log("Download link method with simulated click succeeded"); - success = true; - - } catch (ex) { - console.log("Download link method with simulated click failed with the following exception:"); - console.log(ex); - } - } - - if (!success) { - // Fallback to window.location method - try { - // Prepare a blob URL - // Use application/octet-stream when using window.location to force download - console.log("Trying download link method with window.location ..."); - var blob = new Blob([data], { type: octetStreamMime }); - var url = urlCreator.createObjectURL(blob); - window.location = url; - console.log("Download link method with window.location succeeded"); - success = true; - } catch (ex) { - console.log("Download link method with window.location failed with the following exception:"); - console.log(ex); - } - } - - } - } - - if (!success) { - // Fallback to window.open method - console.log("No methods worked for saving the arraybuffer, using last resort window.open"); - window.open(httpPath, '_blank', ''); - } - - deferred.resolve(); - }) - .error(function (data, status) { - console.log("Request failed with status: " + status); - - deferred.reject({ - errorMsg: "An error occurred downloading the file", - data: data, - status: status - }); - }); - - return deferred.promise; - } - }; -} -angular.module('umbraco.services').factory('umbRequestHelper', umbRequestHelper); +/** +* @ngdoc service +* @name umbraco.services.umbRequestHelper +* @description A helper object used for sending requests to the server +**/ +function umbRequestHelper($http, $q, umbDataFormatter, angularHelper, dialogService, notificationsService, eventsService) { + return { + + /** + * @ngdoc method + * @name umbraco.services.umbRequestHelper#convertVirtualToAbsolutePath + * @methodOf umbraco.services.umbRequestHelper + * @function + * + * @description + * This will convert a virtual path (i.e. ~/App_Plugins/Blah/Test.html ) to an absolute path + * + * @param {string} a virtual path, if this is already an absolute path it will just be returned, if this is a relative path an exception will be thrown + */ + convertVirtualToAbsolutePath: function(virtualPath) { + if (virtualPath.startsWith("/")) { + return virtualPath; + } + if (!virtualPath.startsWith("~/")) { + throw "The path " + virtualPath + " is not a virtual path"; + } + if (!Umbraco.Sys.ServerVariables.application.applicationPath) { + throw "No applicationPath defined in Umbraco.ServerVariables.application.applicationPath"; + } + return Umbraco.Sys.ServerVariables.application.applicationPath + virtualPath.trimStart("~/"); + }, + + /** + * @ngdoc method + * @name umbraco.services.umbRequestHelper#dictionaryToQueryString + * @methodOf umbraco.services.umbRequestHelper + * @function + * + * @description + * This will turn an array of key/value pairs or a standard dictionary into a query string + * + * @param {Array} queryStrings An array of key/value pairs + */ + dictionaryToQueryString: function (queryStrings) { + + if (angular.isArray(queryStrings)) { + return _.map(queryStrings, function (item) { + var key = null; + var val = null; + for (var k in item) { + key = k; + val = item[k]; + break; + } + if (key === null || val === null) { + throw "The object in the array was not formatted as a key/value pair"; + } + return encodeURIComponent(key) + "=" + encodeURIComponent(val); + }).join("&"); + } + else if (angular.isObject(queryStrings)) { + + //this allows for a normal object to be passed in (ie. a dictionary) + return decodeURIComponent($.param(queryStrings)); + } + + throw "The queryString parameter is not an array or object of key value pairs"; + }, + + /** + * @ngdoc method + * @name umbraco.services.umbRequestHelper#getApiUrl + * @methodOf umbraco.services.umbRequestHelper + * @function + * + * @description + * This will return the webapi Url for the requested key based on the servervariables collection + * + * @param {string} apiName The webapi name that is found in the servervariables["umbracoUrls"] dictionary + * @param {string} actionName The webapi action name + * @param {object} queryStrings Can be either a string or an array containing key/value pairs + */ + getApiUrl: function (apiName, actionName, queryStrings) { + if (!Umbraco || !Umbraco.Sys || !Umbraco.Sys.ServerVariables || !Umbraco.Sys.ServerVariables["umbracoUrls"]) { + throw "No server variables defined!"; + } + + if (!Umbraco.Sys.ServerVariables["umbracoUrls"][apiName]) { + throw "No url found for api name " + apiName; + } + + return Umbraco.Sys.ServerVariables["umbracoUrls"][apiName] + actionName + + (!queryStrings ? "" : "?" + (angular.isString(queryStrings) ? queryStrings : this.dictionaryToQueryString(queryStrings))); + + }, + + /** + * @ngdoc function + * @name umbraco.services.umbRequestHelper#resourcePromise + * @methodOf umbraco.services.umbRequestHelper + * @function + * + * @description + * This returns a promise with an underlying http call, it is a helper method to reduce + * the amount of duplicate code needed to query http resources and automatically handle any + * Http errors. See /docs/source/using-promises-resources.md + * + * @param {object} opts A mixed object which can either be a string representing the error message to be + * returned OR an object containing either: + * { success: successCallback, errorMsg: errorMessage } + * OR + * { success: successCallback, error: errorCallback } + * In both of the above, the successCallback must accept these parameters: data, status, headers, config + * If using the errorCallback it must accept these parameters: data, status, headers, config + * The success callback must return the data which will be resolved by the deferred object. + * The error callback must return an object containing: {errorMsg: errorMessage, data: originalData, status: status } + */ + resourcePromise: function (httpPromise, opts) { + var deferred = $q.defer(); + + /** The default success callback used if one is not supplied in the opts */ + function defaultSuccess(data, status, headers, config) { + //when it's successful, just return the data + return data; + } + + /** The default error callback used if one is not supplied in the opts */ + function defaultError(data, status, headers, config) { + + var err = { + //NOTE: the default error message here should never be used based on the above docs! + errorMsg: (angular.isString(opts) ? opts : 'An error occurred!'), + data: data, + status: status + }; + + // if "opts" is a promise, we set "err.errorMsg" to be that promise + if (typeof(opts) == "object" && typeof(opts.then) == "function") { + err.errorMsg = opts; + } + + return err; + + } + + //create the callbacs based on whats been passed in. + var callbacks = { + success: ((!opts || !opts.success) ? defaultSuccess : opts.success), + error: ((!opts || !opts.error) ? defaultError : opts.error) + }; + + httpPromise.success(function (data, status, headers, config) { + + //invoke the callback + var result = callbacks.success.apply(this, [data, status, headers, config]); + + //when it's successful, just return the data + deferred.resolve(result); + + }).error(function (data, status, headers, config) { + + //invoke the callback + var result = callbacks.error.apply(this, [data, status, headers, config]); + + //when there's a 500 (unhandled) error show a YSOD overlay if debugging is enabled. + if (status >= 500 && status < 600) { + + //show a ysod dialog + if (Umbraco.Sys.ServerVariables["isDebuggingEnabled"] === true) { + eventsService.emit('app.ysod', + { + errorMsg: 'An error occured', + data: data + }); + } + else { + //show a simple error notification + notificationsService.error("Server error", "Contact administrator, see log for full details.
" + result.errorMsg + ""); + } + + } + + //return an error object including the error message for UI + deferred.reject({ + errorMsg: result.errorMsg, + data: result.data, + status: result.status + }); + + + }); + + return deferred.promise; + + }, + + /** Used for saving media/content specifically */ + postSaveContent: function (args) { + + if (!args.restApiUrl) { + throw "args.restApiUrl is a required argument"; + } + if (!args.content) { + throw "args.content is a required argument"; + } + if (!args.action) { + throw "args.action is a required argument"; + } + if (!args.files) { + throw "args.files is a required argument"; + } + if (!args.dataFormatter) { + throw "args.dataFormatter is a required argument"; + } + + + var deferred = $q.defer(); + + //save the active tab id so we can set it when the data is returned. + var activeTab = _.find(args.content.tabs, function (item) { + return item.active; + }); + var activeTabIndex = (activeTab === undefined ? 0 : _.indexOf(args.content.tabs, activeTab)); + + //save the data + this.postMultiPartRequest( + args.restApiUrl, + { key: "contentItem", value: args.dataFormatter(args.content, args.action) }, + function (data, formData) { + //now add all of the assigned files + 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 + formData.append("file_" + args.files[f].alias, args.files[f].file); + } + + }, + function (data, status, headers, config) { + //success callback + + //reset the tabs and set the active one + if(data.tabs && data.tabs.length > 0) { + _.each(data.tabs, function (item) { + item.active = false; + }); + data.tabs[activeTabIndex].active = true; + } + + //the data returned is the up-to-date data so the UI will refresh + deferred.resolve(data); + }, + function (data, status, headers, config) { + //failure callback + + //when there's a 500 (unhandled) error show a YSOD overlay if debugging is enabled. + if (status >= 500 && status < 600) { + + //This is a bit of a hack to check if the error is due to a file being uploaded that is too large, + // we have to just check for the existence of a string value but currently that is the best way to + // do this since it's very hacky/difficult to catch this on the server + if (typeof data !== "undefined" && typeof data.indexOf === "function" && data.indexOf("Maximum request length exceeded") >= 0) { + notificationsService.error("Server error", "The uploaded file was too large, check with your site administrator to adjust the maximum size allowed"); + } + else if (Umbraco.Sys.ServerVariables["isDebuggingEnabled"] === true) { + //show a ysod dialog + eventsService.emit('app.ysod', + { + errorMsg: 'An error occured', + data: data + }); + } + else { + //show a simple error notification + notificationsService.error("Server error", "Contact administrator, see log for full details.
" + data.ExceptionMessage + ""); + } + + } + + //return an error object including the error message for UI + deferred.reject({ + errorMsg: 'An error occurred', + data: data, + status: status + }); + + + }); + + return deferred.promise; + }, + + /** Posts a multi-part mime request to the server */ + postMultiPartRequest: function (url, jsonData, transformCallback, successCallback, failureCallback) { + + //validate input, jsonData can be an array of key/value pairs or just one key/value pair. + if (!jsonData) { throw "jsonData cannot be null"; } + + if (angular.isArray(jsonData)) { + _.each(jsonData, function (item) { + if (!item.key || !item.value) { throw "jsonData array item must have both a key and a value property"; } + }); + } + else if (!jsonData.key || !jsonData.value) { throw "jsonData object must have both a key and a value property"; } + + + $http({ + method: 'POST', + url: url, + //IMPORTANT!!! You might think this should be set to 'multipart/form-data' but this is not true because when we are sending up files + // the request needs to include a 'boundary' parameter which identifies the boundary name between parts in this multi-part request + // and setting the Content-type manually will not set this boundary parameter. For whatever reason, setting the Content-type to 'false' + // will force the request to automatically populate the headers properly including the boundary parameter. + headers: { 'Content-Type': false }, + transformRequest: function (data) { + var formData = new FormData(); + //add the json data + if (angular.isArray(data)) { + _.each(data, function (item) { + formData.append(item.key, !angular.isString(item.value) ? angular.toJson(item.value) : item.value); + }); + } + else { + formData.append(data.key, !angular.isString(data.value) ? angular.toJson(data.value) : data.value); + } + + //call the callback + if (transformCallback) { + transformCallback.apply(this, [data, formData]); + } + + return formData; + }, + data: jsonData + }). + success(function (data, status, headers, config) { + if (successCallback) { + successCallback.apply(this, [data, status, headers, config]); + } + }). + error(function (data, status, headers, config) { + if (failureCallback) { + failureCallback.apply(this, [data, status, headers, config]); + } + }); + }, + + /** + * Downloads a file to the client using AJAX/XHR + * Based on an implementation here: web.student.tuwien.ac.at/~e0427417/jsdownload.html + * See https://stackoverflow.com/a/24129082/694494 + */ + downloadFile : function (httpPath) { + + var deferred = $q.defer(); + + // Use an arraybuffer + $http.get(httpPath, { responseType: 'arraybuffer' }) + .success(function (data, status, headers) { + + var octetStreamMime = 'application/octet-stream'; + var success = false; + + // Get the headers + headers = headers(); + + // Get the filename from the x-filename header or default to "download.bin" + var filename = headers['x-filename'] || 'download.bin'; + + // Determine the content type from the header or default to "application/octet-stream" + var contentType = headers['content-type'] || octetStreamMime; + + try { + // Try using msSaveBlob if supported + console.log("Trying saveBlob method ..."); + var blob = new Blob([data], { type: contentType }); + if (navigator.msSaveBlob) + navigator.msSaveBlob(blob, filename); + else { + // Try using other saveBlob implementations, if available + var saveBlob = navigator.webkitSaveBlob || navigator.mozSaveBlob || navigator.saveBlob; + if (saveBlob === undefined) throw "Not supported"; + saveBlob(blob, filename); + } + console.log("saveBlob succeeded"); + success = true; + } catch (ex) { + console.log("saveBlob method failed with the following exception:"); + console.log(ex); + } + + if (!success) { + // Get the blob url creator + var urlCreator = window.URL || window.webkitURL || window.mozURL || window.msURL; + if (urlCreator) { + // Try to use a download link + var link = document.createElement('a'); + if ('download' in link) { + // Try to simulate a click + try { + // Prepare a blob URL + console.log("Trying download link method with simulated click ..."); + var blob = new Blob([data], { type: contentType }); + var url = urlCreator.createObjectURL(blob); + link.setAttribute('href', url); + + // Set the download attribute (Supported in Chrome 14+ / Firefox 20+) + link.setAttribute("download", filename); + + // Simulate clicking the download link + var event = document.createEvent('MouseEvents'); + event.initMouseEvent('click', true, true, window, 1, 0, 0, 0, 0, false, false, false, false, 0, null); + link.dispatchEvent(event); + console.log("Download link method with simulated click succeeded"); + success = true; + + } catch (ex) { + console.log("Download link method with simulated click failed with the following exception:"); + console.log(ex); + } + } + + if (!success) { + // Fallback to window.location method + try { + // Prepare a blob URL + // Use application/octet-stream when using window.location to force download + console.log("Trying download link method with window.location ..."); + var blob = new Blob([data], { type: octetStreamMime }); + var url = urlCreator.createObjectURL(blob); + window.location = url; + console.log("Download link method with window.location succeeded"); + success = true; + } catch (ex) { + console.log("Download link method with window.location failed with the following exception:"); + console.log(ex); + } + } + + } + } + + if (!success) { + // Fallback to window.open method + console.log("No methods worked for saving the arraybuffer, using last resort window.open"); + window.open(httpPath, '_blank', ''); + } + + deferred.resolve(); + }) + .error(function (data, status) { + console.log("Request failed with status: " + status); + + deferred.reject({ + errorMsg: "An error occurred downloading the file", + data: data, + status: status + }); + }); + + return deferred.promise; + } + }; +} +angular.module('umbraco.services').factory('umbRequestHelper', umbRequestHelper); From 96d7a776b7eddf8a21d4c59079adefafb79c292f Mon Sep 17 00:00:00 2001 From: Sebastiaan Janssen Date: Sun, 21 Oct 2018 18:17:08 +0200 Subject: [PATCH 91/98] Removes dangling comma --- .../common/directives/components/umbGenerateAlias.directive.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Umbraco.Web.UI.Client/src/common/directives/components/umbGenerateAlias.directive.js b/src/Umbraco.Web.UI.Client/src/common/directives/components/umbGenerateAlias.directive.js index b3accc18b4..9b4bd17a12 100644 --- a/src/Umbraco.Web.UI.Client/src/common/directives/components/umbGenerateAlias.directive.js +++ b/src/Umbraco.Web.UI.Client/src/common/directives/components/umbGenerateAlias.directive.js @@ -70,7 +70,7 @@ angular.module("umbraco.directives") scope.labels = { idle: "Enter alias...", - busy: "Generating alias...", + busy: "Generating alias..." }; scope.placeholderText = scope.labels.idle; From 10526cfc81f3197336e6bdb543841aee5adfde50 Mon Sep 17 00:00:00 2001 From: Kenn Jacobsen Date: Sun, 21 Oct 2018 12:39:20 +0200 Subject: [PATCH 92/98] Fix #3368 by watching changes and explicitly flagging the form as dirty --- .../src/views/documenttypes/edit.controller.js | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/src/Umbraco.Web.UI.Client/src/views/documenttypes/edit.controller.js b/src/Umbraco.Web.UI.Client/src/views/documenttypes/edit.controller.js index 289bf607c3..cafe91e0eb 100644 --- a/src/Umbraco.Web.UI.Client/src/views/documenttypes/edit.controller.js +++ b/src/Umbraco.Web.UI.Client/src/views/documenttypes/edit.controller.js @@ -9,7 +9,7 @@ (function () { "use strict"; - function DocumentTypesEditController($scope, $routeParams, $injector, contentTypeResource, dataTypeResource, editorState, contentEditingHelper, formHelper, navigationService, iconHelper, contentTypeHelper, notificationsService, $filter, $q, localizationService, overlayHelper, eventsService) { + function DocumentTypesEditController($scope, $routeParams, $injector, contentTypeResource, dataTypeResource, editorState, contentEditingHelper, formHelper, navigationService, iconHelper, contentTypeHelper, notificationsService, $filter, $q, localizationService, overlayHelper, eventsService, angularHelper) { var vm = this; var localizeSaving = localizationService.localize("general_saving"); @@ -375,6 +375,15 @@ eventsService.unsubscribe(evts[e]); } }); + + // #3368 - changes on the other "buttons" do not register on the current form, so we manually have to flag the form as dirty + $scope.$watch("vm.contentType.allowedContentTypes.length + vm.contentType.allowAsRoot + vm.contentType.allowedTemplates.length + vm.contentType.isContainer", function (newVal, oldVal) { + if (oldVal === undefined) { + // still initializing, ignore + return; + } + angularHelper.getCurrentForm($scope).$setDirty(); + }); } angular.module("umbraco").controller("Umbraco.Editors.DocumentTypes.EditController", DocumentTypesEditController); From 2c14f396fbbe5c529e76068e64404d63e02e954b Mon Sep 17 00:00:00 2001 From: Tim Geyssens Date: Thu, 18 Oct 2018 21:28:46 +0200 Subject: [PATCH 93/98] Update FileSystemTree.cs Make sure it can find child items in root folders --- .../umbraco.presentation/umbraco/Trees/FileSystemTree.cs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/Umbraco.Web/umbraco.presentation/umbraco/Trees/FileSystemTree.cs b/src/Umbraco.Web/umbraco.presentation/umbraco/Trees/FileSystemTree.cs index aed6009d86..06a5863da3 100644 --- a/src/Umbraco.Web/umbraco.presentation/umbraco/Trees/FileSystemTree.cs +++ b/src/Umbraco.Web/umbraco.presentation/umbraco/Trees/FileSystemTree.cs @@ -42,8 +42,7 @@ namespace umbraco.cms.presentation.Trees if (!string.IsNullOrEmpty(this.NodeKey)) { orgPath = this.NodeKey; - path = IOHelper.MapPath(FilePath + orgPath); - orgPath += "/"; + path = IOHelper.MapPath(FilePath+ "/" + orgPath + "/"); } else { From 04aa1992667666d1768ef9d2afaa5483d76614b1 Mon Sep 17 00:00:00 2001 From: Sebastiaan Janssen Date: Sun, 21 Oct 2018 18:57:07 +0200 Subject: [PATCH 94/98] Makes sure the path on the tree is correct --- .../umbraco.presentation/umbraco/Trees/FileSystemTree.cs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/Umbraco.Web/umbraco.presentation/umbraco/Trees/FileSystemTree.cs b/src/Umbraco.Web/umbraco.presentation/umbraco/Trees/FileSystemTree.cs index 06a5863da3..35a5b3129a 100644 --- a/src/Umbraco.Web/umbraco.presentation/umbraco/Trees/FileSystemTree.cs +++ b/src/Umbraco.Web/umbraco.presentation/umbraco/Trees/FileSystemTree.cs @@ -8,6 +8,7 @@ using System.Web.UI.WebControls; using System.Web.UI.WebControls.WebParts; using System.Web.UI.HtmlControls; using System.IO; +using Umbraco.Core; using Umbraco.Core.IO; namespace umbraco.cms.presentation.Trees @@ -41,8 +42,8 @@ namespace umbraco.cms.presentation.Trees string path = ""; if (!string.IsNullOrEmpty(this.NodeKey)) { - orgPath = this.NodeKey; - path = IOHelper.MapPath(FilePath+ "/" + orgPath + "/"); + orgPath = this.NodeKey.EnsureEndsWith('/'); + path = IOHelper.MapPath($"{FilePath.EnsureEndsWith('/')}{orgPath}"); } else { From dadc3ad7a7c4c5dcebe8edc18d6e041c7e5f708f Mon Sep 17 00:00:00 2001 From: James Coxhead Date: Thu, 18 Oct 2018 22:08:03 +0100 Subject: [PATCH 95/98] Fixes #3348 - Configure Umbraco.Dropdown.Flexible for new installations --- .../Persistence/Migrations/Initial/BaseDataCreation.cs | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/src/Umbraco.Core/Persistence/Migrations/Initial/BaseDataCreation.cs b/src/Umbraco.Core/Persistence/Migrations/Initial/BaseDataCreation.cs index d98bd81bfd..b8e605e63e 100644 --- a/src/Umbraco.Core/Persistence/Migrations/Initial/BaseDataCreation.cs +++ b/src/Umbraco.Core/Persistence/Migrations/Initial/BaseDataCreation.cs @@ -256,10 +256,10 @@ namespace Umbraco.Core.Persistence.Migrations.Initial _database.Insert("cmsDataType", "pk", false, new DataTypeDto { PrimaryKey = 7, DataTypeId = -92, PropertyEditorAlias = Constants.PropertyEditors.NoEditAlias, DbType = "Nvarchar" }); _database.Insert("cmsDataType", "pk", false, new DataTypeDto { PrimaryKey = 8, DataTypeId = -36, PropertyEditorAlias = Constants.PropertyEditors.DateTimeAlias, DbType = "Date" }); _database.Insert("cmsDataType", "pk", false, new DataTypeDto { PrimaryKey = 9, DataTypeId = -37, PropertyEditorAlias = Constants.PropertyEditors.ColorPickerAlias, DbType = "Nvarchar" }); - _database.Insert("cmsDataType", "pk", false, new DataTypeDto { PrimaryKey = 11, DataTypeId = -39, PropertyEditorAlias = Constants.PropertyEditors.DropDownListMultipleAlias, DbType = "Nvarchar" }); + _database.Insert("cmsDataType", "pk", false, new DataTypeDto { PrimaryKey = 11, DataTypeId = -39, PropertyEditorAlias = Constants.PropertyEditors.DropDownListFlexibleAlias, DbType = "Nvarchar" }); _database.Insert("cmsDataType", "pk", false, new DataTypeDto { PrimaryKey = 12, DataTypeId = -40, PropertyEditorAlias = Constants.PropertyEditors.RadioButtonListAlias, DbType = "Nvarchar" }); _database.Insert("cmsDataType", "pk", false, new DataTypeDto { PrimaryKey = 13, DataTypeId = -41, PropertyEditorAlias = Constants.PropertyEditors.DateAlias, DbType = "Date" }); - _database.Insert("cmsDataType", "pk", false, new DataTypeDto { PrimaryKey = 14, DataTypeId = -42, PropertyEditorAlias = Constants.PropertyEditors.DropDownListAlias, DbType = "Integer" }); + _database.Insert("cmsDataType", "pk", false, new DataTypeDto { PrimaryKey = 14, DataTypeId = -42, PropertyEditorAlias = Constants.PropertyEditors.DropDownListFlexibleAlias, DbType = "Integer" }); _database.Insert("cmsDataType", "pk", false, new DataTypeDto { PrimaryKey = 15, DataTypeId = -43, PropertyEditorAlias = Constants.PropertyEditors.CheckBoxListAlias, DbType = "Nvarchar" }); _database.Insert("cmsDataType", "pk", false, new DataTypeDto { PrimaryKey = 22, DataTypeId = 1041, PropertyEditorAlias = Constants.PropertyEditors.TagsAlias, DbType = "Ntext" }); _database.Insert("cmsDataType", "pk", false, new DataTypeDto { PrimaryKey = 24, DataTypeId = 1043, PropertyEditorAlias = Constants.PropertyEditors.ImageCropperAlias, DbType = "Ntext" }); @@ -300,6 +300,12 @@ namespace Umbraco.Core.Persistence.Migrations.Initial //default's for MultipleMediaPickerAlias picker _database.Insert("cmsDataTypePreValues", "id", false, new DataTypePreValueDto { Id = 6, Alias = "multiPicker", SortOrder = 0, DataTypeNodeId = 1049, Value = "1" }); + + // Defaults for single item dropdown + _database.Insert("cmsDataTypePreValues", "id", false, new DataTypePreValueDto { Id = 7, Alias = "multiple", SortOrder = 0, DataTypeNodeId = -42, Value = "0" }); + + // Defaults for multiple item dropdown + _database.Insert("cmsDataTypePreValues", "id", false, new DataTypePreValueDto { Id = 8, Alias = "multiple", SortOrder = 0, DataTypeNodeId = -39, Value = "1" }); } private void CreateUmbracoRelationTypeData() From 8c8d979eb20214e9c168ff831d5bc0a8afda98f3 Mon Sep 17 00:00:00 2001 From: Kenn Jacobsen Date: Thu, 11 Oct 2018 08:48:55 +0200 Subject: [PATCH 96/98] Style confirmations and alerts consistently across all sections (#3251) --- .../src/views/datatypes/move.html | 10 +++++++--- .../src/views/datatypes/rename.html | 6 ++++-- .../src/views/documenttypes/copy.html | 11 +++++++---- .../src/views/documenttypes/create.html | 12 ++++++++---- .../src/views/documenttypes/move.html | 11 +++++++---- .../src/views/documenttypes/rename.html | 6 ++++-- .../src/views/mediatypes/copy.html | 11 +++++++---- .../src/views/mediatypes/move.html | 10 +++++++--- .../src/views/mediatypes/rename.html | 6 ++++-- .../src/views/partialviewmacros/create.html | 6 ++++-- .../src/views/partialviews/create.html | 6 ++++-- .../src/views/scripts/create.html | 6 ++++-- 12 files changed, 67 insertions(+), 34 deletions(-) diff --git a/src/Umbraco.Web.UI.Client/src/views/datatypes/move.html b/src/Umbraco.Web.UI.Client/src/views/datatypes/move.html index f05b8a6c79..0546cbff44 100644 --- a/src/Umbraco.Web.UI.Client/src/views/datatypes/move.html +++ b/src/Umbraco.Web.UI.Client/src/views/datatypes/move.html @@ -12,12 +12,16 @@
-
{{error.errorMsg}}
-

{{error.data.message}}

+
+
{{error.errorMsg}}
+
{{error.data.message}}
+
-
{{currentNode.name}} was moved underneath {{target.name}}
+
+ {{currentNode.name}} was moved underneath {{target.name}} +
diff --git a/src/Umbraco.Web.UI.Client/src/views/datatypes/rename.html b/src/Umbraco.Web.UI.Client/src/views/datatypes/rename.html index 6840e58565..ec93009a4c 100644 --- a/src/Umbraco.Web.UI.Client/src/views/datatypes/rename.html +++ b/src/Umbraco.Web.UI.Client/src/views/datatypes/rename.html @@ -7,8 +7,10 @@ val-form-manager>
-
{{error.errorMsg}}
-

{{error.data.message}}

+
+
{{error.errorMsg}}
+
{{error.data.message}}
+
diff --git a/src/Umbraco.Web.UI.Client/src/views/documenttypes/copy.html b/src/Umbraco.Web.UI.Client/src/views/documenttypes/copy.html index 2976f65917..97de821909 100644 --- a/src/Umbraco.Web.UI.Client/src/views/documenttypes/copy.html +++ b/src/Umbraco.Web.UI.Client/src/views/documenttypes/copy.html @@ -12,13 +12,16 @@
-
{{error.errorMsg}}
-

{{error.data.message}}

+
+
{{error.errorMsg}}
+
{{error.data.message}}
+
-
- {{currentNode.name}} was copied underneath {{target.name}}
+
+ {{currentNode.name}} was copied underneath {{target.name}} +
diff --git a/src/Umbraco.Web.UI.Client/src/views/documenttypes/create.html b/src/Umbraco.Web.UI.Client/src/views/documenttypes/create.html index 3519195848..b4818a51ab 100644 --- a/src/Umbraco.Web.UI.Client/src/views/documenttypes/create.html +++ b/src/Umbraco.Web.UI.Client/src/views/documenttypes/create.html @@ -50,8 +50,10 @@ val-form-manager>
-
{{error.errorMsg}}
-

{{error.data.message}}

+
+
{{error.errorMsg}}
+
{{error.data.message}}
+
@@ -74,8 +76,10 @@ val-form-manager>
-
{{error.errorMsg}}
-

{{error.data.message}}

+
+
{{error.errorMsg}}
+
{{error.data.message}}
+
diff --git a/src/Umbraco.Web.UI.Client/src/views/documenttypes/move.html b/src/Umbraco.Web.UI.Client/src/views/documenttypes/move.html index 1ed224b5ba..0af4cbfda7 100644 --- a/src/Umbraco.Web.UI.Client/src/views/documenttypes/move.html +++ b/src/Umbraco.Web.UI.Client/src/views/documenttypes/move.html @@ -12,13 +12,16 @@
-
{{error.errorMsg}}
-

{{error.data.message}}

+
+
{{error.errorMsg}}
+
{{error.data.message}}
+
-
- {{currentNode.name}} was moved underneath {{target.name}}
+
+ {{currentNode.name}} was moved underneath {{target.name}} +
diff --git a/src/Umbraco.Web.UI.Client/src/views/documenttypes/rename.html b/src/Umbraco.Web.UI.Client/src/views/documenttypes/rename.html index f739cadb71..c52b3be6d6 100644 --- a/src/Umbraco.Web.UI.Client/src/views/documenttypes/rename.html +++ b/src/Umbraco.Web.UI.Client/src/views/documenttypes/rename.html @@ -6,8 +6,10 @@ val-form-manager>
-
{{error.errorMsg}}
-

{{error.data.message}}

+
+
{{error.errorMsg}}
+
{{error.data.message}}
+
diff --git a/src/Umbraco.Web.UI.Client/src/views/mediatypes/copy.html b/src/Umbraco.Web.UI.Client/src/views/mediatypes/copy.html index fcc26b9928..77f50358c3 100644 --- a/src/Umbraco.Web.UI.Client/src/views/mediatypes/copy.html +++ b/src/Umbraco.Web.UI.Client/src/views/mediatypes/copy.html @@ -12,13 +12,16 @@
-
{{error.errorMsg}}
-

{{error.data.message}}

+
+
{{error.errorMsg}}
+
{{error.data.message}}
+
-
- {{currentNode.name}} was copied underneath {{target.name}}
+
+ {{currentNode.name}} was copied underneath {{target.name}} +
diff --git a/src/Umbraco.Web.UI.Client/src/views/mediatypes/move.html b/src/Umbraco.Web.UI.Client/src/views/mediatypes/move.html index 18f7aee337..c240925a7d 100644 --- a/src/Umbraco.Web.UI.Client/src/views/mediatypes/move.html +++ b/src/Umbraco.Web.UI.Client/src/views/mediatypes/move.html @@ -12,12 +12,16 @@
-
{{error.errorMsg}}
-

{{error.data.message}}

+
+
{{error.errorMsg}}
+
{{error.data.message}}
+
-
{{currentNode.name}} was moved underneath {{target.name}}
+
+ {{currentNode.name}} was moved underneath {{target.name}} +
diff --git a/src/Umbraco.Web.UI.Client/src/views/mediatypes/rename.html b/src/Umbraco.Web.UI.Client/src/views/mediatypes/rename.html index 5f027cf607..0bc4aa5123 100644 --- a/src/Umbraco.Web.UI.Client/src/views/mediatypes/rename.html +++ b/src/Umbraco.Web.UI.Client/src/views/mediatypes/rename.html @@ -6,8 +6,10 @@ val-form-manager>
-
{{error.errorMsg}}
-

{{error.data.message}}

+
+
{{error.errorMsg}}
+
{{error.data.message}}
+
diff --git a/src/Umbraco.Web.UI.Client/src/views/partialviewmacros/create.html b/src/Umbraco.Web.UI.Client/src/views/partialviewmacros/create.html index febaaab646..e2c7ab0af6 100644 --- a/src/Umbraco.Web.UI.Client/src/views/partialviewmacros/create.html +++ b/src/Umbraco.Web.UI.Client/src/views/partialviewmacros/create.html @@ -61,8 +61,10 @@ val-form-manager>
-
{{vm.createFolderError.errorMsg}}
-

{{vm.createFolderError.data.message}}

+
+
{{vm.createFolderError.errorMsg}}
+
{{vm.createFolderError.data.message}}
+
diff --git a/src/Umbraco.Web.UI.Client/src/views/partialviews/create.html b/src/Umbraco.Web.UI.Client/src/views/partialviews/create.html index 7dc4268ce1..4d15ab6c01 100644 --- a/src/Umbraco.Web.UI.Client/src/views/partialviews/create.html +++ b/src/Umbraco.Web.UI.Client/src/views/partialviews/create.html @@ -51,8 +51,10 @@ val-form-manager>
-
{{vm.createFolderError.errorMsg}}
-

{{vm.createFolderError.data.message}}

+
+
{{vm.createFolderError.errorMsg}}
+
{{vm.createFolderError.data.message}}
+
diff --git a/src/Umbraco.Web.UI.Client/src/views/scripts/create.html b/src/Umbraco.Web.UI.Client/src/views/scripts/create.html index f7d8b0382d..6cda42f21a 100644 --- a/src/Umbraco.Web.UI.Client/src/views/scripts/create.html +++ b/src/Umbraco.Web.UI.Client/src/views/scripts/create.html @@ -26,8 +26,10 @@ val-form-manager>
-
{{vm.createFolderError.errorMsg}}
-

{{vm.createFolderError.data.message}}

+
+
{{vm.createFolderError.errorMsg}}
+
{{vm.createFolderError.data.message}}
+
From b86be5b854f0b3d7bf5964bf7cab52f08ffc659d Mon Sep 17 00:00:00 2001 From: Bjarne Fyrstenborg Date: Thu, 11 Oct 2018 00:44:04 +0200 Subject: [PATCH 97/98] Fix color swatches title when using css classes for colors --- .../src/views/components/umb-color-swatches.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Umbraco.Web.UI.Client/src/views/components/umb-color-swatches.html b/src/Umbraco.Web.UI.Client/src/views/components/umb-color-swatches.html index d038c9973c..2bc7ce9622 100644 --- a/src/Umbraco.Web.UI.Client/src/views/components/umb-color-swatches.html +++ b/src/Umbraco.Web.UI.Client/src/views/components/umb-color-swatches.html @@ -1,6 +1,6 @@ 
-