diff --git a/build/NuSpecs/UmbracoCms.Web.nuspec b/build/NuSpecs/UmbracoCms.Web.nuspec index 658d2f0672..347bde139e 100644 --- a/build/NuSpecs/UmbracoCms.Web.nuspec +++ b/build/NuSpecs/UmbracoCms.Web.nuspec @@ -28,7 +28,7 @@ - + diff --git a/src/Umbraco.Core/Composing/ComponentCollection.cs b/src/Umbraco.Core/Composing/ComponentCollection.cs index fa4a1849b6..62b240f10f 100644 --- a/src/Umbraco.Core/Composing/ComponentCollection.cs +++ b/src/Umbraco.Core/Composing/ComponentCollection.cs @@ -51,7 +51,7 @@ namespace Umbraco.Core.Composing } catch (Exception ex) { - _logger.Error(componentType, ex, "Error while terminating component {ComponentType}.", componentType.FullName); + _logger.Error(ex, "Error while terminating component {ComponentType}.", componentType.FullName); } } } diff --git a/src/Umbraco.Core/ContentVariationExtensions.cs b/src/Umbraco.Core/ContentVariationExtensions.cs index 5b157307ab..fe5a82047a 100644 --- a/src/Umbraco.Core/ContentVariationExtensions.cs +++ b/src/Umbraco.Core/ContentVariationExtensions.cs @@ -19,6 +19,11 @@ namespace Umbraco.Core /// public static bool VariesByCulture(this ISimpleContentType contentType) => contentType.Variations.VariesByCulture(); + /// + /// Determines whether the content type varies by segment. + /// + public static bool VariesBySegment(this ISimpleContentType contentType) => contentType.Variations.VariesBySegment(); + /// /// Determines whether the content type is invariant. /// diff --git a/src/Umbraco.Examine/Umbraco.Examine.csproj b/src/Umbraco.Examine/Umbraco.Examine.csproj index 7eff1bddc2..0e0ee62139 100644 --- a/src/Umbraco.Examine/Umbraco.Examine.csproj +++ b/src/Umbraco.Examine/Umbraco.Examine.csproj @@ -49,7 +49,7 @@ - + 1.0.0-beta2-19324-01 runtime; build; native; contentfiles; analyzers; buildtransitive @@ -112,4 +112,4 @@ - + \ No newline at end of file diff --git a/src/Umbraco.ModelsBuilder.Embedded/Compose/ModelsBuilderComposer.cs b/src/Umbraco.ModelsBuilder.Embedded/Compose/ModelsBuilderComposer.cs index c6924e3abe..45c4de5d2a 100644 --- a/src/Umbraco.ModelsBuilder.Embedded/Compose/ModelsBuilderComposer.cs +++ b/src/Umbraco.ModelsBuilder.Embedded/Compose/ModelsBuilderComposer.cs @@ -22,6 +22,9 @@ namespace Umbraco.ModelsBuilder.Embedded.Compose { var isLegacyModelsBuilderInstalled = IsLegacyModelsBuilderInstalled(); + + composition.Configs.Add(() => new ModelsBuilderConfig()); + if (isLegacyModelsBuilderInstalled) { ComposeForLegacyModelsBuilder(composition); @@ -30,7 +33,7 @@ namespace Umbraco.ModelsBuilder.Embedded.Compose composition.Components().Append(); composition.Register(Lifetime.Singleton); - composition.Configs.Add(() => new ModelsBuilderConfig()); + composition.RegisterUnique(); composition.RegisterUnique(); composition.RegisterUnique(); diff --git a/src/Umbraco.Tests/Umbraco.Tests.csproj b/src/Umbraco.Tests/Umbraco.Tests.csproj index 06f41b21c6..15c8eec0e1 100644 --- a/src/Umbraco.Tests/Umbraco.Tests.csproj +++ b/src/Umbraco.Tests/Umbraco.Tests.csproj @@ -79,7 +79,7 @@ - + 1.8.14 diff --git a/src/Umbraco.Web.UI.Client/src/common/directives/components/buttons/umbtoggle.directive.js b/src/Umbraco.Web.UI.Client/src/common/directives/components/buttons/umbtoggle.directive.js index 5d34ad2906..79cb99cf07 100644 --- a/src/Umbraco.Web.UI.Client/src/common/directives/components/buttons/umbtoggle.directive.js +++ b/src/Umbraco.Web.UI.Client/src/common/directives/components/buttons/umbtoggle.directive.js @@ -75,6 +75,8 @@ scope.displayLabelOff = ""; function onInit() { + scope.inputId = scope.inputId || "umb-toggle_" + String.CreateGuid(); + setLabelText(); // must wait until the current digest cycle is finished before we emit this event on init, // otherwise other property editors might not yet be ready to receive the event diff --git a/src/Umbraco.Web.UI.Client/src/common/directives/components/forms/umbcheckbox.directive.js b/src/Umbraco.Web.UI.Client/src/common/directives/components/forms/umbcheckbox.directive.js index ff51b1ae90..d562b21d52 100644 --- a/src/Umbraco.Web.UI.Client/src/common/directives/components/forms/umbcheckbox.directive.js +++ b/src/Umbraco.Web.UI.Client/src/common/directives/components/forms/umbcheckbox.directive.js @@ -46,6 +46,8 @@ vm.change = change; function onInit() { + vm.inputId = vm.inputId || "umb-check_" + String.CreateGuid(); + // If a labelKey is passed let's update the returned text if it's does not contain an opening square bracket [ if (vm.labelKey) { localizationService.localize(vm.labelKey).then(function (data) { diff --git a/src/Umbraco.Web.UI.Client/src/common/directives/components/forms/umbradiobutton.directive.js b/src/Umbraco.Web.UI.Client/src/common/directives/components/forms/umbradiobutton.directive.js index f3ecac2a74..7ed84547f1 100644 --- a/src/Umbraco.Web.UI.Client/src/common/directives/components/forms/umbradiobutton.directive.js +++ b/src/Umbraco.Web.UI.Client/src/common/directives/components/forms/umbradiobutton.directive.js @@ -44,6 +44,8 @@ vm.change = change; function onInit() { + vm.inputId = vm.inputId || "umb-radio_" + String.CreateGuid(); + // If a labelKey is passed let's update the returned text if it's does not contain an opening square bracket [ if (vm.labelKey) { localizationService.localize(vm.labelKey).then(function (data) { diff --git a/src/Umbraco.Web.UI.Client/src/common/services/editor.service.js b/src/Umbraco.Web.UI.Client/src/common/services/editor.service.js index 8b922d7ec8..1d80d3a3ed 100644 --- a/src/Umbraco.Web.UI.Client/src/common/services/editor.service.js +++ b/src/Umbraco.Web.UI.Client/src/common/services/editor.service.js @@ -367,7 +367,7 @@ When building a custom infinite editor view you can use the same components as a */ function contentPicker(editor) { editor.view = "views/common/infiniteeditors/treepicker/treepicker.html"; - editor.size = "small"; + if (!editor.size) editor.size = "small"; editor.section = "content"; editor.treeAlias = "content"; open(editor); @@ -390,7 +390,7 @@ When building a custom infinite editor view you can use the same components as a */ function contentTypePicker(editor) { editor.view = "views/common/infiniteeditors/treepicker/treepicker.html"; - editor.size = "small"; + if (!editor.size) editor.size = "small"; editor.section = "settings"; editor.treeAlias = "documentTypes"; open(editor); @@ -413,7 +413,7 @@ When building a custom infinite editor view you can use the same components as a */ function mediaTypePicker(editor) { editor.view = "views/common/infiniteeditors/treepicker/treepicker.html"; - editor.size = "small"; + if (!editor.size) editor.size = "small"; editor.section = "settings"; editor.treeAlias = "mediaTypes"; open(editor); @@ -436,7 +436,7 @@ When building a custom infinite editor view you can use the same components as a */ function memberTypePicker(editor) { editor.view = "views/common/infiniteeditors/treepicker/treepicker.html"; - editor.size = "small"; + if (!editor.size) editor.size = "small"; editor.section = "settings"; editor.treeAlias = "memberTypes"; open(editor); @@ -457,7 +457,7 @@ When building a custom infinite editor view you can use the same components as a function copy(editor) { editor.view = "views/common/infiniteeditors/copy/copy.html"; - editor.size = "small"; + if (!editor.size) editor.size = "small"; open(editor); } @@ -477,7 +477,7 @@ When building a custom infinite editor view you can use the same components as a function move(editor) { editor.view = "views/common/infiniteeditors/move/move.html"; - editor.size = "small"; + if (!editor.size) editor.size = "small"; open(editor); } @@ -495,7 +495,7 @@ When building a custom infinite editor view you can use the same components as a function embed(editor) { editor.view = "views/common/infiniteeditors/embed/embed.html"; - editor.size = "small"; + if (!editor.size) editor.size = "small"; open(editor); } @@ -514,7 +514,7 @@ When building a custom infinite editor view you can use the same components as a function rollback(editor) { editor.view = "views/common/infiniteeditors/rollback/rollback.html"; - editor.size = "small"; + if (!editor.size) editor.size = "small"; open(editor); } @@ -534,7 +534,7 @@ When building a custom infinite editor view you can use the same components as a */ function linkPicker(editor) { editor.view = "views/common/infiniteeditors/linkpicker/linkpicker.html"; - editor.size = "small"; + if (!editor.size) editor.size = "small"; open(editor); } @@ -577,7 +577,7 @@ When building a custom infinite editor view you can use the same components as a */ function mediaPicker(editor) { editor.view = "views/common/infiniteeditors/mediapicker/mediapicker.html"; - editor.size = "small"; + if (!editor.size) editor.size = "small"; editor.updatedMediaNodes = []; open(editor); } @@ -598,7 +598,7 @@ When building a custom infinite editor view you can use the same components as a */ function iconPicker(editor) { editor.view = "views/common/infiniteeditors/iconpicker/iconpicker.html"; - editor.size = "small"; + if (!editor.size) editor.size = "small"; open(editor); } @@ -692,7 +692,7 @@ When building a custom infinite editor view you can use the same components as a */ function treePicker(editor) { editor.view = "views/common/infiniteeditors/treepicker/treepicker.html"; - editor.size = "small"; + if (!editor.size) editor.size = "small"; open(editor); } @@ -710,7 +710,7 @@ When building a custom infinite editor view you can use the same components as a */ function nodePermissions(editor) { editor.view = "views/common/infiniteeditors/nodepermissions/nodepermissions.html"; - editor.size = "small"; + if (!editor.size) editor.size = "small"; open(editor); } @@ -728,7 +728,7 @@ When building a custom infinite editor view you can use the same components as a */ function insertCodeSnippet(editor) { editor.view = "views/common/infiniteeditors/insertcodesnippet/insertcodesnippet.html"; - editor.size = "small"; + if (!editor.size) editor.size = "small"; open(editor); } @@ -746,7 +746,7 @@ When building a custom infinite editor view you can use the same components as a */ function userGroupPicker(editor) { editor.view = "views/common/infiniteeditors/usergrouppicker/usergrouppicker.html"; - editor.size = "small"; + if (!editor.size) editor.size = "small"; open(editor); } @@ -782,7 +782,7 @@ When building a custom infinite editor view you can use the same components as a */ function sectionPicker(editor) { editor.view = "views/common/infiniteeditors/sectionpicker/sectionpicker.html"; - editor.size = "small"; + if (!editor.size) editor.size = "small"; open(editor); } @@ -800,7 +800,7 @@ When building a custom infinite editor view you can use the same components as a */ function insertField(editor) { editor.view = "views/common/infiniteeditors/insertfield/insertfield.html"; - editor.size = "small"; + if (!editor.size) editor.size = "small"; open(editor); } @@ -818,7 +818,7 @@ When building a custom infinite editor view you can use the same components as a */ function templateSections(editor) { editor.view = "views/common/infiniteeditors/templatesections/templatesections.html"; - editor.size = "small"; + if (!editor.size) editor.size = "small"; open(editor); } @@ -836,7 +836,7 @@ When building a custom infinite editor view you can use the same components as a */ function userPicker(editor) { editor.view = "views/common/infiniteeditors/userpicker/userpicker.html"; - editor.size = "small"; + if (!editor.size) editor.size = "small"; open(editor); } @@ -858,7 +858,7 @@ When building a custom infinite editor view you can use the same components as a */ function itemPicker(editor) { editor.view = "views/common/infiniteeditors/itempicker/itempicker.html"; - editor.size = "small"; + if (!editor.size) editor.size = "small"; open(editor); } @@ -876,7 +876,7 @@ When building a custom infinite editor view you can use the same components as a */ function macroPicker(editor) { editor.view = "views/common/infiniteeditors/macropicker/macropicker.html"; - editor.size = "small"; + if (!editor.size) editor.size = "small"; open(editor); } @@ -896,7 +896,7 @@ When building a custom infinite editor view you can use the same components as a */ function memberGroupPicker(editor) { editor.view = "views/common/infiniteeditors/membergrouppicker/membergrouppicker.html"; - editor.size = "small"; + if (!editor.size) editor.size = "small"; open(editor); } @@ -917,7 +917,7 @@ When building a custom infinite editor view you can use the same components as a */ function memberPicker(editor) { editor.view = "views/common/infiniteeditors/treepicker/treepicker.html"; - editor.size = "small"; + if (!editor.size) editor.size = "small"; editor.section = "member"; editor.treeAlias = "member"; open(editor); diff --git a/src/Umbraco.Web.UI.Client/src/common/services/notifications.service.js b/src/Umbraco.Web.UI.Client/src/common/services/notifications.service.js index c123ac6cea..e5701b9de0 100644 --- a/src/Umbraco.Web.UI.Client/src/common/services/notifications.service.js +++ b/src/Umbraco.Web.UI.Client/src/common/services/notifications.service.js @@ -148,7 +148,7 @@ angular.module('umbraco.services') break; case 1: //info - this.success(args.header, args.message); + this.info(args.header, args.message); break; case 2: //error @@ -297,4 +297,4 @@ angular.module('umbraco.services') }; return service; -}); \ No newline at end of file +}); diff --git a/src/Umbraco.Web.UI.Client/src/common/services/tinymce.service.js b/src/Umbraco.Web.UI.Client/src/common/services/tinymce.service.js index b0941bd5ad..61e3ae90ec 100644 --- a/src/Umbraco.Web.UI.Client/src/common/services/tinymce.service.js +++ b/src/Umbraco.Web.UI.Client/src/common/services/tinymce.service.js @@ -488,7 +488,7 @@ function tinyMceService($rootScope, $q, imageHelper, $locale, $http, $timeout, s * @methodOf umbraco.services.tinyMceService * * @description - * Creates the umbrco insert embedded media tinymce plugin + * Creates the umbraco insert embedded media tinymce plugin * * @param {Object} editor the TinyMCE editor instance */ @@ -575,7 +575,7 @@ function tinyMceService($rootScope, $q, imageHelper, $locale, $http, $timeout, s * @methodOf umbraco.services.tinyMceService * * @description - * Creates the umbrco insert media tinymce plugin + * Creates the umbraco insert media tinymce plugin * * @param {Object} editor the TinyMCE editor instance */ @@ -705,7 +705,7 @@ function tinyMceService($rootScope, $q, imageHelper, $locale, $http, $timeout, s * @methodOf umbraco.services.tinyMceService * * @description - * Creates the insert umbrco macro tinymce plugin + * Creates the insert umbraco macro tinymce plugin * * @param {Object} editor the TinyMCE editor instance */ diff --git a/src/Umbraco.Web.UI.Client/src/less/components/application/umb-drawer.less b/src/Umbraco.Web.UI.Client/src/less/components/application/umb-drawer.less index 064ad67438..5c77a15ec7 100644 --- a/src/Umbraco.Web.UI.Client/src/less/components/application/umb-drawer.less +++ b/src/Umbraco.Web.UI.Client/src/less/components/application/umb-drawer.less @@ -86,6 +86,7 @@ } .umb-help-badge__title { + display: block; font-size: 15px; font-weight: bold; color: @black; @@ -160,6 +161,9 @@ border-radius: 0; border-bottom: 1px solid @gray-9; padding: 10px; + background: transparent; + width:100%; + border: 0 none; } .umb-help-list-item:last-child { diff --git a/src/Umbraco.Web.UI.Client/src/less/components/application/umb-tour.less b/src/Umbraco.Web.UI.Client/src/less/components/application/umb-tour.less index 33a723a3f7..42403c65b1 100644 --- a/src/Umbraco.Web.UI.Client/src/less/components/application/umb-tour.less +++ b/src/Umbraco.Web.UI.Client/src/less/components/application/umb-tour.less @@ -112,3 +112,10 @@ .umb-tour-is-visible .umb-backdrop { z-index: @zindexTourBackdrop; } + +.umb-tour__popover .underline{ + font-size: 13px; + background: transparent; + border: none; + padding: 0; +} diff --git a/src/Umbraco.Web.UI.Client/src/less/components/tree/umb-tree.less b/src/Umbraco.Web.UI.Client/src/less/components/tree/umb-tree.less index 4793bbf4f8..d06c15cd30 100644 --- a/src/Umbraco.Web.UI.Client/src/less/components/tree/umb-tree.less +++ b/src/Umbraco.Web.UI.Client/src/less/components/tree/umb-tree.less @@ -293,9 +293,8 @@ body.touch .umb-tree { } .no-access { - .umb-tree-icon, - .root-link, - .umb-tree-item__label { + > .umb-tree-item__inner .umb-tree-icon, + > .umb-tree-item__inner .umb-tree-item__label { color: @gray-7; cursor: not-allowed; } diff --git a/src/Umbraco.Web.UI.Client/src/less/components/umb-grid-selector.less b/src/Umbraco.Web.UI.Client/src/less/components/umb-grid-selector.less index e25349f555..1ae476d584 100644 --- a/src/Umbraco.Web.UI.Client/src/less/components/umb-grid-selector.less +++ b/src/Umbraco.Web.UI.Client/src/less/components/umb-grid-selector.less @@ -41,12 +41,17 @@ margin-top: 10px; } +button.umb-grid-selector__item { + width: 169px; + height: 194px; +} + .umb-grid-selector__item-icon { - font-size: 50px; - color: @gray-8; - display: block; - line-height: 50px; - margin-bottom: 15px; + font-size: 50px; + color: @gray-8; + display: block; + line-height: 50px; + margin-bottom: 15px; } .umb-grid-selector__item-label { 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 699496f5d3..4168ab3c39 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 @@ -41,11 +41,8 @@ } .umb-nested-content__item.ui-sortable-placeholder { - background: @gray-10; - border: 1px solid @gray-9; + margin-top: 1px; visibility: visible !important; - height: 55px; - margin-top: -1px; } .umb-nested-content__item--single > .umb-nested-content__content { diff --git a/src/Umbraco.Web.UI.Client/src/less/components/umb-progress-circle.less b/src/Umbraco.Web.UI.Client/src/less/components/umb-progress-circle.less index 03816637a7..d8fb3b4d8f 100644 --- a/src/Umbraco.Web.UI.Client/src/less/components/umb-progress-circle.less +++ b/src/Umbraco.Web.UI.Client/src/less/components/umb-progress-circle.less @@ -5,6 +5,7 @@ .umb-progress-circle__view-box { position: absolute; transform: rotate(-90deg); + right: 0; } // circle highlight on progressbar diff --git a/src/Umbraco.Web.UI.Client/src/less/components/users/umb-user-group-picker-list.less b/src/Umbraco.Web.UI.Client/src/less/components/users/umb-user-group-picker-list.less index dff78ce627..0a06120b11 100644 --- a/src/Umbraco.Web.UI.Client/src/less/components/users/umb-user-group-picker-list.less +++ b/src/Umbraco.Web.UI.Client/src/less/components/users/umb-user-group-picker-list.less @@ -7,11 +7,17 @@ display: flex; margin-bottom: 5px; padding: 10px; + position: relative; } -.umb-user-group-picker-list-item:active, -.umb-user-group-picker-list-item:focus { - text-decoration: none; +.umb-user-group-picker__action{ + background: transparent; + border: 0 none; + position: absolute; + top: 0; + left: 0; + width: 100%; + height: 100%; } .umb-user-group-picker-list-item:hover { @@ -35,4 +41,4 @@ .umb-user-group-picker-list-item__permission { font-size: 13px; color: @gray-4; -} \ No newline at end of file +} diff --git a/src/Umbraco.Web.UI.Client/src/less/listview.less b/src/Umbraco.Web.UI.Client/src/less/listview.less index b724688a32..fe8af6dbc4 100644 --- a/src/Umbraco.Web.UI.Client/src/less/listview.less +++ b/src/Umbraco.Web.UI.Client/src/less/listview.less @@ -47,6 +47,15 @@ /* add padding */ .left-addon input[type="text"] { padding-left: 30px !important; padding-right: 6px; } .right-addon input[type="text"] { padding-right: 30px; padding-left: 6px !important; } + + &__label-icon{ + width: 30px; + height: 30px; + position: absolute; + top: -1px; + left:0; + margin:0 + } } .umb-listview table form { @@ -140,7 +149,36 @@ /* TEMP */ .umb-minilistview { - .umb-table-row.not-allowed { opacity: 0.6; cursor: not-allowed; } + .umb-table-row.not-allowed { + opacity: 0.6; + cursor: not-allowed; + } + + div.umb-mini-list-view__breadcrumb { + margin-bottom: 10px; + } + + div.no-display { + display: none + } + + div.umb-table-cell-padding { + padding-top: 8px; + padding-bottom: 8px; + } + + div.umb-table-cell .form-search { + width: 100%; + margin-right: 0; + + input { + width: 100%; + } + + .icon-search { + font-size: 14px; + } + } } .umb-listview .table-striped tbody td { diff --git a/src/Umbraco.Web.UI.Client/src/less/main.less b/src/Umbraco.Web.UI.Client/src/less/main.less index 0d646d11c6..b34f313435 100644 --- a/src/Umbraco.Web.UI.Client/src/less/main.less +++ b/src/Umbraco.Web.UI.Client/src/less/main.less @@ -117,6 +117,12 @@ h5.-black { } .umb-control-group { position: relative; + + &.umb-control-group__listview { + // position: relative messes up the listview status messages (e.g. "no search results") + position: unset; + } + &::after { content: ''; display:block; diff --git a/src/Umbraco.Web.UI.Client/src/less/panel.less b/src/Umbraco.Web.UI.Client/src/less/panel.less index bad0ab9715..40c70f5331 100644 --- a/src/Umbraco.Web.UI.Client/src/less/panel.less +++ b/src/Umbraco.Web.UI.Client/src/less/panel.less @@ -341,6 +341,7 @@ .umb-panel-header-icon { cursor: pointer; margin-right: 5px; + margin-top: -6px; height: 50px; display: flex; justify-content: center; diff --git a/src/Umbraco.Web.UI.Client/src/less/variables.less b/src/Umbraco.Web.UI.Client/src/less/variables.less index 264b4df23d..a906bc0eed 100644 --- a/src/Umbraco.Web.UI.Client/src/less/variables.less +++ b/src/Umbraco.Web.UI.Client/src/less/variables.less @@ -454,7 +454,7 @@ @successBorder: transparent; @infoText: @white; -@infoBackground: @turquoise-d1; +@infoBackground: @blueDark; @infoBorder: transparent; @alertBorderRadius: 0; diff --git a/src/Umbraco.Web.UI.Client/src/views/common/drawers/help/help.html b/src/Umbraco.Web.UI.Client/src/views/common/drawers/help/help.html index 4ae3121098..96f4a404bc 100644 --- a/src/Umbraco.Web.UI.Client/src/views/common/drawers/help/help.html +++ b/src/Umbraco.Web.UI.Client/src/views/common/drawers/help/help.html @@ -17,17 +17,21 @@
- -
- +
+ -
+
@@ -85,9 +89,9 @@ @@ -96,7 +100,7 @@ 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 d72e977010..c35686acd1 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 @@ -169,7 +169,7 @@ ng-change="updateTemplate(node.template)"> -
diff --git a/src/Umbraco.Web.UI.Client/src/views/components/editor/umb-editor-header.html b/src/Umbraco.Web.UI.Client/src/views/components/editor/umb-editor-header.html index c46efb7b74..e1bc01a7a1 100644 --- a/src/Umbraco.Web.UI.Client/src/views/components/editor/umb-editor-header.html +++ b/src/Umbraco.Web.UI.Client/src/views/components/editor/umb-editor-header.html @@ -12,13 +12,17 @@
-
- -
- -
-
+
diff --git a/src/Umbraco.Web.UI.Client/src/views/components/property/umb-property.html b/src/Umbraco.Web.UI.Client/src/views/components/property/umb-property.html index c2f9ceebc4..ca57679f51 100644 --- a/src/Umbraco.Web.UI.Client/src/views/components/property/umb-property.html +++ b/src/Umbraco.Web.UI.Client/src/views/components/property/umb-property.html @@ -1,6 +1,6 @@
-
+
diff --git a/src/Umbraco.Web.UI.Client/src/views/components/umb-grid-selector.html b/src/Umbraco.Web.UI.Client/src/views/components/umb-grid-selector.html index c2ce93b8be..ae3bbbf699 100644 --- a/src/Umbraco.Web.UI.Client/src/views/components/umb-grid-selector.html +++ b/src/Umbraco.Web.UI.Client/src/views/components/umb-grid-selector.html @@ -4,30 +4,34 @@
- +
{{ defaultItem.name }}
- +
(Default {{itemLabel}}) -
- +
+ + Remove Template +
- +
{{ selectedItem.name }}
- - +
+
- + + Remove Template +
- +
diff --git a/src/Umbraco.Web.UI.Client/src/views/components/umb-mini-list-view.html b/src/Umbraco.Web.UI.Client/src/views/components/umb-mini-list-view.html index c596734e36..da1e5c3aa7 100644 --- a/src/Umbraco.Web.UI.Client/src/views/components/umb-mini-list-view.html +++ b/src/Umbraco.Web.UI.Client/src/views/components/umb-mini-list-view.html @@ -5,14 +5,14 @@ ng-repeat="miniListView in miniListViews">
- +

{{ miniListView.node.name }}

- + Back / @@ -30,13 +30,12 @@
- -
-
-
- Remove file + + +
diff --git a/src/Umbraco.Web.UI.Client/src/views/components/users/umb-user-group-preview.html b/src/Umbraco.Web.UI.Client/src/views/components/users/umb-user-group-preview.html index 33c861c3d0..20718cf804 100644 --- a/src/Umbraco.Web.UI.Client/src/views/components/users/umb-user-group-preview.html +++ b/src/Umbraco.Web.UI.Client/src/views/components/users/umb-user-group-preview.html @@ -39,8 +39,8 @@
- Edit - Remove + +
diff --git a/src/Umbraco.Web.UI.Client/src/views/content/assigndomain.html b/src/Umbraco.Web.UI.Client/src/views/content/assigndomain.html index 42876cc27a..6238d11a69 100644 --- a/src/Umbraco.Web.UI.Client/src/views/content/assigndomain.html +++ b/src/Umbraco.Web.UI.Client/src/views/content/assigndomain.html @@ -2,7 +2,7 @@ - +
@@ -24,11 +24,11 @@
Domains
- +
- +
diff --git a/src/Umbraco.Web.UI.Client/src/views/prevalueeditors/multivalues.html b/src/Umbraco.Web.UI.Client/src/views/prevalueeditors/multivalues.html index bb5e5fe782..f569105083 100644 --- a/src/Umbraco.Web.UI.Client/src/views/prevalueeditors/multivalues.html +++ b/src/Umbraco.Web.UI.Client/src/views/prevalueeditors/multivalues.html @@ -9,12 +9,12 @@
- +
- Remove +
diff --git a/src/Umbraco.Web.UI.Client/src/views/prevalueeditors/treesource.controller.js b/src/Umbraco.Web.UI.Client/src/views/prevalueeditors/treesource.controller.js index 828763bc1c..f9c8ae8b0e 100644 --- a/src/Umbraco.Web.UI.Client/src/views/prevalueeditors/treesource.controller.js +++ b/src/Umbraco.Web.UI.Client/src/views/prevalueeditors/treesource.controller.js @@ -19,15 +19,16 @@ angular.module('umbraco') }; } - if($scope.model.value.id && $scope.model.value.type !== "member"){ - entityResource.getById($scope.model.value.id, entityType()).then(function(item){ + if($scope.model.value.id && $scope.model.value.type !== "member"){ + entityResource.getById($scope.model.value.id, entityType()).then(function(item){ populate(item); - }); + }); + } + else { + $timeout(function () { + treeSourceChanged(); + }, 100); } - - $timeout(function () { - treeSourceChanged(); - }, 100); function entityType() { var ent = "Document"; diff --git a/src/Umbraco.Web.UI.Client/src/views/prevalueeditors/treesourcetypepicker.controller.js b/src/Umbraco.Web.UI.Client/src/views/prevalueeditors/treesourcetypepicker.controller.js index ef781c6014..a87377c84b 100644 --- a/src/Umbraco.Web.UI.Client/src/views/prevalueeditors/treesourcetypepicker.controller.js +++ b/src/Umbraco.Web.UI.Client/src/views/prevalueeditors/treesourcetypepicker.controller.js @@ -7,7 +7,6 @@ function TreeSourceTypePickerController($scope, contentTypeResource, mediaTypeRe var allItemTypes = null; var currentItemType = null; - var initialLoad = true; function init() { vm.loading = true; @@ -86,13 +85,12 @@ function TreeSourceTypePickerController($scope, contentTypeResource, mediaTypeRe } eventsService.on("treeSourceChanged", function (e, args) { - currentItemType = args.value; // reset the model value if we changed node type (but not on the initial load) - if (!initialLoad) { + if (!!currentItemType && currentItemType !== args.value) { vm.itemTypes = []; updateModel(); } - initialLoad = false; + currentItemType = args.value; init(); }); } diff --git a/src/Umbraco.Web.UI.Client/src/views/propertyeditors/grid/dialogs/rowdeleteconfirm.html b/src/Umbraco.Web.UI.Client/src/views/propertyeditors/grid/dialogs/rowdeleteconfirm.html index 2bf1f00b0e..02b92f44f7 100644 --- a/src/Umbraco.Web.UI.Client/src/views/propertyeditors/grid/dialogs/rowdeleteconfirm.html +++ b/src/Umbraco.Web.UI.Client/src/views/propertyeditors/grid/dialogs/rowdeleteconfirm.html @@ -1,53 +1,45 @@
+ + + + +

Warning!

- +

+ You are deleting the row configuration {{model.dialogData.rowName}} +

- - - +

+ + Modifying a row configuration name will result in loss of + data for any existing content that is based on this configuration. + +

+

+ Are you sure? +

+
+
+
-

Warning!

- -

- You are deleting the row configuration '{{model.dialogData.rowName}}' -

- -

- Modifying a row configuration name will result in loss of - data for any existing content that is based on this configuration. -

- -

- Are you sure? -

- - - - -
-
-
- - - - + + - - + - - - + + +
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 a0faefe690..3164a6964c 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 @@ -41,7 +41,8 @@ on-value-changed="focalPointChanged(left, top)" on-image-loaded="imageLoaded(isCroppable, hasDimensions)"> - Remove file + +
diff --git a/src/Umbraco.Web.UI.Client/src/views/propertyeditors/multiurlpicker/multiurlpicker.controller.js b/src/Umbraco.Web.UI.Client/src/views/propertyeditors/multiurlpicker/multiurlpicker.controller.js index 8381a53644..6b7d9dd7ae 100644 --- a/src/Umbraco.Web.UI.Client/src/views/propertyeditors/multiurlpicker/multiurlpicker.controller.js +++ b/src/Umbraco.Web.UI.Client/src/views/propertyeditors/multiurlpicker/multiurlpicker.controller.js @@ -19,7 +19,10 @@ function multiUrlPickerController($scope, angularHelper, localizationService, en var currentForm = angularHelper.getCurrentForm($scope); $scope.sortableOptions = { + axis: "y", + containment: "parent", distance: 10, + opacity: 0.7, tolerance: "pointer", scroll: true, zIndex: 6000, 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 0a99b68a06..84069acfcf 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 @@ -134,7 +134,7 @@ }; vm.openNodeTypePicker = function ($event) { - if (vm.nodes.length >= vm.maxItems) { + if (vm.overlayMenu || vm.nodes.length >= vm.maxItems) { return; } diff --git a/src/Umbraco.Web.UI.Client/src/views/propertyeditors/nestedcontent/nestedcontent.doctypepicker.controller.js b/src/Umbraco.Web.UI.Client/src/views/propertyeditors/nestedcontent/nestedcontent.doctypepicker.controller.js index 6e807ffaa4..d4380d6c64 100644 --- a/src/Umbraco.Web.UI.Client/src/views/propertyeditors/nestedcontent/nestedcontent.doctypepicker.controller.js +++ b/src/Umbraco.Web.UI.Client/src/views/propertyeditors/nestedcontent/nestedcontent.doctypepicker.controller.js @@ -134,6 +134,9 @@ event: $event, submit: function (model) { config.ncAlias = model.selectedItem.alias; + if (model.selectedItem.tabs.length === 1) { + config.ncTabAlias = model.selectedItem.tabs[0]; + } overlayService.close(); }, close: function () { diff --git a/src/Umbraco.Web.UI.Client/src/views/propertyeditors/nestedcontent/nestedcontent.propertyeditor.html b/src/Umbraco.Web.UI.Client/src/views/propertyeditors/nestedcontent/nestedcontent.propertyeditor.html index d24d3796f3..b3821cff3d 100644 --- a/src/Umbraco.Web.UI.Client/src/views/propertyeditors/nestedcontent/nestedcontent.propertyeditor.html +++ b/src/Umbraco.Web.UI.Client/src/views/propertyeditors/nestedcontent/nestedcontent.propertyeditor.html @@ -1,6 +1,6 @@ 
- + @@ -40,8 +40,8 @@
- 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 b35a29d2de..a1dcafd421 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 @@ -196,23 +196,22 @@ diff --git a/src/Umbraco.Web.UI.Client/test/unit/common/services/notifications.spec.js b/src/Umbraco.Web.UI.Client/test/unit/common/services/notifications.spec.js index 28f6f80802..071c2158b8 100644 --- a/src/Umbraco.Web.UI.Client/test/unit/common/services/notifications.spec.js +++ b/src/Umbraco.Web.UI.Client/test/unit/common/services/notifications.spec.js @@ -14,21 +14,23 @@ describe('notification tests', function () { var not1 = notifications.success("success", "something great happened"); var not2 = notifications.error("error", "something great happened"); var not3 = notifications.warning("warning", "something great happened"); - var not4 = notifications.warning("warning", ""); + var not4 = notifications.warning("warning", ""); + var not5 = notifications.info("info", "something informative happened"); - expect(notifications.getCurrent().length).toBe(4); + expect(notifications.getCurrent().length).toBe(5); //remove at index 0 notifications.remove(0); - expect(notifications.getCurrent().length).toEqual(3); + expect(notifications.getCurrent().length).toEqual(4); expect(notifications.getCurrent()[0].headline).toBe("error: "); expect(notifications.getCurrent()[1].headline).toBe("warning: "); - expect(notifications.getCurrent()[2].headline).toBe("warning"); + expect(notifications.getCurrent()[2].headline).toBe("warning"); + expect(notifications.getCurrent()[3].headline).toBe("info: "); notifications.removeAll(); expect(notifications.getCurrent().length).toEqual(0); }); }); -}); \ No newline at end of file +}); diff --git a/src/Umbraco.Web.UI.Docs/umb-docs.css b/src/Umbraco.Web.UI.Docs/umb-docs.css index eef0fcee39..931c22b255 100644 --- a/src/Umbraco.Web.UI.Docs/umb-docs.css +++ b/src/Umbraco.Web.UI.Docs/umb-docs.css @@ -76,3 +76,12 @@ a:hover { width: 50px; margin-top: 5px; } + +.content .methods code { + border: 1px solid #e1e1e8; + background-color: #f7f7f9; + padding: 0px 3px; + font-size: 85%; + color: #d14; + white-space: nowrap; +} diff --git a/src/Umbraco.Web.UI/Umbraco.Web.UI.csproj b/src/Umbraco.Web.UI/Umbraco.Web.UI.csproj index deaf7fb1ab..a2dfa0ffd2 100644 --- a/src/Umbraco.Web.UI/Umbraco.Web.UI.csproj +++ b/src/Umbraco.Web.UI/Umbraco.Web.UI.csproj @@ -88,7 +88,7 @@ - + @@ -347,10 +347,7 @@ True 8600 / - http://localhost:8600/ - 8500 - / - http://localhost:8500 + http://localhost:8600 False False @@ -432,4 +429,4 @@ - \ No newline at end of file + diff --git a/src/Umbraco.Web.UI/Umbraco/config/lang/da.xml b/src/Umbraco.Web.UI/Umbraco/config/lang/da.xml index fbfaccc768..5b4d1c9afa 100644 --- a/src/Umbraco.Web.UI/Umbraco/config/lang/da.xml +++ b/src/Umbraco.Web.UI/Umbraco/config/lang/da.xml @@ -1180,6 +1180,8 @@ Mange hilsner fra Umbraco robotten Bruger gemt Brugertype gemt Brugergruppe gemt + Sprog og domæner gemt + Der opstod en fejl ved at gemme sprog og domæner Fil ikke gemt Filen kunne ikke gemmes. Tjek filrettighederne Fil gemt diff --git a/src/Umbraco.Web.UI/Umbraco/config/lang/de.xml b/src/Umbraco.Web.UI/Umbraco/config/lang/de.xml index 74f987a4cb..e45d97e7bd 100644 --- a/src/Umbraco.Web.UI/Umbraco/config/lang/de.xml +++ b/src/Umbraco.Web.UI/Umbraco/config/lang/de.xml @@ -100,11 +100,10 @@ Die Domain '%0%' ist bereits zugeordnet Domain '%0%' aktualisiert Domains bearbeiten - - - + + + Vererben Kultur Definiert die Kultureinstellung für untergeordnete Elemente dieses Elements oder vererbt vom übergeordneten Element. Wird auch auf das aktuelle Element angewendet, sofern auf tieferer Ebene keine Domain zugeordnet ist. @@ -156,7 +155,8 @@ Bestätigen - Anzeigen als + Anzeigen als + Inhalt gelöscht Inhalt unveröffentlicht Inhalt unveröffentlicht für Sprache: %0% @@ -293,6 +293,7 @@ Wollen Sie dieses Element wirklich entfernen? Eigenschaft %0% verwendet Editor %1%, welcher nicht von Nested Content unterstützt wird. + Es wurden keine Dokument-(Inhalts-)Typen für diese Eigenschaft definiert. Füge ein weiteres Textfeld hinzu Entferne dieses Textfeld Inhalt-Basis @@ -309,10 +310,13 @@ Veröffentlichte Sprachen Unveröffentlichte Sprachen Unveränderte Sprachen + Diese Sprachen wurden nicht angelegt Bereit zu Veröffentlichen? Bereit zu Sichern? Freigabe anfordern Wählen Sie Datum und Uhrzeit für die Veröffentlichung bzw. deren Rücknahme. + Neues Element anlegen + Aus der Zwischenablage einfügen Erzeuge eine neue Inhaltsvorlage von '%0%' @@ -348,7 +352,11 @@ Geben Sie einen Verzeichnisnamen ein Wählen Sie einen Namen und einen Typ + Die im Inhaltsbaum ausgewählte Seite erlaubt keine Unterseiten. + Bearbeitungsrechte für diesen Dokumenttyp + Das im Strukturbaum ausgewählte Medienelement erlaubt keine untergeordneten Elemente. + Bearbeitungsrechte für diesen Medientyp Dokumenttyp ohne Vorlage Neues Verzeichnis Neuer Datentyp @@ -408,7 +416,6 @@ Link Anker / querystring Name - Hostnamen verwalten Fenster schließen Wollen Sie dies wirklich entfernen Wollen Sie folgendes wirklich deaktivieren @@ -425,11 +432,14 @@ klicken um Macro hinzuzufügen Tabelle einfügen Dies entfernt die Sprache + + Die Kultur-Variante einer Sprache zu ändern ist möglicherweise eine aufwendige Operation und führt zum Erneuern von Inhalts-Zwischenspeicher und Such-Index. Zuletzt bearbeitet Verknüpfung Anker: Wenn lokale Links verwendet werden, füge ein "#" vor den Link ein In einem neuen Fenster öffnen? + Macro Einstellungen Dieses Makro enthält keine einstellbaren Eigenschaften. Einfügen Berechtigungen bearbeiten für @@ -464,6 +474,7 @@ Link wählen Makro wählen Inhalt wählen + Inhaltstyp wählen Medien-Startknoten wählen Mitglied wählen Mitgliedergruppe wählen @@ -637,7 +648,8 @@ Fenster schließen Kommentar bestätigen - Beschneiden + Beschneiden + Seitenverhältnis beibehalten Inhalt Weiter @@ -702,7 +714,8 @@ Ok Öffnen Optionen - An + An + oder Sortieren nach Kennwort @@ -756,7 +769,8 @@ Sortierung abschließen Vorschau Kennwort ändern - nach + nach + Listenansicht Sichern läuft... Aktuelle(s) @@ -844,8 +858,8 @@ Schauen Sie sich die <strong>Video-Lehrgänge</strong> zum Thema Verzeichnisberechtigungen für Umbraco an oder lesen Sie den technischen Artikel. <strong>Die Dateiberechtigungen sind möglicherweise fehlerhaft!</strong>Sie können Umbraco vermutlich ohne Probleme verwenden, werden aber viele Erweiterungspakete können nicht installiert werden. - <strong>Die Dateiberechtigungen sind nicht geeignet!</strong><br /><br /> - Die Dateiberechtigungen müssen angepasst werden. + <strong>Die Dateiberechtigungen sind nicht geeignet!</strong><br /><br /> + Die Dateiberechtigungen müssen angepasst werden. <strong>Die Dateiberechtigungen sind perfekt eingestellt!</strong><br /><br /> Damit ist Umbraco komplett eingerichtet und es können problemlos Erweiterungspakete installiert werden. Verzeichnisprobleme lösen @@ -1301,7 +1315,8 @@ %0% wurde veröffentlicht %0% und die untergeordneten Elemente wurden veröffentlicht %0% und alle untergeordneten Elemente veröffentlichen - + Sichern und Veröffentlichen, um %0% zu veröffentlicht und auf der Website sichtbar zu machen.

Sie können dieses Element mitsamt seinen untergeordneten Elementen veröffentlichen, indem Sie Unveröffentlichte Unterelemente einschließen markieren. ]]> @@ -1309,13 +1324,14 @@ Sie haben keine freigegeben Farben konfiguriert - + Sie können nur Elemente folgender Typen wählen: %0% Sie haben ein entferntes oder im Papierkorb befindliches Inhaltselement ausgewählt Sie haben entfernte oder im Papierkorb befindliche Inhaltselemente ausgewählt + Element entfernen Sie haben ein entferntes oder im Papierkorb befindliches Medienelement ausgewählt Sie haben entfernte oder im Papierkorb befindliche medienelemente ausgewählt Verworfen @@ -1481,8 +1497,9 @@ Stil bearbeiten Rich text editor Stile - Definiere die Stile, die im 'Rich-Text-Editor' verfügbar sein sollen. - + Definiere die Stile, die im 'Rich-Text-Editor' verfügbar sein sollen. +
+ Definiere die Styles, die im Rich-Text-Editor dieses Stylesheets verfügbar sein sollen. Stylesheet bearbeiten Stylesheet-Regel bearbeiten Bezeichnung im Auswahlmenü des Rich-Text-Editors @@ -1504,21 +1521,22 @@ Einfügen Wählen Sie, was in die Vorlage eingefügt werden soll Wörterbucheintrag einfügen - Ein Wörterbuchelement ist ein Platzhalter für lokalisierbaren Text. - Das macht es einfach mehrsprachige Websites zu gestalten. + Ein Wörterbuchelement ist ein Platzhalter für lokalisierbaren Text. Das macht es einfach mehrsprachige Websites zu gestalten. Makro - Ein Makro ist eine konfigurierbare Komponente, die großartig für wiederverwendbare Teile Ihres Entwurfes sind, - für welche Sie optionale Parameter benötigen, wie z. B. Galerien, Formulare oder Listen. + Ein Makro ist eine konfigurierbare Komponente, die großartig + für wiederverwendbare Teile Ihres Entwurfes sind, + für welche Sie optionale Parameter benötigen, wie z. B. Galerien, Formulare oder Listen. Umbraco-Feld - Zeigt den Wert eines benannten Feldes der aktuellen Seite an, mit der Möglichkeit den Wert zu verändern - oder einen alternativen Ersatzwert zu wählen. + Zeigt den Wert eines benannten Feldes der aktuellen Seite an, mit der Möglichkeit den Wert zu verändern + oder einen alternativen Ersatzwert zu wählen. + Teilansicht (Partial View) - Eine Teilansicht ist eine eigenständige Vorlagen-Datei, die innerhalb einer anderen Vorlage verwendet werden kann. - Sie ist gut geeignet, um "Markup"-Kode wiederzuverwenden oder komplexe Vorlagen in mehrere Dateien aufzuteilen. + Eine Teilansicht ist eine eigenständige Vorlagen-Datei, die innerhalb einer anderen Vorlage verwendet werden kann. + Sie ist gut geeignet, um "Markup"-Kode wiederzuverwenden oder komplexe Vorlagen in mehrere Dateien aufzuteilen. Basisvorlage Keine Basis @@ -1547,8 +1565,8 @@ Bereichsname Bereich ist notwendig - Wenn notwendig, dann muss die untergeordnete Vorlage eine @section Definition gleichen Namens enthalten, - anderfalls tritt ein Fehler auf. + Wenn notwendig, dann muss die untergeordnete Vorlage eine @section Definition gleichen Namens enthalten, + anderfalls tritt ein Fehler auf. Abfrage-Generator zurückgegebene Elemente, in @@ -1589,7 +1607,7 @@ Neues Element Layout auswählen Neue Zeile - Inhalt hinzufügen + Neuer Inhalt Inhalt entfernen Einstellungen anwenden nicht zugelassen]]> @@ -1623,6 +1641,7 @@ Mischungen + Gruppe Sie haben keine Gruppen hinzugefügt Gruppe hinzufügen Übernimm von @@ -1630,18 +1649,23 @@ Notwendige Bezeichnung Listenansicht aktivieren - Konfiguriert die Verwendung einer sortier- und filterbaren Listenansicht der Unterknoten für diesen Dokumenttyp. - Die Unterknoten werden nicht in Baumstruktur angezeigt. + Konfiguriert die Verwendung einer sortier- und filterbaren Listenansicht der Unterknoten für diesen Dokumenttyp. + Die Unterknoten werden nicht in Baumstruktur angezeigt. + Erlaubte Vorlagen - Wählen Sie die Vorlagen, die Editoren für diesen Dokumenttyp wählen dürfen + Wählen Sie die Vorlagen, die Editoren für diesen Dokumenttyp wählen dürfen + Als Wurzelknoten zulassen - Ermöglicht es Editoren diesen Dokumenttyp in der obersten Ebene der Inhalt-Baum-Strukur zu wählen + Ermöglicht es Editoren diesen Dokumenttyp in der obersten Ebene der Inhalt-Baum-Strukur zu wählen + Erlaubte Dokumenttypen für Unterknoten - Erlaubt es Inhalt der angegebenen Typen unterhalb Inhalten dieses Typs anzulegen - Wählen Sie einen Unterknoten + Erlaubt es Inhalt der angegebenen Typen unterhalb Inhalten dieses Typs anzulegen + + Wählen Sie einen Unterknoten + Übernimm Tabs und Eigenschaften vone einem vorhandenen Dokumenttyp. Neue Tabs werden zum vorliegenden Dokumenttyp hinzugefügt oder mit einem gleichnamigen Tab zusammengeführt. Dieser Dokumenttyp wird in einer Mischung verwendet und kann deshalb nicht selbst zusammengemischt werden. Es sind keine Dokumenttypen für eine Mischung vorhanden. @@ -1666,23 +1690,28 @@ und alle Mitglieder, die auf diesem Typ basieren Mitglied kann bearbeiten - Diese Eigenschaft zur Bearbeitung des Mitglieds auf seiner Profileseite freigeben + Diese Eigenschaft zur Bearbeitung des Mitglieds auf seiner Profileseite freigeben + sensibelle Daten - Diese Eigenschaft für Editoren, die keine Berechtigung für sensibelle Daten haben, verbergen + Diese Eigenschaft für Editoren, die keine Berechtigung für sensibelle Daten haben, verbergen + Auf Mitgliedsprofil anzeigen Diesen Eigenschaftswert für die Anzeige auf der Profilseite des Mitglieds zulassen Tab hat keine Sortierung Wo wird diese Mischung verwendet? - Diese Mischung wird aktuell in den Mischungen folgender Dokumenttypen verwendet: + Diese Mischung wird aktuell in den Mischungen folgender Dokumenttypen verwendet: + Kultur basierte Variationen zulassen Editoren erlauben, Inhalt dieses Typs in verschiedenen Sprachen anzulegen Kultur basierte Variationen zulassen Ist ein Elementtyp - + Nested Content vorgesehen, nicht jedoch als Inhalt-Knoten in der Baumstruktur - ]]> + ]]> + Dies kann nicht für Elementtypen verwendet werden @@ -1695,8 +1724,9 @@ Wird ersetzt durch Kein Ersatzsprache - Um mehrsprachigem Inhalt zu ermöglichen durch eine andere Sprache ersetzt zu werden, - falls die angefragte Sprache nicht verfügbar ist, wählen Sie diese Option hier aus. + Um mehrsprachigem Inhalt zu ermöglichen durch eine andere Sprache ersetzt zu werden, + falls die angefragte Sprache nicht verfügbar ist, wählen Sie diese Option hier aus. + Ersatzsprache @@ -1758,7 +1788,7 @@ Felder Einschließlich der Unterseiten - Schnittstelle für externe Editoren Weiteren Benutzer anlegen - Lege neue Benutzer an, um ihnen Zugang zum Umbraco-Back-Office zu geben. - Während des Anlegens eines neuen Benutzer wird ein Kennwort erzeugt, das Sie dem Benutzer mitteilen können. + Lege neue Benutzer an, um ihnen Zugang zum Umbraco-Back-Office zu geben. + Während des Anlegens eines neuen Benutzer wird ein Kennwort erzeugt, das Sie dem Benutzer mitteilen können. Feld für Beschreibung Benutzer endgültig deaktivieren @@ -1854,12 +1884,14 @@ Editor Feld für Textausschnitt Fehlgeschlagene Anmeldeversuche - Bneutzerprofil aufrufen + Benutzerprofil aufrufen Gruppen hinzufügen, um Zugang und Berechtigungen zuzuweisen Weitere Benutzer einladen - Laden Sie neue Benutzer ein, um ihnen Zugang zum Umbraco-Back-Office zu geben. - Eine Einladungs-E-Mail wird an dem Benutzer geschickt. Diese enthält Informationen, wie sich der Benutzer im Umbraco-Back-Office anmelden kann. - Einladungen sind 72 Stunden lang gültig. + + Laden Sie neue Benutzer ein, um ihnen Zugang zum Umbraco-Back-Office zu geben. + Eine Einladungs-E-Mail wird an dem Benutzer geschickt. Diese enthält Informationen, wie sich der Benutzer im Umbraco-Back-Office anmelden kann. + Einladungen sind 72 Stunden lang gültig. + Sprache Bestimmen Sie die Sprache für Menüs und Dialoge Letztes Abmeldedatum @@ -1914,15 +1946,16 @@ Willkommen bei Umbraco! Bedauerlicherweise ist Ihre Einladung verfallen. Bitte kontaktieren Sie Ihren Administrator und bitten Sie ihn, diese erneut zu schicken. Laden Sie ein Foto von sich hoch, um es anderen Benutzern zu erleichtern, sie zu erkennen. Klicken Sie auf den Kreis oben, um Ihr Foto hochzuladen. Autor - Änderung + Änderung + Ihr Profil Ihr Verlauf Sitzung läuft ab in - Invite user - Create user - Send invite - Back to users - Umbraco: Invitation + Benutzer einladen + Benutzer anlegen + Einladung schicken + Zurück zu den Benutzern + Umbraco: Einladung @@ -2064,8 +2097,10 @@ "customErrors" aktuell auf '%0%' gesetzt. Es wird empfohlen, diese vor dem Live-Gang auf '%1%' zu setzen. "customErrors" erfolgreich auf '%0%' gesetzt. "MacroErrors" auf '%0%' gesetzt. - "MacroErrors" sind auf '%0%' gesetzt, - was verhindert, dass einige oder alle Seiten Ihrer Website vollständig geladen werden, falls Fehler in Makros auftreten. Schaltfläche "Beheben" setzt den Wert auf '%1%'. + + "MacroErrors" sind auf '%0%' gesetzt, + was verhindert, dass einige oder alle Seiten Ihrer Website vollständig geladen werden, falls Fehler in Makros auftreten. Schaltfläche "Beheben" setzt den Wert auf '%1%'. + "MacroErrors" sind jetzt auf '%0%' gesetzt. "trySkipIisCustomErrors" ist auf '%0%' gestellt und Sie verwenden IIS-Version '%1%'. "trySkipIisCustomErrors" ist aktuell auf '%0%' gestellt. Für Ihre IIS-Version (%2%) wird empfohlen, diese auf '%1%' zu stellen. @@ -2116,7 +2151,9 @@ Der 'web.config'-Datei wurde eine Einstellung zum Schutz gegen MIME-'Schnüffeln'-Schwachstellen hinzugefügt. Strict-Transport-Security, auch bekannt als HSTS-Header, ist vorhanden.]]> Strict-Transport-Security, auch bekannt als HSTS-Header, ist nicht vorhanden.]]> - Fügt den Header 'Strict-Transport-Security' mit dem Wert 'max-age=10886400; preload' im Abschnitt 'httpProtocol/customHeaders' der 'web.config'-Datei hinzu. Benutzen Sie dies nur, wenn Sie Ihre Domainen für mindestens 18 Wochen unter HTTPS laufen lassen. + + Fügt den Header 'Strict-Transport-Security' mit dem Wert 'max-age=10886400; preload' im Abschnitt 'httpProtocol/customHeaders' der 'web.config'-Datei hinzu. Benutzen Sie dies nur, wenn Sie Ihre Domainen für mindestens 18 Wochen unter HTTPS laufen lassen. + Die HSTS-Header-Einstellung wurde der 'web.config'-Datei hinzugefügt. X-XSS-Protection ist vorhanden.]]> X-XSS-Protection ist nicht vorhanden]]> @@ -2130,11 +2167,13 @@ Der konfigurierte SMTP-Server mit Host '%0%' und Port '%1%' konnte nicht erreicht werden. Bitte überprüfen Sie die SMTP-Einstellungen in der 'web.config'-Datei im Abschnitt 'system.net/mailsettings'. %0% eingestellt.]]> %0% gestellt.]]> - +

Die Ergebnisse der geplanten Systemzustandsprüfung läuft am %0% um %1% lauten wie folgt:

%2% - ]]>
+ ]]> +
Status der Umbraco Systemzustand: %0% @@ -2182,7 +2221,8 @@ Bidirektional Oberknoten Unterknoten - Anzahl + Anzahl + Relationen Angelegt Kommentar @@ -2203,4 +2243,19 @@ Lassen Sie uns beginnen Umbraco Forms installieren + + zurück gehen + Aktives Layout: + Springe zu + Gruppe + bestanden + alarmierend + fehlgeschlagen + Vorschlag + Prüfung bestanden + Prüfung fehlgeschlagen + Back-Office Suche öffnen + Back-Office Hilfe öffnen / schliessen + Ihre Profil-Einstellungen öffnen / schliessen + diff --git a/src/Umbraco.Web.UI/Umbraco/config/lang/en.xml b/src/Umbraco.Web.UI/Umbraco/config/lang/en.xml index 878427bdde..f61cc767a0 100644 --- a/src/Umbraco.Web.UI/Umbraco/config/lang/en.xml +++ b/src/Umbraco.Web.UI/Umbraco/config/lang/en.xml @@ -266,6 +266,8 @@ Last edited Date/time this document was edited Remove file(s) + Click here to remove the image from the media item + Click here to remove the file from the media item Link to document Member of group(s) Not a member of group(s) @@ -484,7 +486,6 @@ Un-link your account Select editor - Select configuration Select snippet This will delete the node and all its languages. If you only want to delete one language, you should unpublish the node in that language instead. @@ -1406,6 +1407,8 @@ To manage your website, simply open the Umbraco back office and start adding con User Saved User type saved User group saved + Cultures and hostnames saved + Error saving cultures and hostnames File not saved file could not be saved. Please check file permissions File saved @@ -1574,6 +1577,11 @@ To manage your website, simply open the Umbraco back office and start adding con Choose extra Choose default are added + Warning + You are deleting the row configuration + + Deleting a row configuration name will result in loss of data for any existing content that is based on this configuration. + Compositions @@ -1599,8 +1607,6 @@ To manage your website, simply open the Umbraco back office and start adding con Create new Use existing Editor settings - Available configurations - Create a new configuration Configuration Yes, delete was moved underneath @@ -1976,6 +1982,7 @@ To manage your website, simply open the Umbraco back office and start adding con Newest Oldest Last login + No user groups have been added Validation @@ -2101,6 +2108,14 @@ To manage your website, simply open the Umbraco back office and start adding con %0%.]]>

Results of the scheduled Umbraco Health Checks run on %0% at %1% are as follows:

%2%]]>
Umbraco Health Check Status: %0% + Check All Groups + Check group + + The health checker evaluates various areas of your site for best practice settings, configuration, potential problems, etc. You can easily fix problems by pressing a button. + You can add your own health checks, have a look at the documentation for more information about custom health checks.

+ ]]> +
Disable URL tracker @@ -2185,6 +2200,9 @@ To manage your website, simply open the Umbraco back office and start adding con Partial View Macro Member Data type + Search the redirect dashboard + Search the user group section + Search the users section References @@ -2344,4 +2362,8 @@ To manage your website, simply open the Umbraco back office and start adding con ]]> + + Welcome to The Friendly CMS + Thank you for choosing Umbraco - we think this could be the beginning of something beautiful. While it may feel overwhelming at first, we've done a lot to make the learning curve as smooth and fast as possible. + 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 5e0bcdf35a..83d896d489 100644 --- a/src/Umbraco.Web.UI/Umbraco/config/lang/en_us.xml +++ b/src/Umbraco.Web.UI/Umbraco/config/lang/en_us.xml @@ -270,6 +270,8 @@ Last edited Date/time this document was edited Remove file(s) + Click here to remove the image from the media item + Click here to remove the file from the media item Link to document Member of group(s) Not a member of group(s) @@ -1411,6 +1413,8 @@ To manage your website, simply open the Umbraco back office and start adding con User Saved User type saved User group saved + Cultures and hostnames saved + Error saving cultures and hostnames File not saved file could not be saved. Please check file permissions File saved @@ -1588,6 +1592,11 @@ To manage your website, simply open the Umbraco back office and start adding con Choose extra Choose default are added + Warning + You are deleting the row configuration + + Deleting a row configuration name will result in loss of data for any existing content that is based on this configuration. + Compositions @@ -1989,6 +1998,7 @@ To manage your website, simply open the Umbraco back office and start adding con Newest Oldest Last login + No user groups have been added Validation @@ -2116,6 +2126,14 @@ To manage your website, simply open the Umbraco back office and start adding con %0%.]]>

Results of the scheduled Umbraco Health Checks run on %0% at %1% are as follows:

%2%]]>
Umbraco Health Check Status: %0% + Check All Groups + Check group + + The health checker evaluates various areas of your site for best practice settings, configuration, potential problems, etc. You can easily fix problems by pressing a button. + You can add your own health checks, have a look at the documentation for more information about custom health checks.

+ ]]> +
Disable URL tracker @@ -2201,6 +2219,9 @@ To manage your website, simply open the Umbraco back office and start adding con Partial View Macro Member Data type + Search the redirect dashboard + Search the user group section + Search the users section References @@ -2360,4 +2381,8 @@ To manage your website, simply open the Umbraco back office and start adding con ]]> + + Welcome to The Friendly CMS + Thank you for choosing Umbraco - we think this could be the beginning of something beautiful. While it may feel overwhelming at first, we've done a lot to make the learning curve as smooth and fast as possible. + diff --git a/src/Umbraco.Web.UI/Umbraco/config/lang/sv.xml b/src/Umbraco.Web.UI/Umbraco/config/lang/sv.xml index 31846e9e07..152a40b965 100644 --- a/src/Umbraco.Web.UI/Umbraco/config/lang/sv.xml +++ b/src/Umbraco.Web.UI/Umbraco/config/lang/sv.xml @@ -4,6 +4,9 @@ The Umbraco community https://our.umbraco.com/documentation/Extending-Umbraco/Language-Files + + Innehåll + Hantera domännamn Hantera versioner @@ -11,6 +14,7 @@ Ändra dokumenttyp Kopiera Skapa + Skapa grupp Skapa paket Skapa innehållsmall Standardvärde @@ -38,6 +42,12 @@ Avpublicera Uppdatera + + Innehåll + Administration + Struktur + Övrigt + Lägg till nytt domännamn Domännamn @@ -98,6 +108,7 @@ En innehållsmall är fördefinierat innehåll som en redaktör kan välja att använda som grund för att skapa nytt innehåll + Rensa urval Fetstil Minska indrag Infoga formulärfält @@ -121,6 +132,7 @@ Spara och publicera Spara och schemalägg Spara och skicka för godkännande + Schemaläggning Välj Förhandsgranska Förhandsgranskning är avstängt på grund av att det inte finns någon mall tilldelad @@ -295,6 +307,12 @@ Webbplatsen har indexerats Cache för webbplatsen har uppdaterats. Allt publicerat innehåll är nu uppdaterat. Innehåll som inte har publicerats är fortfarande opublicerat. Webbplatsens cache kommer att uppdateras. Allt innehåll som är publicerat kommer att uppdateras. Innehåll som inte är publicerat kommer att förbli opublicerat. + Välj startnod för innehåll + Välj ikon + Välj startnod för media + Välj användargrupper + Välj sektioner + Välj användare Antal kolumner Antal rader Klicka på förhandsgranskningsbilden för att se bilden i full storlek @@ -425,6 +443,7 @@ Egenskaper E-postadress för formulärsdata Papperskorg + Din papperskorg är tom Återstående Ta bort Döp om @@ -568,6 +587,7 @@ Klicka för att ladda upp eller klicka här för att välja filer + Drag och släpp dina filer i denna yta Välj sida ovan... @@ -601,6 +621,7 @@ Paketalternativ Paket läsmig Paketvalv + Sök efter paket Bekräfta avinstallation Paketet har avinstallerats Paketet har avinstallerats utan problem @@ -621,6 +642,7 @@ Fyll i ditt lösenord Skriv för att söka... Fyll i ditt lösenord + Välj alias... Skriv för att lägga till taggar (och tryck enter efter varje tagg)... @@ -691,6 +713,7 @@ Media Medlemmar Nyhetsbrev + Paket Inställningar Statistik Översättning @@ -786,7 +809,7 @@ Sidmall - Image + Bild Macro Lägg till Choose layout @@ -866,6 +889,7 @@ Cacha webbläsare + Innehåll Papperskorg Skapade paket Datatyper @@ -902,24 +926,52 @@ Fel vid kontroll av uppdatering. Se trace-stack för mer information. + Åtkomst + Baserat på tilldelade grupper och startnod så har användaren åtkomst till följande noder + Tilldela åtkomst Administratör Kategorifält + Användare skapad Ändra lösenord - Du kan byta ditt lösenord för Umbraco Back Office genom att fylla i nedanstående formulär och klicka på knappen "Ändra lösenord". + Ändra bild Bekräfta det nya lösenordet + Du kan byta ditt lösenord för Umbraco Back Office genom att fylla i nedanstående formulär och klicka på knappen "Ändra lösenord". Innehållskanal + Skapa en till användare + Skapa nya användare för att ge dom åtkomst till Umbraco. När en ny användare skapas kommer ett lösenord genereras som du kan dela med användaren. Skapa användare + Ta bort användare User + Är du säker på att du vill ta bort användarens konto? Fält för beskrivning Avaktivera användare Dokumenttyp Redaktör Fält för utdrag + Misslyckade inloggningsförsök + Gå till användarens profil + Lägg till grupper för att tilldela åtkomst och rättigheter + Bjud in + Bjud in en till användare + Bjud in nya användare för att ge dom åtkomst till Umbraco. Ett e-postmeddelande kommer skikcas till användaren med information om hur man loggar in i Umbraco. Inbjudningar är giltiga i 72 timmar. Språk + Välj de språk som kommer visas i meny och dialoger + Senast utlåst + Senast inloggad + Lösenordet ändrades Login Startnod i mediabiblioteket + Begränsa media sectionen till en specifik startnod + Media startnoder + Begränsa media sectionen till specifika startnoder Sektioner Byt ditt lösenord + har inte blivit utlåst + har inte loggat in ännu Inaktivera tillgång till Umbraco + Lösenordet har inte ändrats + Ingen startnod vald + Inga startnoder valda + Gammalt lösenord Lösenord Ditt lösenord är nu ändrat! Vänligen bekräfta ditt nya lösenord @@ -933,17 +985,36 @@ Du redigerar nu rättigheterna för sidorna: Välj de sidor vars rättigheter du vill redigera Återställ lösenord + Ta bort bild + Standard rättigheter + Granulära rättigheter Sök igenom alla undernoder + Sätt rättigheter för specifika noder + Profil Sessionen går ut + Välj sektioner för användaråtkomst + Alla + Aktiv + Utlåst + Inbjuden + Inaktiv Namn (A-Z) Namn (Z-A) - Startnod i innehåll + Startnod för innehåll + Begränsa sidträdet till en specifik startnod + Startnoder för innehåll + Begränsa sidträdet till specifika startnoder + Användare ändrad Användarens namn + Användarhantering Användarrättigheter Användartyp Användartyper Skribent Din nuvarande historik Din profil + Nyast + Äldst + Senaste login diff --git a/src/Umbraco.Web/Editors/Binders/ContentItemBinder.cs b/src/Umbraco.Web/Editors/Binders/ContentItemBinder.cs index 11a876345d..a6cba6ce41 100644 --- a/src/Umbraco.Web/Editors/Binders/ContentItemBinder.cs +++ b/src/Umbraco.Web/Editors/Binders/ContentItemBinder.cs @@ -49,18 +49,15 @@ namespace Umbraco.Web.Editors.Binders { foreach (var variant in model.Variants) { - if (variant.Culture.IsNullOrWhiteSpace()) - { - //map the property dto collection (no culture is passed to the mapping context so it will be invariant) - variant.PropertyCollectionDto = Current.Mapper.Map(model.PersistedContent); - } - else - { - //map the property dto collection with the culture of the current variant - variant.PropertyCollectionDto = Current.Mapper.Map( - model.PersistedContent, - context => context.SetCulture(variant.Culture)); - } + //map the property dto collection with the culture of the current variant + variant.PropertyCollectionDto = Current.Mapper.Map( + model.PersistedContent, + context => + { + // either of these may be null and that is ok, if it's invariant they will be null which is what is expected + context.SetCulture(variant.Culture); + context.SetSegment(variant.Segment); + }); //now map all of the saved values to the dto _modelBinderHelper.MapPropertyValuesFromSaved(variant, variant.PropertyCollectionDto); @@ -87,6 +84,5 @@ namespace Umbraco.Web.Editors.Binders model.ParentId, contentType); } - } } diff --git a/src/Umbraco.Web/Editors/ContentController.cs b/src/Umbraco.Web/Editors/ContentController.cs index 361912b2bd..f5d72894ca 100644 --- a/src/Umbraco.Web/Editors/ContentController.cs +++ b/src/Umbraco.Web/Editors/ContentController.cs @@ -303,7 +303,7 @@ namespace Umbraco.Web.Editors } /// - /// Gets the content json for the content id + /// Gets the content json for the content guid /// /// /// @@ -323,7 +323,7 @@ namespace Umbraco.Web.Editors } /// - /// Gets the content json for the content id + /// Gets the content json for the content udi /// /// /// @@ -341,7 +341,7 @@ namespace Umbraco.Web.Editors } /// - /// Gets an empty content item for the + /// Gets an empty content item for the document type. /// /// /// @@ -1836,8 +1836,13 @@ namespace Umbraco.Web.Editors /// private void MapValuesForPersistence(ContentItemSave contentSave) { - // inline method to determine if a property type varies - bool Varies(Property property) => property.PropertyType.VariesByCulture(); + // inline method to determine the culture and segment to persist the property + (string culture, string segment) PropertyCultureAndSegment(Property property, ContentVariantSave variant) + { + var culture = property.PropertyType.VariesByCulture() ? variant.Culture : null; + var segment = property.PropertyType.VariesBySegment() ? variant.Segment : null; + return (culture, segment); + } var variantIndex = 0; @@ -1876,8 +1881,18 @@ namespace Umbraco.Web.Editors MapPropertyValuesForPersistence( contentSave, propertyCollection, - (save, property) => Varies(property) ? property.GetValue(variant.Culture) : property.GetValue(), //get prop val - (save, property, v) => { if (Varies(property)) property.SetValue(v, variant.Culture); else property.SetValue(v); }, //set prop val + (save, property) => + { + // Get property value + (var culture, var segment) = PropertyCultureAndSegment(property, variant); + return property.GetValue(culture, segment); + }, + (save, property, v) => + { + // Set property value + (var culture, var segment) = PropertyCultureAndSegment(property, variant); + property.SetValue(v, culture, segment); + }, variant.Culture); variantIndex++; diff --git a/src/Umbraco.Web/Editors/DataTypeController.cs b/src/Umbraco.Web/Editors/DataTypeController.cs index 31e0d70a42..5f5f5104cb 100644 --- a/src/Umbraco.Web/Editors/DataTypeController.cs +++ b/src/Umbraco.Web/Editors/DataTypeController.cs @@ -20,6 +20,7 @@ using Umbraco.Web.Composing; using Umbraco.Core.Configuration; using Umbraco.Core.Logging; using Umbraco.Core.Persistence; +using System.Web.Http.Controllers; namespace Umbraco.Web.Editors { @@ -34,6 +35,7 @@ namespace Umbraco.Web.Editors [PluginController("UmbracoApi")] [UmbracoTreeAuthorize(Constants.Trees.DataTypes, Constants.Trees.DocumentTypes, Constants.Trees.MediaTypes, Constants.Trees.MemberTypes)] [EnableOverrideAuthorization] + [DataTypeControllerConfiguration] public class DataTypeController : BackOfficeNotificationsController { private readonly PropertyEditorCollection _propertyEditors; @@ -44,6 +46,19 @@ namespace Umbraco.Web.Editors _propertyEditors = propertyEditors; } + /// + /// Configures this controller with a custom action selector + /// + private class DataTypeControllerConfigurationAttribute : Attribute, IControllerConfiguration + { + public void Initialize(HttpControllerSettings controllerSettings, HttpControllerDescriptor controllerDescriptor) + { + controllerSettings.Services.Replace(typeof(IHttpActionSelector), new ParameterSwapControllerActionSelector( + new ParameterSwapControllerActionSelector.ParameterSwapInfo("GetById", "id", typeof(int), typeof(Guid), typeof(Udi)) + )); + } + } + /// /// Gets data type by name /// @@ -70,6 +85,40 @@ namespace Umbraco.Web.Editors return Mapper.Map(dataType); } + /// + /// Gets the datatype json for the datatype guid + /// + /// + /// + public DataTypeDisplay GetById(Guid id) + { + var dataType = Services.DataTypeService.GetDataType(id); + if (dataType == null) + { + throw new HttpResponseException(HttpStatusCode.NotFound); + } + return Mapper.Map(dataType); + } + + /// + /// Gets the datatype json for the datatype udi + /// + /// + /// + public DataTypeDisplay GetById(Udi id) + { + var guidUdi = id as GuidUdi; + if (guidUdi == null) + throw new HttpResponseException(HttpStatusCode.NotFound); + + var dataType = Services.DataTypeService.GetDataType(guidUdi.Guid); + if (dataType == null) + { + throw new HttpResponseException(HttpStatusCode.NotFound); + } + return Mapper.Map(dataType); + } + /// /// Deletes a data type with a given ID /// diff --git a/src/Umbraco.Web/Editors/MacrosController.cs b/src/Umbraco.Web/Editors/MacrosController.cs index 2e68925ce4..38103400d9 100644 --- a/src/Umbraco.Web/Editors/MacrosController.cs +++ b/src/Umbraco.Web/Editors/MacrosController.cs @@ -19,6 +19,7 @@ using Umbraco.Web.Mvc; using Umbraco.Web.WebApi; using Umbraco.Web.WebApi.Filters; using Constants = Umbraco.Core.Constants; +using System.Web.Http.Controllers; namespace Umbraco.Web.Editors { @@ -28,6 +29,7 @@ namespace Umbraco.Web.Editors /// [PluginController("UmbracoApi")] [UmbracoTreeAuthorize(Constants.Trees.Macros)] + [MacrosControllerConfiguration] public class MacrosController : BackOfficeNotificationsController { private readonly IMacroService _macroService; @@ -38,6 +40,19 @@ namespace Umbraco.Web.Editors _macroService = Services.MacroService; } + /// + /// Configures this controller with a custom action selector + /// + private class MacrosControllerConfigurationAttribute : Attribute, IControllerConfiguration + { + public void Initialize(HttpControllerSettings controllerSettings, HttpControllerDescriptor controllerDescriptor) + { + controllerSettings.Services.Replace(typeof(IHttpActionSelector), new ParameterSwapControllerActionSelector( + new ParameterSwapControllerActionSelector.ParameterSwapInfo("GetById", "id", typeof(int), typeof(Guid), typeof(Udi)) + )); + } + } + /// /// Creates a new macro /// @@ -97,39 +112,43 @@ namespace Umbraco.Web.Editors return this.ReturnErrorResponse($"Macro with id {id} does not exist"); } - var macroDisplay = new MacroDisplay - { - Alias = macro.Alias, - Id = macro.Id, - Key = macro.Key, - Name = macro.Name, - CacheByPage = macro.CacheByPage, - CacheByUser = macro.CacheByMember, - CachePeriod = macro.CacheDuration, - View = macro.MacroSource, - RenderInEditor = !macro.DontRender, - UseInEditor = macro.UseInEditor, - Path = $"-1,{macro.Id}" - }; - - var parameters = new List(); - - foreach (var param in macro.Properties.Values.OrderBy(x => x.SortOrder)) - { - parameters.Add(new MacroParameterDisplay - { - Editor = param.EditorAlias, - Key = param.Alias, - Label = param.Name, - Id = param.Id - }); - } - - macroDisplay.Parameters = parameters; + var macroDisplay = MapToDisplay(macro); return this.Request.CreateResponse(HttpStatusCode.OK, macroDisplay); } + [HttpGet] + public HttpResponseMessage GetById(Guid id) + { + var macro = _macroService.GetById(id); + + if (macro == null) + { + return this.ReturnErrorResponse($"Macro with id {id} does not exist"); + } + + var macroDisplay = MapToDisplay(macro); + + return this.Request.CreateResponse(HttpStatusCode.OK, macroDisplay); + } + + [HttpGet] + public HttpResponseMessage GetById(Udi id) + { + var guidUdi = id as GuidUdi; + if (guidUdi == null) + this.ReturnErrorResponse($"Macro with id {id} does not exist"); + + var macro = _macroService.GetById(guidUdi.Guid); + if (macro == null) + { + return this.ReturnErrorResponse($"Macro with id {id} does not exist"); + } + + var macroDisplay = MapToDisplay(macro); + + return this.Request.CreateResponse(HttpStatusCode.OK, macroDisplay); + } [HttpPost] public HttpResponseMessage DeleteById(int id) @@ -384,5 +403,29 @@ namespace Umbraco.Web.Editors return files; } + + /// + /// Used to map an instance to a + /// + /// + /// + private MacroDisplay MapToDisplay(IMacro macro) + { + var display = Mapper.Map(macro); + + var parameters = macro.Properties.Values + .OrderBy(x => x.SortOrder) + .Select(x => new MacroParameterDisplay() + { + Editor = x.EditorAlias, + Key = x.Alias, + Label = x.Name, + Id = x.Id + }); + + display.Parameters = parameters; + + return display; + } } } diff --git a/src/Umbraco.Web/ExamineExtensions.cs b/src/Umbraco.Web/ExamineExtensions.cs index 9a9fa98d95..421993f8fd 100644 --- a/src/Umbraco.Web/ExamineExtensions.cs +++ b/src/Umbraco.Web/ExamineExtensions.cs @@ -2,32 +2,95 @@ using System.Collections.Generic; using System.Linq; using Examine; -using Umbraco.Core; +using Examine.LuceneEngine.Providers; using Umbraco.Core.Models.PublishedContent; +using Umbraco.Examine; using Umbraco.Web.PublishedCache; namespace Umbraco.Web { /// - /// Extension methods for Examine + /// Extension methods for Examine. /// public static class ExamineExtensions { + /// + /// Creates an containing all content from the . + /// + /// The search results. + /// The cache to fetch the content from. + /// + /// An containing all content. + /// + /// cache + /// + /// Search results are skipped if it can't be fetched from the by its integer id. + /// public static IEnumerable ToPublishedSearchResults(this IEnumerable results, IPublishedCache cache) { - var list = new List(); + if (cache == null) throw new ArgumentNullException(nameof(cache)); - foreach (var result in results.OrderByDescending(x => x.Score)) + var publishedSearchResults = new List(); + + foreach (var result in results) { - if (!int.TryParse(result.Id, out var intId)) continue; //invalid - var content = cache.GetById(intId); - if (content == null) continue; // skip if this doesn't exist in the cache - - list.Add(new PublishedSearchResult(content, result.Score)); - + if (int.TryParse(result.Id, out var contentId) && + cache.GetById(contentId) is IPublishedContent content) + { + publishedSearchResults.Add(new PublishedSearchResult(content, result.Score)); + } } - return list; + return publishedSearchResults; + } + + /// + /// Creates an containing all content, media or members from the . + /// + /// The search results. + /// The snapshot. + /// + /// An containing all content, media or members. + /// + /// snapshot + /// + /// Search results are skipped if it can't be fetched from the respective cache by its integer id. + /// + public static IEnumerable ToPublishedSearchResults(this IEnumerable results, IPublishedSnapshot snapshot) + { + if (snapshot == null) throw new ArgumentNullException(nameof(snapshot)); + + var publishedSearchResults = new List(); + + foreach (var result in results) + { + if (int.TryParse(result.Id, out var contentId) && + result.Values.TryGetValue(LuceneIndex.CategoryFieldName, out var indexType)) + { + IPublishedContent content; + switch (indexType) + { + case IndexTypes.Content: + content = snapshot.Content.GetById(contentId); + break; + case IndexTypes.Media: + content = snapshot.Media.GetById(contentId); + break; + case IndexTypes.Member: + content = snapshot.Members.GetById(contentId); + break; + default: + continue; + } + + if (content != null) + { + publishedSearchResults.Add(new PublishedSearchResult(content, result.Score)); + } + } + } + + return publishedSearchResults; } } } diff --git a/src/Umbraco.Web/IPublishedContentQuery.cs b/src/Umbraco.Web/IPublishedContentQuery.cs index 8a8d678aba..7066475dc9 100644 --- a/src/Umbraco.Web/IPublishedContentQuery.cs +++ b/src/Umbraco.Web/IPublishedContentQuery.cs @@ -35,52 +35,63 @@ namespace Umbraco.Web /// /// Searches content. /// - /// Term to search. - /// Optional culture. - /// Optional index name. + /// The term to search. + /// The culture (defaults to a culture insensitive search). + /// The name of the index to search (defaults to ). + /// + /// The search results. + /// /// /// - /// When the is not specified or is *, all cultures are searched. + /// When the is not specified or is *, all cultures are searched. /// To search for only invariant documents and fields use null. /// When searching on a specific culture, all culture specific fields are searched for the provided culture and all invariant fields for all documents. /// /// While enumerating results, the ambient culture is changed to be the searched culture. /// - IEnumerable Search(string term, string culture = "*", string indexName = null); + IEnumerable Search(string term, string culture = "*", string indexName = Constants.UmbracoIndexes.ExternalIndexName); /// /// Searches content. /// - /// Term to search. - /// Numbers of items to skip. - /// Numbers of items to return. - /// Total number of matching items. - /// Optional culture. - /// Optional index name. + /// The term to search. + /// The amount of results to skip. + /// The amount of results to take/return. + /// The total amount of records. + /// The culture (defaults to a culture insensitive search). + /// The name of the index to search (defaults to ). + /// + /// The search results. + /// /// /// - /// When the is not specified or is *, all cultures are searched. + /// When the is not specified or is *, all cultures are searched. /// To search for only invariant documents and fields use null. /// When searching on a specific culture, all culture specific fields are searched for the provided culture and all invariant fields for all documents. /// /// While enumerating results, the ambient culture is changed to be the searched culture. /// - IEnumerable Search(string term, int skip, int take, out long totalRecords, string culture = "*", string indexName = null); + IEnumerable Search(string term, int skip, int take, out long totalRecords, string culture = "*", string indexName = Constants.UmbracoIndexes.ExternalIndexName); /// - /// Executes the query and converts the results to PublishedSearchResult. + /// Executes the query and converts the results to . /// - /// - /// While enumerating results, the ambient culture is changed to be the searched culture. - /// + /// The query. + /// + /// The search results. + /// IEnumerable Search(IQueryExecutor query); /// - /// Executes the query and converts the results to PublishedSearchResult. + /// Executes the query and converts the results to . /// - /// - /// While enumerating results, the ambient culture is changed to be the searched culture. - /// + /// The query. + /// The amount of results to skip. + /// The amount of results to take/return. + /// The total amount of records. + /// + /// The search results. + /// IEnumerable Search(IQueryExecutor query, int skip, int take, out long totalRecords); } } diff --git a/src/Umbraco.Web/Models/ContentEditing/ContentPropertyBasic.cs b/src/Umbraco.Web/Models/ContentEditing/ContentPropertyBasic.cs index c5c22484ad..2b70a63035 100644 --- a/src/Umbraco.Web/Models/ContentEditing/ContentPropertyBasic.cs +++ b/src/Umbraco.Web/Models/ContentEditing/ContentPropertyBasic.cs @@ -53,11 +53,21 @@ namespace Umbraco.Web.Models.ContentEditing [ReadOnly(true)] public string Culture { get; set; } + /// + /// The segment of the property + /// + /// + /// The segment value of a property can always be null but can only have a non-null value + /// when the property can be varied by segment. + /// + [DataMember(Name = "segment")] + [ReadOnly(true)] + public string Segment { get; set; } + /// /// Used internally during model mapping /// [IgnoreDataMember] internal IDataEditor PropertyEditor { get; set; } - } } diff --git a/src/Umbraco.Web/Models/ContentEditing/ContentVariantSave.cs b/src/Umbraco.Web/Models/ContentEditing/ContentVariantSave.cs index deadac949a..9a7555ad92 100644 --- a/src/Umbraco.Web/Models/ContentEditing/ContentVariantSave.cs +++ b/src/Umbraco.Web/Models/ContentEditing/ContentVariantSave.cs @@ -29,6 +29,12 @@ namespace Umbraco.Web.Models.ContentEditing [DataMember(Name = "culture")] public string Culture { get; set; } + /// + /// The segment of this variant, if this is invariant than this is null or empty + /// + [DataMember(Name = "segment")] + public string Segment { get; set; } + /// /// Indicates if the variant should be updated /// diff --git a/src/Umbraco.Web/Models/Mapping/ContentPropertyBasicMapper.cs b/src/Umbraco.Web/Models/Mapping/ContentPropertyBasicMapper.cs index 36c1b360b2..cf1bc3c253 100644 --- a/src/Umbraco.Web/Models/Mapping/ContentPropertyBasicMapper.cs +++ b/src/Umbraco.Web/Models/Mapping/ContentPropertyBasicMapper.cs @@ -70,8 +70,13 @@ namespace Umbraco.Web.Models.Mapping dest.Culture = culture; + // Get the segment, which is always allowed to be null even if the propertyType *can* be varied by segment. + // There is therefore no need to perform the null check like with culture above. + var segment = !property.PropertyType.VariesBySegment() ? null : context.GetSegment(); + dest.Segment = segment; + // if no 'IncludeProperties' were specified or this property is set to be included - we will map the value and return. - dest.Value = editor.GetValueEditor().ToEditor(property, DataTypeService, culture); + dest.Value = editor.GetValueEditor().ToEditor(property, DataTypeService, culture, segment); } } } diff --git a/src/Umbraco.Web/Models/Mapping/ContentVariantMapper.cs b/src/Umbraco.Web/Models/Mapping/ContentVariantMapper.cs index c279ae2c70..5d076812f3 100644 --- a/src/Umbraco.Web/Models/Mapping/ContentVariantMapper.cs +++ b/src/Umbraco.Web/Models/Mapping/ContentVariantMapper.cs @@ -21,52 +21,117 @@ namespace Umbraco.Web.Models.Mapping public IEnumerable Map(IContent source, MapperContext context) { - var result = new List(); - if (!source.ContentType.VariesByCulture()) + var variesByCulture = source.ContentType.VariesByCulture(); + var variesBySegment = source.ContentType.VariesBySegment(); + + IList variants = new List(); + + if (!variesByCulture && !variesBySegment) { - //this is invariant so just map the IContent instance to ContentVariationDisplay - result.Add(context.Map(source)); + // this is invariant so just map the IContent instance to ContentVariationDisplay + var variantDisplay = context.Map(source); + variants.Add(variantDisplay); + } + else if (variesByCulture && !variesBySegment) + { + var languages = GetLanguages(context); + variants = languages + .Select(language => CreateVariantDisplay(context, source, language, null)) + .ToList(); + } + else if (variesBySegment && !variesByCulture) + { + // Segment only + var segments = GetSegments(source); + variants = segments + .Select(segment => CreateVariantDisplay(context, source, null, segment)) + .ToList(); } else { - var allLanguages = _localizationService.GetAllLanguages().OrderBy(x => x.Id).ToList(); - if (allLanguages.Count == 0) return Enumerable.Empty(); //this should never happen + // Culture and segment + var languages = GetLanguages(context).ToList(); + var segments = GetSegments(source).ToList(); - var langs = context.MapEnumerable(allLanguages).ToList(); - - //create a variant for each language, then we'll populate the values - var variants = langs.Select(x => + if (languages.Count == 0 || segments.Count == 0) { - //We need to set the culture in the mapping context since this is needed to ensure that the correct property values - //are resolved during the mapping - context.SetCulture(x.IsoCode); - return context.Map(source); - }).ToList(); - - for (int i = 0; i < langs.Count; i++) - { - var x = langs[i]; - var variant = variants[i]; - - variant.Language = x; - variant.Name = source.GetCultureName(x.IsoCode); + // This should not happen + throw new InvalidOperationException("No languages or segments available"); } - //Put the default language first in the list & then sort rest by a-z - var defaultLang = variants.SingleOrDefault(x => x.Language.IsDefault); + variants = languages + .SelectMany(language => segments + .Select(segment => CreateVariantDisplay(context, source, language, segment))) + .ToList(); + } - //Remove the default language from the list for now - variants.Remove(defaultLang); - - //Sort the remaining languages a-z - variants = variants.OrderBy(x => x.Language.Name).ToList(); - - //Insert the default language as the first item - variants.Insert(0, defaultLang); + return SortVariants(variants); + } + private IList SortVariants(IList variants) + { + if (variants == null || variants.Count <= 1) + { return variants; } - return result; + + // Default variant first, then order by language, segment. + return variants + .OrderBy(v => IsDefaultLanguage(v) ? 0 : 1) + .ThenBy(v => IsDefaultSegment(v) ? 0 : 1) + .ThenBy(v => v?.Language?.Name) + .ThenBy(v => v.Segment) + .ToList(); + } + + private static bool IsDefaultSegment(ContentVariantDisplay variant) + { + return variant.Segment == null; + } + + private static bool IsDefaultLanguage(ContentVariantDisplay variant) + { + return variant.Language == null || variant.Language.IsDefault; + } + + private IEnumerable GetLanguages(MapperContext context) + { + var allLanguages = _localizationService.GetAllLanguages().OrderBy(x => x.Id).ToList(); + if (allLanguages.Count == 0) + { + // This should never happen + return Enumerable.Empty(); + } + else + { + return context.MapEnumerable(allLanguages).ToList(); + } + } + + /// + /// Returns all segments assigned to the content + /// + /// + /// + /// Returns all segments assigned to the content including 'null' values + /// + private IEnumerable GetSegments(IContent content) + { + return content.Properties.SelectMany(p => p.Values.Select(v => v.Segment)).Distinct(); + } + + private ContentVariantDisplay CreateVariantDisplay(MapperContext context, IContent content, Language language, string segment) + { + context.SetCulture(language?.IsoCode); + context.SetSegment(segment); + + var variantDisplay = context.Map(content); + + variantDisplay.Segment = segment; + variantDisplay.Language = language; + variantDisplay.Name = content.GetCultureName(language?.IsoCode); + + return variantDisplay; } } } diff --git a/src/Umbraco.Web/Models/Mapping/MacroMapDefinition.cs b/src/Umbraco.Web/Models/Mapping/MacroMapDefinition.cs index e5bca22287..e654fc16a1 100644 --- a/src/Umbraco.Web/Models/Mapping/MacroMapDefinition.cs +++ b/src/Umbraco.Web/Models/Mapping/MacroMapDefinition.cs @@ -1,4 +1,5 @@ -using System.Collections.Generic; +using System; +using System.Collections.Generic; using System.Linq; using Umbraco.Core; using Umbraco.Core.Logging; @@ -23,6 +24,7 @@ namespace Umbraco.Web.Models.Mapping public void DefineMaps(UmbracoMapper mapper) { mapper.Define((source, context) => new EntityBasic(), Map); + mapper.Define((source, context) => new MacroDisplay(), Map); mapper.Define>((source, context) => context.MapEnumerable(source.Properties.Values)); mapper.Define((source, context) => new MacroParameter(), Map); } @@ -40,6 +42,23 @@ namespace Umbraco.Web.Models.Mapping target.Udi = Udi.Create(Constants.UdiEntityType.Macro, source.Key); } + private void Map(IMacro source, MacroDisplay target, MapperContext context) + { + target.Alias = source.Alias; + target.Icon = Constants.Icons.Macro; + target.Id = source.Id; + target.Key = source.Key; + target.Name = source.Name; + target.ParentId = -1; + target.Path = "-1," + source.Id; + target.Udi = Udi.Create(Constants.UdiEntityType.Macro, source.Key); + target.CacheByPage = source.CacheByPage; + target.CacheByUser = source.CacheByMember; + target.CachePeriod = source.CacheDuration; + target.UseInEditor = source.UseInEditor; + target.RenderInEditor = !source.DontRender; + target.View = source.MacroSource; + } // Umbraco.Code.MapAll -Value private void Map(IMacroProperty source, MacroParameter target, MapperContext context) { diff --git a/src/Umbraco.Web/Models/Mapping/MapperContextExtensions.cs b/src/Umbraco.Web/Models/Mapping/MapperContextExtensions.cs index 1538f1a987..20a387c679 100644 --- a/src/Umbraco.Web/Models/Mapping/MapperContextExtensions.cs +++ b/src/Umbraco.Web/Models/Mapping/MapperContextExtensions.cs @@ -8,6 +8,7 @@ namespace Umbraco.Web.Models.Mapping internal static class MapperContextExtensions { private const string CultureKey = "Map.Culture"; + private const string SegmentKey = "Map.Segment"; private const string IncludedPropertiesKey = "Map.IncludedProperties"; /// @@ -18,6 +19,14 @@ namespace Umbraco.Web.Models.Mapping return context.HasItems && context.Items.TryGetValue(CultureKey, out var obj) && obj is string s ? s : null; } + /// + /// Gets the context segment. + /// + public static string GetSegment(this MapperContext context) + { + return context.HasItems && context.Items.TryGetValue(SegmentKey, out var obj) && obj is string s ? s : null; + } + /// /// Sets a context culture. /// @@ -26,6 +35,14 @@ namespace Umbraco.Web.Models.Mapping context.Items[CultureKey] = culture; } + /// + /// Sets a context segment. + /// + public static void SetSegment(this MapperContext context, string segment) + { + context.Items[SegmentKey] = segment; + } + /// /// Get included properties. /// @@ -42,4 +59,4 @@ namespace Umbraco.Web.Models.Mapping context.Items[IncludedPropertiesKey] = properties; } } -} \ No newline at end of file +} diff --git a/src/Umbraco.Web/PropertyEditors/GridPropertyEditor.cs b/src/Umbraco.Web/PropertyEditors/GridPropertyEditor.cs index 24e2fc29a5..792552c5d7 100644 --- a/src/Umbraco.Web/PropertyEditors/GridPropertyEditor.cs +++ b/src/Umbraco.Web/PropertyEditors/GridPropertyEditor.cs @@ -117,10 +117,10 @@ namespace Umbraco.Web.PropertyEditors /// public override object ToEditor(Property property, IDataTypeService dataTypeService, string culture = null, string segment = null) { - var val = property.GetValue(culture, segment); - if (val == null) return string.Empty; + var val = property.GetValue(culture, segment)?.ToString(); + if (val.IsNullOrWhiteSpace()) return string.Empty; - var grid = DeserializeGridValue(val.ToString(), out var rtes); + var grid = DeserializeGridValue(val, out var rtes); //process the rte values foreach (var rte in rtes.ToList()) diff --git a/src/Umbraco.Web/PublishedCache/NuCache/PublishedSnapshotService.cs b/src/Umbraco.Web/PublishedCache/NuCache/PublishedSnapshotService.cs index a866297d72..e0b95e8481 100755 --- a/src/Umbraco.Web/PublishedCache/NuCache/PublishedSnapshotService.cs +++ b/src/Umbraco.Web/PublishedCache/NuCache/PublishedSnapshotService.cs @@ -54,6 +54,7 @@ namespace Umbraco.Web.PublishedCache.NuCache private readonly ContentStore _mediaStore; private readonly SnapDictionary _domainStore; private readonly object _storesLock = new object(); + private readonly object _elementsLock = new object(); private BPlusTree _localContentDb; private BPlusTree _localMediaDb; @@ -1131,7 +1132,13 @@ namespace Umbraco.Web.PublishedCache.NuCache ContentStore.Snapshot contentSnap, mediaSnap; SnapDictionary.Snapshot domainSnap; IAppCache elementsCache; - lock (_storesLock) + + // Here we are reading/writing to shared objects so we need to lock (can't be _storesLock which manages the actual nucache files + // and would result in a deadlock). Even though we are locking around underlying readlocks (within CreateSnapshot) it's because + // we need to ensure that the result of contentSnap.Gen (etc) and the re-assignment of these values and _elements cache + // are done atomically. + + lock (_elementsLock) { var scopeContext = _scopeProvider.Context; diff --git a/src/Umbraco.Web/PublishedContentQuery.cs b/src/Umbraco.Web/PublishedContentQuery.cs index 2dbe4de4c5..d697898f33 100644 --- a/src/Umbraco.Web/PublishedContentQuery.cs +++ b/src/Umbraco.Web/PublishedContentQuery.cs @@ -183,54 +183,62 @@ namespace Umbraco.Web #region Search /// - public IEnumerable Search(string term, string culture = "*", string indexName = null) + public IEnumerable Search(string term, string culture = "*", string indexName = Constants.UmbracoIndexes.ExternalIndexName) { return Search(term, 0, 0, out _, culture, indexName); } /// - public IEnumerable Search(string term, int skip, int take, out long totalRecords, string culture = "*", string indexName = null) + public IEnumerable Search(string term, int skip, int take, out long totalRecords, string culture = "*", string indexName = Constants.UmbracoIndexes.ExternalIndexName) { - indexName = string.IsNullOrEmpty(indexName) - ? Constants.UmbracoIndexes.ExternalIndexName - : indexName; + if (skip < 0) + { + throw new ArgumentOutOfRangeException(nameof(skip), skip, "The value must be greater than or equal to zero."); + } + + if (take < 0) + { + throw new ArgumentOutOfRangeException(nameof(take), take, "The value must be greater than or equal to zero."); + } + + if (string.IsNullOrEmpty(indexName)) + { + indexName = Constants.UmbracoIndexes.ExternalIndexName; + } if (!_examineManager.TryGetIndex(indexName, out var index) || !(index is IUmbracoIndex umbIndex)) + { throw new InvalidOperationException($"No index found by name {indexName} or is not of type {typeof(IUmbracoIndex)}"); + } - var searcher = umbIndex.GetSearcher(); + var query = umbIndex.GetSearcher().CreateQuery(IndexTypes.Content); - // default to max 500 results - var count = skip == 0 && take == 0 ? 500 : skip + take; - - ISearchResults results; + IQueryExecutor queryExecutor; if (culture == "*") { - //search everything - - results = searcher.Search(term, count); + // Search everything + queryExecutor = query.ManagedQuery(term); } - else if (culture.IsNullOrWhiteSpace()) + else if (string.IsNullOrWhiteSpace(culture)) { - //only search invariant - - var qry = searcher.CreateQuery().Field(UmbracoContentIndex.VariesByCultureFieldName, "n"); //must not vary by culture - qry = qry.And().ManagedQuery(term); - results = qry.Execute(count); + // Only search invariant + queryExecutor = query.Field(UmbracoContentIndex.VariesByCultureFieldName, "n") // Must not vary by culture + .And().ManagedQuery(term); } else { - //search only the specified culture - - //get all index fields suffixed with the culture name supplied - var cultureFields = umbIndex.GetCultureAndInvariantFields(culture).ToArray(); - var qry = searcher.CreateQuery().ManagedQuery(term, cultureFields); - results = qry.Execute(count); + // Only search the specified culture + var fields = umbIndex.GetCultureAndInvariantFields(culture).ToArray(); // Get all index fields suffixed with the culture name supplied + queryExecutor = query.ManagedQuery(term, fields); } + var results = skip == 0 && take == 0 + ? queryExecutor.Execute() + : queryExecutor.Execute(skip + take); + totalRecords = results.TotalItemCount; - return new CultureContextualSearchResults(results.ToPublishedSearchResults(_publishedSnapshot.Content), _variationContextAccessor, culture); + return new CultureContextualSearchResults(results.Skip(skip).ToPublishedSearchResults(_publishedSnapshot.Content), _variationContextAccessor, culture); } /// @@ -242,12 +250,23 @@ namespace Umbraco.Web /// public IEnumerable Search(IQueryExecutor query, int skip, int take, out long totalRecords) { + if (skip < 0) + { + throw new ArgumentOutOfRangeException(nameof(skip), skip, "The value must be greater than or equal to zero."); + } + + if (take < 0) + { + throw new ArgumentOutOfRangeException(nameof(take), take, "The value must be greater than or equal to zero."); + } + var results = skip == 0 && take == 0 ? query.Execute() - : query.Execute(maxResults: skip + take); + : query.Execute(skip + take); totalRecords = results.TotalItemCount; - return results.ToPublishedSearchResults(_publishedSnapshot.Content); + + return results.Skip(skip).ToPublishedSearchResults(_publishedSnapshot); } /// @@ -320,9 +339,6 @@ namespace Umbraco.Web } } - - - #endregion } } diff --git a/src/Umbraco.Web/Trees/ContentTreeControllerBase.cs b/src/Umbraco.Web/Trees/ContentTreeControllerBase.cs index f3422a04c9..1069df0ec4 100644 --- a/src/Umbraco.Web/Trees/ContentTreeControllerBase.cs +++ b/src/Umbraco.Web/Trees/ContentTreeControllerBase.cs @@ -195,20 +195,30 @@ namespace Umbraco.Web.Trees //get the current user start node/paths GetUserStartNodes(out var userStartNodes, out var userStartNodePaths); - nodes.AddRange(entities.Select(x => GetSingleTreeNodeWithAccessCheck(x, id, queryStrings, userStartNodes, userStartNodePaths)).Where(x => x != null)); - // if the user does not have access to the root node, what we have is the start nodes, - // but to provide some context we also need to add their topmost nodes when they are not + // but to provide some context we need to add their topmost nodes when they are not // topmost nodes themselves (level > 1). if (id == rootIdString && hasAccessToRoot == false) { - var topNodeIds = entities.Where(x => x.Level > 1).Select(GetTopNodeId).Where(x => x != 0).Distinct().ToArray(); + // first add the entities that are topmost to the nodes collection + var topMostEntities = entities.Where(x => x.Level == 1).ToArray(); + nodes.AddRange(topMostEntities.Select(x => GetSingleTreeNodeWithAccessCheck(x, id, queryStrings, userStartNodes, userStartNodePaths)).Where(x => x != null)); + + // now add the topmost nodes of the entities that aren't topmost to the nodes collection as well + // - these will appear as "no-access" nodes in the tree, but will allow the editors to drill down through the tree + // until they reach their start nodes + var topNodeIds = entities.Except(topMostEntities).Select(GetTopNodeId).Where(x => x != 0).Distinct().ToArray(); if (topNodeIds.Length > 0) { var topNodes = Services.EntityService.GetAll(UmbracoObjectType, topNodeIds.ToArray()); nodes.AddRange(topNodes.Select(x => GetSingleTreeNodeWithAccessCheck(x, id, queryStrings, userStartNodes, userStartNodePaths)).Where(x => x != null)); } } + else + { + // the user has access to the root, just add the entities + nodes.AddRange(entities.Select(x => GetSingleTreeNodeWithAccessCheck(x, id, queryStrings, userStartNodes, userStartNodePaths)).Where(x => x != null)); + } return nodes; } diff --git a/src/Umbraco.Web/Trees/DataTypeTreeController.cs b/src/Umbraco.Web/Trees/DataTypeTreeController.cs index 4e5b1df631..6a7fb7f5ad 100644 --- a/src/Umbraco.Web/Trees/DataTypeTreeController.cs +++ b/src/Umbraco.Web/Trees/DataTypeTreeController.cs @@ -60,19 +60,20 @@ namespace Umbraco.Web.Trees //System ListView nodes var systemListViewDataTypeIds = GetNonDeletableSystemListViewDataTypeIds(); + var children = Services.EntityService.GetChildren(intId.Result, UmbracoObjectTypes.DataType).ToArray(); + var dataTypes = Services.DataTypeService.GetAll(children.Select(c => c.Id).ToArray()).ToDictionary(dt => dt.Id); + nodes.AddRange( - Services.EntityService.GetChildren(intId.Result, UmbracoObjectTypes.DataType) + children .OrderBy(entity => entity.Name) .Select(dt => { - var node = CreateTreeNode(dt.Id.ToInvariantString(), id, queryStrings, dt.Name, Constants.Icons.DataType, false); + var dataType = dataTypes[dt.Id]; + var node = CreateTreeNode(dt.Id.ToInvariantString(), id, queryStrings, dt.Name, dataType.Editor.Icon, false); node.Path = dt.Path; - if (systemListViewDataTypeIds.Contains(dt.Id)) - { - node.Icon = Constants.Icons.ListView; - } return node; - })); + }) + ); return nodes; } diff --git a/src/Umbraco.Web/Umbraco.Web.csproj b/src/Umbraco.Web/Umbraco.Web.csproj index 5d29e53d4a..caf91152fe 100755 --- a/src/Umbraco.Web/Umbraco.Web.csproj +++ b/src/Umbraco.Web/Umbraco.Web.csproj @@ -63,7 +63,7 @@ - + 2.7.0.100 @@ -1279,4 +1279,4 @@ - + \ No newline at end of file
@@ -45,7 +45,9 @@
- + + + @@ -53,9 +55,8 @@ diff --git a/src/Umbraco.Web.UI.Client/src/views/dashboard/default/StartupDashboardIntro.html b/src/Umbraco.Web.UI.Client/src/views/dashboard/default/StartupDashboardIntro.html index 0478e6ba3c..17a4dcdb65 100644 --- a/src/Umbraco.Web.UI.Client/src/views/dashboard/default/StartupDashboardIntro.html +++ b/src/Umbraco.Web.UI.Client/src/views/dashboard/default/StartupDashboardIntro.html @@ -40,8 +40,12 @@
-

Welcome to The Friendly CMS

-

Thank you for choosing Umbraco - we think this could be the beginning of something beautiful. While it may feel overwhelming at first, we've done a lot to make the learning curve as smooth and fast as possible.

+

+ Welcome to The Friendly CMS +

+

+ Thank you for choosing Umbraco - we think this could be the beginning of something beautiful. While it may feel overwhelming at first, we've done a lot to make the learning curve as smooth and fast as possible. +

diff --git a/src/Umbraco.Web.UI.Client/src/views/dashboard/settings/examinemanagement.controller.js b/src/Umbraco.Web.UI.Client/src/views/dashboard/settings/examinemanagement.controller.js index cd936bcdf7..97f8b6bd79 100644 --- a/src/Umbraco.Web.UI.Client/src/views/dashboard/settings/examinemanagement.controller.js +++ b/src/Umbraco.Web.UI.Client/src/views/dashboard/settings/examinemanagement.controller.js @@ -26,17 +26,16 @@ function ExamineManagementController($scope, $http, $q, $timeout, $location, umb function showSearchResultDialog(values) { if (vm.searchResults) { - localizationService.localize("examineManagement_fieldValues").then(function (value) { - - vm.searchResults.overlay = { + editorService.open({ title: value, searchResultValues: values, + size: "medium", view: "views/dashboard/settings/examinemanagementresults.html", close: function () { - vm.searchResults.overlay = null; + editorService.close(); } - }; + }); }); } } diff --git a/src/Umbraco.Web.UI.Client/src/views/dashboard/settings/examinemanagement.html b/src/Umbraco.Web.UI.Client/src/views/dashboard/settings/examinemanagement.html index 632127e38c..35962be39f 100644 --- a/src/Umbraco.Web.UI.Client/src/views/dashboard/settings/examinemanagement.html +++ b/src/Umbraco.Web.UI.Client/src/views/dashboard/settings/examinemanagement.html @@ -408,10 +408,4 @@
- - - diff --git a/src/Umbraco.Web.UI.Client/src/views/dashboard/settings/examinemanagementresults.html b/src/Umbraco.Web.UI.Client/src/views/dashboard/settings/examinemanagementresults.html index bb8a29fca5..26fa0cb72f 100644 --- a/src/Umbraco.Web.UI.Client/src/views/dashboard/settings/examinemanagementresults.html +++ b/src/Umbraco.Web.UI.Client/src/views/dashboard/settings/examinemanagementresults.html @@ -1,18 +1,41 @@
- - - - - - - - - - - - - - -
FieldValue
{{key}}{{val}}
- + + + + + + + + + + + + + + + + + + + +
FieldValue
{{key}}{{val}}
+
+
+
+ + + + + + +
diff --git a/src/Umbraco.Web.UI.Client/src/views/dashboard/settings/healthcheck.html b/src/Umbraco.Web.UI.Client/src/views/dashboard/settings/healthcheck.html index 4c041a573e..a73b5eccd7 100644 --- a/src/Umbraco.Web.UI.Client/src/views/dashboard/settings/healthcheck.html +++ b/src/Umbraco.Web.UI.Client/src/views/dashboard/settings/healthcheck.html @@ -5,10 +5,10 @@
-

- The health checker evaluates various areas of your site for best practice settings, configuration, potential problems, etc. You can easily fix problems by pressing a button. - You can add your own health checks, have a look at the documentation for more information about custom health checks. -

+ +

The health checker evaluates various areas of your site for best practice settings, configuration, potential problems, etc. You can easily fix problems by pressing a button. + You can add your own health checks, have a look at the documentation for more information about custom health checks.

+
@@ -85,9 +85,12 @@
{{ vm.selectedGroup.name }}
- +
diff --git a/src/Umbraco.Web.UI.Client/src/views/logviewer/search.controller.js b/src/Umbraco.Web.UI.Client/src/views/logviewer/search.controller.js index 70cfd0e190..d03f292717 100644 --- a/src/Umbraco.Web.UI.Client/src/views/logviewer/search.controller.js +++ b/src/Umbraco.Web.UI.Client/src/views/logviewer/search.controller.js @@ -262,11 +262,7 @@ submitButtonLabel: "Save Search", disableSubmitButton: true, view: "logviewersearch", - query: { - filterExpression: vm.logOptions.filterExpression, - startDate: vm.logOptions.startDate, - endDate: vm.logOptions.endDate - }, + query: vm.logOptions.filterExpression, submit: function (model) { //Resource call with two params (name & query) //API that opens the JSON and adds it to the bottom diff --git a/src/Umbraco.Web.UI.Client/src/views/macros/views/settings.html b/src/Umbraco.Web.UI.Client/src/views/macros/views/settings.html index d34cf1810d..7706734327 100644 --- a/src/Umbraco.Web.UI.Client/src/views/macros/views/settings.html +++ b/src/Umbraco.Web.UI.Client/src/views/macros/views/settings.html @@ -11,7 +11,7 @@ - + +
{{ installedPackage.name }}
- {{ installedPackage.version }} | {{ installedPackage.url }}| {{ installedPackage.author }} + {{ installedPackage.version }} | {{ installedPackage.url }} | {{ installedPackage.author }}