diff --git a/src/Umbraco.Core/Migrations/Upgrade/UmbracoPlan.cs b/src/Umbraco.Core/Migrations/Upgrade/UmbracoPlan.cs index 30f2606bfa..0a67a5726d 100644 --- a/src/Umbraco.Core/Migrations/Upgrade/UmbracoPlan.cs +++ b/src/Umbraco.Core/Migrations/Upgrade/UmbracoPlan.cs @@ -8,6 +8,7 @@ using Umbraco.Core.Migrations.Upgrade.V_8_0_1; using Umbraco.Core.Migrations.Upgrade.V_8_1_0; using Umbraco.Core.Migrations.Upgrade.V_8_6_0; using Umbraco.Core.Migrations.Upgrade.V_8_9_0; +using Umbraco.Core.Migrations.Upgrade.V_8_10_0; namespace Umbraco.Core.Migrations.Upgrade { @@ -197,7 +198,10 @@ namespace Umbraco.Core.Migrations.Upgrade // to 8.9.0 To("{B5838FF5-1D22-4F6C-BCEB-F83ACB14B575}"); - + + // to 8.10.0... + To("{D6A8D863-38EC-44FB-91EC-ACD6A668BD18}"); + //FINAL } } diff --git a/src/Umbraco.Core/Migrations/Upgrade/V_8_10_0/AddPropertyTypeLabelOnTopColumn.cs b/src/Umbraco.Core/Migrations/Upgrade/V_8_10_0/AddPropertyTypeLabelOnTopColumn.cs new file mode 100644 index 0000000000..206ea2be02 --- /dev/null +++ b/src/Umbraco.Core/Migrations/Upgrade/V_8_10_0/AddPropertyTypeLabelOnTopColumn.cs @@ -0,0 +1,20 @@ +using System.Linq; +using Umbraco.Core.Persistence.Dtos; + +namespace Umbraco.Core.Migrations.Upgrade.V_8_10_0 +{ + + public class AddPropertyTypeLabelOnTopColumn : MigrationBase + { + public AddPropertyTypeLabelOnTopColumn(IMigrationContext context) + : base(context) + { } + + public override void Migrate() + { + var columns = SqlSyntax.GetColumnsInSchema(Context.Database).ToList(); + + AddColumnIfNotExists(columns, "labelOnTop"); + } + } +} diff --git a/src/Umbraco.Core/Models/PropertyType.cs b/src/Umbraco.Core/Models/PropertyType.cs index 75c2a7cc00..abdbbfd8db 100644 --- a/src/Umbraco.Core/Models/PropertyType.cs +++ b/src/Umbraco.Core/Models/PropertyType.cs @@ -31,6 +31,7 @@ namespace Umbraco.Core.Models private string _validationRegExp; private string _validationRegExpMessage; private ContentVariation _variations; + private bool _labelOnTop; /// /// Initializes a new instance of the class. @@ -205,6 +206,16 @@ namespace Umbraco.Core.Models set => SetPropertyValueAndDetectChanges(value, ref _mandatoryMessage, nameof(MandatoryMessage)); } + /// + /// Gets or sets a value indicating whether the label of this property type should be displayed on top. + /// + [DataMember] + public bool LabelOnTop + { + get => _labelOnTop; + set => SetPropertyValueAndDetectChanges(value, ref _labelOnTop, nameof(LabelOnTop)); + } + /// /// Gets of sets the sort order of the property type. /// @@ -438,7 +449,7 @@ namespace Umbraco.Core.Models base.PerformDeepClone(clone); var clonedEntity = (PropertyType)clone; - + //need to manually assign the Lazy value as it will not be automatically mapped if (PropertyGroupId != null) { diff --git a/src/Umbraco.Core/Packaging/PackageDataInstallation.cs b/src/Umbraco.Core/Packaging/PackageDataInstallation.cs index 1320f33a50..3553e224cb 100644 --- a/src/Umbraco.Core/Packaging/PackageDataInstallation.cs +++ b/src/Umbraco.Core/Packaging/PackageDataInstallation.cs @@ -800,7 +800,10 @@ namespace Umbraco.Core.Packaging SortOrder = sortOrder, Variations = property.Element("Variations") != null ? (ContentVariation)Enum.Parse(typeof(ContentVariation), property.Element("Variations").Value) - : ContentVariation.Nothing + : ContentVariation.Nothing, + LabelOnTop = property.Element("LabelOnTop") != null + ? property.Element("LabelOnTop").Value.ToLowerInvariant().Equals("true") + : false }; if (property.Element("Key") != null) propertyType.Key = new Guid(property.Element("Key").Value); diff --git a/src/Umbraco.Core/Persistence/Dtos/PropertyTypeDto.cs b/src/Umbraco.Core/Persistence/Dtos/PropertyTypeDto.cs index 3e8d6e7496..572201c94a 100644 --- a/src/Umbraco.Core/Persistence/Dtos/PropertyTypeDto.cs +++ b/src/Umbraco.Core/Persistence/Dtos/PropertyTypeDto.cs @@ -62,6 +62,10 @@ namespace Umbraco.Core.Persistence.Dtos [Length(2000)] public string Description { get; set; } + [Column("labelOnTop")] + [Constraint(Default = "0")] + public bool LabelOnTop { get; set; } + [Column("variations")] [Constraint(Default = "1" /*ContentVariation.InvariantNeutral*/)] public byte Variations { get; set; } diff --git a/src/Umbraco.Core/Persistence/Dtos/PropertyTypeReadOnlyDto.cs b/src/Umbraco.Core/Persistence/Dtos/PropertyTypeReadOnlyDto.cs index 4c352a0134..d2001c00d5 100644 --- a/src/Umbraco.Core/Persistence/Dtos/PropertyTypeReadOnlyDto.cs +++ b/src/Umbraco.Core/Persistence/Dtos/PropertyTypeReadOnlyDto.cs @@ -44,6 +44,9 @@ namespace Umbraco.Core.Persistence.Dtos [Column("Description")] public string Description { get; set; } + [Column("labelOnTop")] + public bool LabelOnTop { get; set; } + /* cmsMemberType */ [Column("memberCanEdit")] public bool CanEdit { get; set; } diff --git a/src/Umbraco.Core/Persistence/Factories/PropertyGroupFactory.cs b/src/Umbraco.Core/Persistence/Factories/PropertyGroupFactory.cs index dc1629e8f7..f139619302 100644 --- a/src/Umbraco.Core/Persistence/Factories/PropertyGroupFactory.cs +++ b/src/Umbraco.Core/Persistence/Factories/PropertyGroupFactory.cs @@ -132,7 +132,8 @@ namespace Umbraco.Core.Persistence.Factories ValidationRegExp = propertyType.ValidationRegExp, ValidationRegExpMessage = propertyType.ValidationRegExpMessage, UniqueId = propertyType.Key, - Variations = (byte)propertyType.Variations + Variations = (byte)propertyType.Variations, + LabelOnTop = propertyType.LabelOnTop }; if (tabId != default) diff --git a/src/Umbraco.Core/Persistence/Mappers/PropertyTypeMapper.cs b/src/Umbraco.Core/Persistence/Mappers/PropertyTypeMapper.cs index 6f22b61f9a..d44618cc96 100644 --- a/src/Umbraco.Core/Persistence/Mappers/PropertyTypeMapper.cs +++ b/src/Umbraco.Core/Persistence/Mappers/PropertyTypeMapper.cs @@ -29,6 +29,7 @@ namespace Umbraco.Core.Persistence.Mappers DefineMap(nameof(PropertyType.SortOrder), nameof(PropertyTypeDto.SortOrder)); DefineMap(nameof(PropertyType.ValidationRegExp), nameof(PropertyTypeDto.ValidationRegExp)); DefineMap(nameof(PropertyType.ValidationRegExpMessage), nameof(PropertyTypeDto.ValidationRegExpMessage)); + DefineMap(nameof(PropertyType.LabelOnTop), nameof(PropertyTypeDto.LabelOnTop)); DefineMap(nameof(PropertyType.PropertyEditorAlias), nameof(DataTypeDto.EditorAlias)); DefineMap(nameof(PropertyType.ValueStorageType), nameof(DataTypeDto.DbType)); } diff --git a/src/Umbraco.Core/Persistence/Repositories/Implement/ContentTypeCommonRepository.cs b/src/Umbraco.Core/Persistence/Repositories/Implement/ContentTypeCommonRepository.cs index 7781e2e38a..90774e4c0b 100644 --- a/src/Umbraco.Core/Persistence/Repositories/Implement/ContentTypeCommonRepository.cs +++ b/src/Umbraco.Core/Persistence/Repositories/Implement/ContentTypeCommonRepository.cs @@ -303,7 +303,8 @@ namespace Umbraco.Core.Persistence.Repositories.Implement SortOrder = dto.SortOrder, ValidationRegExp = dto.ValidationRegExp, ValidationRegExpMessage = dto.ValidationRegExpMessage, - Variations = (ContentVariation)dto.Variations + Variations = (ContentVariation)dto.Variations, + LabelOnTop = dto.LabelOnTop }; } } diff --git a/src/Umbraco.Core/PropertyEditors/DataValueEditor.cs b/src/Umbraco.Core/PropertyEditors/DataValueEditor.cs index c4380f032c..eebe5f5722 100644 --- a/src/Umbraco.Core/PropertyEditors/DataValueEditor.cs +++ b/src/Umbraco.Core/PropertyEditors/DataValueEditor.cs @@ -204,7 +204,7 @@ namespace Umbraco.Core.PropertyEditors /// /// /// By default this will attempt to automatically convert the string value to the value type supplied by ValueType. - /// + /// /// If overridden then the object returned must match the type supplied in the ValueType, otherwise persisting the /// value to the DB will fail when it tries to validate the value type. /// diff --git a/src/Umbraco.Core/Services/Implement/EntityXmlSerializer.cs b/src/Umbraco.Core/Services/Implement/EntityXmlSerializer.cs index 76c0a631ba..4d7694d1b8 100644 --- a/src/Umbraco.Core/Services/Implement/EntityXmlSerializer.cs +++ b/src/Umbraco.Core/Services/Implement/EntityXmlSerializer.cs @@ -363,6 +363,7 @@ namespace Umbraco.Core.Services.Implement new XElement("MandatoryMessage", propertyType.MandatoryMessage), new XElement("Validation", propertyType.ValidationRegExp), new XElement("ValidationRegExpMessage", propertyType.ValidationRegExpMessage), + new XElement("LabelOnTop", propertyType.LabelOnTop), new XElement("Description", new XCData(propertyType.Description))); genericProperties.Add(genericProperty); } @@ -491,6 +492,7 @@ namespace Umbraco.Core.Services.Implement new XElement("Tab", propertyGroup == null ? "" : propertyGroup.Name), new XElement("SortOrder", propertyType.SortOrder), new XElement("Mandatory", propertyType.Mandatory.ToString()), + new XElement("LabelOnTop", propertyType.LabelOnTop.ToString()), propertyType.MandatoryMessage != null ? new XElement("MandatoryMessage", propertyType.MandatoryMessage) : null, propertyType.ValidationRegExp != null ? new XElement("Validation", propertyType.ValidationRegExp) : null, propertyType.ValidationRegExpMessage != null ? new XElement("ValidationRegExpMessage", propertyType.ValidationRegExpMessage) : null, diff --git a/src/Umbraco.Core/Umbraco.Core.csproj b/src/Umbraco.Core/Umbraco.Core.csproj index 04ae182b46..685e5a5165 100755 --- a/src/Umbraco.Core/Umbraco.Core.csproj +++ b/src/Umbraco.Core/Umbraco.Core.csproj @@ -132,6 +132,7 @@ + diff --git a/src/Umbraco.Tests/Models/Mapping/ContentTypeModelMappingTests.cs b/src/Umbraco.Tests/Models/Mapping/ContentTypeModelMappingTests.cs index eee7446823..1480253958 100644 --- a/src/Umbraco.Tests/Models/Mapping/ContentTypeModelMappingTests.cs +++ b/src/Umbraco.Tests/Models/Mapping/ContentTypeModelMappingTests.cs @@ -215,6 +215,7 @@ namespace Umbraco.Tests.Models.Mapping { Assert.AreEqual(propTypes.ElementAt(j).Id, result.PropertyTypes.ElementAt(j).Id); Assert.AreEqual(propTypes.ElementAt(j).DataTypeId, result.PropertyTypes.ElementAt(j).DataTypeId); + Assert.AreEqual(propTypes.ElementAt(j).LabelOnTop, result.PropertyTypes.ElementAt(j).LabelOnTop); } } @@ -449,6 +450,7 @@ namespace Umbraco.Tests.Models.Mapping { Assert.AreEqual(propTypes[j].Id, result.Groups.ElementAt(i).Properties.ElementAt(j).Id); Assert.AreEqual(propTypes[j].DataTypeId, result.Groups.ElementAt(i).Properties.ElementAt(j).DataTypeId); + Assert.AreEqual(propTypes[j].LabelOnTop, result.Groups.ElementAt(i).Properties.ElementAt(j).LabelOnTop); } } @@ -639,6 +641,7 @@ namespace Umbraco.Tests.Models.Mapping Assert.AreEqual(basic.Validation.MandatoryMessage, result.MandatoryMessage); Assert.AreEqual(basic.Validation.Pattern, result.ValidationRegExp); Assert.AreEqual(basic.Validation.PatternMessage, result.ValidationRegExpMessage); + Assert.AreEqual(basic.LabelOnTop, result.LabelOnTop); } [Test] @@ -677,6 +680,7 @@ namespace Umbraco.Tests.Models.Mapping Assert.AreEqual(basic.Validation.MandatoryMessage, result.MandatoryMessage); Assert.AreEqual(basic.Validation.Pattern, result.ValidationRegExp); Assert.AreEqual(basic.Validation.PatternMessage, result.ValidationRegExpMessage); + Assert.AreEqual(basic.LabelOnTop, result.LabelOnTop); } [Test] @@ -1074,7 +1078,8 @@ namespace Umbraco.Tests.Models.Mapping Pattern = string.Empty }, SortOrder = 0, - DataTypeId = 555 + DataTypeId = 555, + LabelOnTop = true } } } @@ -1120,7 +1125,8 @@ namespace Umbraco.Tests.Models.Mapping Pattern = string.Empty }, SortOrder = 0, - DataTypeId = 555 + DataTypeId = 555, + LabelOnTop = true } } }, @@ -1144,7 +1150,8 @@ namespace Umbraco.Tests.Models.Mapping Pattern = string.Empty }, SortOrder = 0, - DataTypeId = 555 + DataTypeId = 555, + LabelOnTop = false } } @@ -1198,7 +1205,8 @@ namespace Umbraco.Tests.Models.Mapping Pattern = string.Empty }, SortOrder = 0, - DataTypeId = 555 + DataTypeId = 555, + LabelOnTop = true } } }, @@ -1222,7 +1230,8 @@ namespace Umbraco.Tests.Models.Mapping Pattern = string.Empty }, SortOrder = 0, - DataTypeId = 555 + DataTypeId = 555, + LabelOnTop = false } } diff --git a/src/Umbraco.Tests/Persistence/Repositories/ContentTypeRepositoryTest.cs b/src/Umbraco.Tests/Persistence/Repositories/ContentTypeRepositoryTest.cs index e592c5171a..e8fc94e962 100644 --- a/src/Umbraco.Tests/Persistence/Repositories/ContentTypeRepositoryTest.cs +++ b/src/Umbraco.Tests/Persistence/Repositories/ContentTypeRepositoryTest.cs @@ -348,6 +348,7 @@ namespace Umbraco.Tests.Persistence.Repositories Assert.That(contentType.Path.Contains(","), Is.True); Assert.That(contentType.SortOrder, Is.GreaterThan(0)); + Assert.That(contentType.PropertyGroups.ElementAt(0).Name == "testGroup", Is.True); var groupId = contentType.PropertyGroups.ElementAt(0).Id; @@ -355,6 +356,7 @@ namespace Umbraco.Tests.Persistence.Repositories Assert.AreEqual("gen", propertyTypes[0].Alias); // just to be sure Assert.IsNull(propertyTypes[0].PropertyGroupId); Assert.IsTrue(propertyTypes.Skip(1).All((x => x.PropertyGroupId.Value == groupId))); + Assert.That(propertyTypes.Single(x=> x.Alias == "title").LabelOnTop, Is.True); } } @@ -377,7 +379,8 @@ namespace Umbraco.Tests.Persistence.Repositories Description = "Optional Subtitle", Mandatory = false, SortOrder = 1, - DataTypeId = -88 + DataTypeId = -88, + LabelOnTop = true }); repository.Save(contentType); @@ -389,6 +392,8 @@ namespace Umbraco.Tests.Persistence.Repositories Assert.That(dirty, Is.False); Assert.That(contentType.Thumbnail, Is.EqualTo("Doc2.png")); Assert.That(contentType.PropertyTypes.Any(x => x.Alias == "subtitle"), Is.True); + Assert.That(contentType.PropertyTypes.Single(x => x.Alias == "subtitle").LabelOnTop, Is.True); + } @@ -467,7 +472,8 @@ namespace Umbraco.Tests.Persistence.Repositories Pattern = "" }, SortOrder = 1, - DataTypeId = -88 + DataTypeId = -88, + LabelOnTop = true } }); @@ -476,6 +482,7 @@ namespace Umbraco.Tests.Persistence.Repositories // just making sure Assert.AreEqual(mapped.Thumbnail, "Doc2.png"); Assert.IsTrue(mapped.PropertyTypes.Any(x => x.Alias == "subtitle")); + Assert.IsTrue(mapped.PropertyTypes.Single(x => x.Alias == "subtitle").LabelOnTop); repository.Save(mapped); @@ -490,6 +497,9 @@ namespace Umbraco.Tests.Persistence.Repositories Assert.That(dirty, Is.False); Assert.That(contentType.Thumbnail, Is.EqualTo("Doc2.png")); Assert.That(contentType.PropertyTypes.Any(x => x.Alias == "subtitle"), Is.True); + + Assert.That(contentType.PropertyTypes.Single(x => x.Alias == "subtitle").LabelOnTop, Is.True); + foreach (var propertyType in contentType.PropertyTypes) { Assert.IsTrue(propertyType.HasIdentity); diff --git a/src/Umbraco.Tests/TestHelpers/Entities/MockedContentTypes.cs b/src/Umbraco.Tests/TestHelpers/Entities/MockedContentTypes.cs index b4cd4ab05e..e3bb012dae 100644 --- a/src/Umbraco.Tests/TestHelpers/Entities/MockedContentTypes.cs +++ b/src/Umbraco.Tests/TestHelpers/Entities/MockedContentTypes.cs @@ -41,8 +41,8 @@ namespace Umbraco.Tests.TestHelpers.Entities }; var contentCollection = new PropertyTypeCollection(true); - contentCollection.Add(new PropertyType("test", ValueStorageType.Ntext) { Alias = "title", Name = "Title", Description = "", Mandatory = false, SortOrder = 1, DataTypeId = Constants.DataTypes.Textbox }); - contentCollection.Add(new PropertyType("test", ValueStorageType.Ntext) { Alias = "bodyText", Name = "Body Text", Description = "", Mandatory = false, SortOrder = 2, DataTypeId = Constants.DataTypes.RichtextEditor }); + contentCollection.Add(new PropertyType("test", ValueStorageType.Ntext) { Alias = "title", Name = "Title", Description = "", Mandatory = false, SortOrder = 1, DataTypeId = Constants.DataTypes.Textbox, LabelOnTop = true }); + contentCollection.Add(new PropertyType("test", ValueStorageType.Ntext) { Alias = "bodyText", Name = "Body Text", Description = "", Mandatory = false, SortOrder = 2, DataTypeId = Constants.DataTypes.RichtextEditor, LabelOnTop = false }); var metaCollection = new PropertyTypeCollection(true); metaCollection.Add(new PropertyType("test", ValueStorageType.Ntext) { Alias = "keywords", Name = "Meta Keywords", Description = "", Mandatory = false, SortOrder = 1, DataTypeId = Constants.DataTypes.Textbox }); @@ -213,7 +213,7 @@ namespace Umbraco.Tests.TestHelpers.Entities contentType.Trashed = false; var contentCollection = new PropertyTypeCollection(true); - contentCollection.Add(new PropertyType(Constants.PropertyEditors.Aliases.TextBox, ValueStorageType.Ntext) { Alias = RandomAlias("title", randomizeAliases), Name = "Title", Description = "", Mandatory = false, SortOrder = 1, DataTypeId = -88 }); + contentCollection.Add(new PropertyType(Constants.PropertyEditors.Aliases.TextBox, ValueStorageType.Ntext) { Alias = RandomAlias("title", randomizeAliases), Name = "Title", Description = "", Mandatory = false, SortOrder = 1, DataTypeId = -88, LabelOnTop = true }); contentCollection.Add(new PropertyType(Constants.PropertyEditors.Aliases.TinyMce, ValueStorageType.Ntext) { Alias = RandomAlias("bodyText", randomizeAliases), Name = "Body Text", Description = "", Mandatory = false, SortOrder = 2, DataTypeId = -87 }); contentCollection.Add(new PropertyType(Constants.PropertyEditors.Aliases.TextBox, ValueStorageType.Ntext) { Alias = RandomAlias("author", randomizeAliases) , Name = "Author", Description = "Name of the author", Mandatory = false, SortOrder = 3, DataTypeId = -88 }); diff --git a/src/Umbraco.Web.UI.Client/src/common/directives/components/umbgroupsbuilder.directive.js b/src/Umbraco.Web.UI.Client/src/common/directives/components/umbgroupsbuilder.directive.js index 92d2df43e5..06e1c61f1e 100644 --- a/src/Umbraco.Web.UI.Client/src/common/directives/components/umbgroupsbuilder.directive.js +++ b/src/Umbraco.Web.UI.Client/src/common/directives/components/umbgroupsbuilder.directive.js @@ -323,12 +323,12 @@ filterAvailableCompositions(selectedContentType, newSelection).then(function () { deferred.resolve({ selectedContentType, newSelection }); // TODO: Here we could probably re-enable selection if we previously showed a throbber or something - }, function () { + }, function () { deferred.reject(); }); } - return deferred.promise; + return deferred.promise; } }; @@ -353,7 +353,7 @@ }), //get where used document types whereUsedContentTypeResource(scope.model.id).then(function (whereUsed) { - //pass to the dialog model the content type eg documentType or mediaType + //pass to the dialog model the content type eg documentType or mediaType scope.compositionsDialogModel.section = scope.contentType; //pass the list of 'where used' document types scope.compositionsDialogModel.whereCompositionUsed = whereUsed; @@ -566,6 +566,7 @@ property.isSensitiveValue = propertyModel.isSensitiveValue; property.allowCultureVariant = propertyModel.allowCultureVariant; property.allowSegmentVariant = propertyModel.allowSegmentVariant; + property.labelOnTop = propertyModel.labelOnTop; // update existing data types if (model.updateSameDataTypes) { @@ -647,7 +648,8 @@ mandatoryMessage: null, pattern: null, patternMessage: null - } + }, + labelOnTop: false }; // check if there already is an init property diff --git a/src/Umbraco.Web.UI.Client/src/common/services/umbdataformatter.service.js b/src/Umbraco.Web.UI.Client/src/common/services/umbdataformatter.service.js index 109fff0919..c646c4833f 100644 --- a/src/Umbraco.Web.UI.Client/src/common/services/umbdataformatter.service.js +++ b/src/Umbraco.Web.UI.Client/src/common/services/umbdataformatter.service.js @@ -83,7 +83,7 @@ }); var saveProperties = _.map(realProperties, function (p) { - var saveProperty = _.pick(p, 'id', 'alias', 'description', 'validation', 'label', 'sortOrder', 'dataTypeId', 'groupId', 'memberCanEdit', 'showOnMemberProfile', 'isSensitiveData', 'allowCultureVariant', 'allowSegmentVariant'); + var saveProperty = _.pick(p, 'id', 'alias', 'description', 'validation', 'label', 'sortOrder', 'dataTypeId', 'groupId', 'memberCanEdit', 'showOnMemberProfile', 'isSensitiveData', 'allowCultureVariant', 'allowSegmentVariant', 'labelOnTop'); return saveProperty; }); @@ -404,7 +404,7 @@ if (displayModel.variants && displayModel.variants.length > 1) { // Collect all invariant properties from the variants that are either the // default language variant or the default segment variant. - var defaultVariants = _.filter(displayModel.variants, function (variant) { + var defaultVariants = _.filter(displayModel.variants, function (variant) { var isDefaultLanguage = variant.language && variant.language.isDefault; var isDefaultSegment = variant.segment == null; @@ -433,7 +433,7 @@ return variant !== defaultVariant; }); - // now assign this same invariant property instance to the same index of the other variants property array + // now assign this same invariant property instance to the same index of the other variants property array _.each(otherVariants, function (variant) { _.each(invariantProps, function (invProp) { var tab = variant.tabs[invProp.tabIndex]; diff --git a/src/Umbraco.Web.UI.Client/src/less/main.less b/src/Umbraco.Web.UI.Client/src/less/main.less index e1e368f2e2..7c5ed4c9bb 100644 --- a/src/Umbraco.Web.UI.Client/src/less/main.less +++ b/src/Umbraco.Web.UI.Client/src/less/main.less @@ -228,6 +228,7 @@ umb-property:last-of-type .umb-control-group { padding-top: 5px; padding-bottom: 0; text-align: left; + margin-bottom: 5px; .control-label { width: auto; @@ -237,7 +238,7 @@ umb-property:last-of-type .umb-control-group { .control-description { max-width:480px;// avoiding description becoming too wide when its placed on top of property. - margin-bottom: 10px; + margin-bottom: 5px; } } @media (max-width: 767px) { @@ -245,9 +246,27 @@ umb-property:last-of-type .umb-control-group { .form-horizontal .umb-control-group .control-header { float: none; width: 100%; + &::after { + content: ""; + display: table; + clear: both; + } } - +} +.form-horizontal .umb-control-group.--label-on-top > .umb-el-wrap { + & > .control-header { + float: none; + width: 100%; + &::after { + content: ""; + display: table; + clear: both; + } + } + & > .controls { + margin-left: 0; + } } /* LABELS*/ diff --git a/src/Umbraco.Web.UI.Client/src/views/common/infiniteeditors/propertysettings/propertysettings.controller.js b/src/Umbraco.Web.UI.Client/src/views/common/infiniteeditors/propertysettings/propertysettings.controller.js index 6310545b20..3c09745f15 100644 --- a/src/Umbraco.Web.UI.Client/src/views/common/infiniteeditors/propertysettings/propertysettings.controller.js +++ b/src/Umbraco.Web.UI.Client/src/views/common/infiniteeditors/propertysettings/propertysettings.controller.js @@ -35,6 +35,7 @@ vm.toggleShowOnMemberProfile = toggleShowOnMemberProfile; vm.toggleMemberCanEdit = toggleMemberCanEdit; vm.toggleIsSensitiveData = toggleIsSensitiveData; + vm.toggleLabelOnTop = toggleLabelOnTop; function onInit() { @@ -42,23 +43,24 @@ vm.showSensitiveData = user.userGroups.indexOf("sensitiveData") != -1; }); - //make the default the same as the content type + //make the default the same as the content type if (!$scope.model.property.dataTypeId) { $scope.model.property.allowCultureVariant = $scope.model.contentTypeAllowCultureVariant; } - + loadValidationTypes(); - + } function loadValidationTypes() { var labels = [ - "validation_validateAsEmail", - "validation_validateAsNumber", - "validation_validateAsUrl", + "validation_validateAsEmail", + "validation_validateAsNumber", + "validation_validateAsUrl", "validation_enterCustomValidation", - "validation_fieldIsMandatory" + "validation_fieldIsMandatory", + "contentTypeEditor_displaySettingsLabelOnTop" ]; localizationService.localizeMany(labels) @@ -69,6 +71,7 @@ vm.labels.validateAsUrl = data[2]; vm.labels.customValidation = data[3]; vm.labels.fieldIsMandatory = data[4]; + vm.labels.displaySettingsLabelOnTop = data[5]; vm.validationTypes = [ { @@ -121,7 +124,7 @@ $scope.model.updateSameDataTypes = model.updateSameDataTypes; vm.focusOnMandatoryField = true; - + // update property property.config = model.property.config; property.editor = model.property.editor; @@ -179,7 +182,7 @@ if(event && event.keyCode === 13) { submit(); } - } + } function submit() { if($scope.model.submit) { @@ -245,28 +248,31 @@ return !settingValue; } - function toggleAllowCultureVariants() { + function toggleAllowCultureVariants() { $scope.model.property.allowCultureVariant = toggleValue($scope.model.property.allowCultureVariant); } - function toggleAllowSegmentVariants() { + function toggleAllowSegmentVariants() { $scope.model.property.allowSegmentVariant = toggleValue($scope.model.property.allowSegmentVariant); } function toggleValidation() { - $scope.model.property.validation.mandatory = toggleValue($scope.model.property.validation.mandatory); + $scope.model.property.validation.mandatory = toggleValue($scope.model.property.validation.mandatory); } function toggleShowOnMemberProfile() { - $scope.model.property.showOnMemberProfile = toggleValue($scope.model.property.showOnMemberProfile); + $scope.model.property.showOnMemberProfile = toggleValue($scope.model.property.showOnMemberProfile); } function toggleMemberCanEdit() { - $scope.model.property.memberCanEdit = toggleValue($scope.model.property.memberCanEdit); + $scope.model.property.memberCanEdit = toggleValue($scope.model.property.memberCanEdit); } function toggleIsSensitiveData() { - $scope.model.property.isSensitiveData = toggleValue($scope.model.property.isSensitiveData); + $scope.model.property.isSensitiveData = toggleValue($scope.model.property.isSensitiveData); + } + function toggleLabelOnTop() { + $scope.model.property.labelOnTop = toggleValue($scope.model.property.labelOnTop); } onInit(); diff --git a/src/Umbraco.Web.UI.Client/src/views/common/infiniteeditors/propertysettings/propertysettings.html b/src/Umbraco.Web.UI.Client/src/views/common/infiniteeditors/propertysettings/propertysettings.html index af9295f1ed..482345c3b3 100644 --- a/src/Umbraco.Web.UI.Client/src/views/common/infiniteeditors/propertysettings/propertysettings.html +++ b/src/Umbraco.Web.UI.Client/src/views/common/infiniteeditors/propertysettings/propertysettings.html @@ -135,6 +135,21 @@ ng-if="vm.showValidationPattern" ng-keypress="vm.submitOnEnter($event)" /> + +
+ +
+ + + +
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 dff62ee1eb..5b8e6d8f04 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,7 +1,7 @@
+ ng-class="{'hidelabel':vm.property.hideLabel, '--label-on-top':vm.property.labelOnTop, 'umb-control-group__listview': vm.property.alias === '_umb_containerView'}"> diff --git a/src/Umbraco.Web.UI/Umbraco/config/lang/da.xml b/src/Umbraco.Web.UI/Umbraco/config/lang/da.xml index d7597d2c87..35279a75f3 100644 --- a/src/Umbraco.Web.UI/Umbraco/config/lang/da.xml +++ b/src/Umbraco.Web.UI/Umbraco/config/lang/da.xml @@ -1438,6 +1438,8 @@ Mange hilsner fra Umbraco robotten En Element-type er tiltænkt brug i f.eks. Nested Content, ikke i indholdstræet. Dette benyttes ikke for en Element-type Du har lavet ændringer til denne egenskab. Er du sikker på at du vil kassere dem? + Visning + Flyt label over editoren Tilføj sprog diff --git a/src/Umbraco.Web.UI/Umbraco/config/lang/en.xml b/src/Umbraco.Web.UI/Umbraco/config/lang/en.xml index a7f4e6f3f9..3c864e2d66 100644 --- a/src/Umbraco.Web.UI/Umbraco/config/lang/en.xml +++ b/src/Umbraco.Web.UI/Umbraco/config/lang/en.xml @@ -1696,6 +1696,8 @@ To manage your website, simply open the Umbraco back office and start adding con A document type cannot be changed to an Element type once it has been used to create one or more content items. This is not applicable for an Element type You have made changes to this property. Are you sure you want to discard them? + Appearance + Display label on top of editor. Add language 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 93a4879739..a5144bf450 100644 --- a/src/Umbraco.Web.UI/Umbraco/config/lang/en_us.xml +++ b/src/Umbraco.Web.UI/Umbraco/config/lang/en_us.xml @@ -1716,6 +1716,8 @@ To manage your website, simply open the Umbraco back office and start adding con A document type cannot be changed to an element type once it has been used to create one or more content items. This is not applicable for an element type You have made changes to this property. Are you sure you want to discard them? + Appearance + Display label on top of editor. Add language diff --git a/src/Umbraco.Web/Models/ContentEditing/ContentPropertyDisplay.cs b/src/Umbraco.Web/Models/ContentEditing/ContentPropertyDisplay.cs index 39a4718dd0..9a07d29a02 100644 --- a/src/Umbraco.Web/Models/ContentEditing/ContentPropertyDisplay.cs +++ b/src/Umbraco.Web/Models/ContentEditing/ContentPropertyDisplay.cs @@ -33,6 +33,9 @@ namespace Umbraco.Web.Models.ContentEditing [DataMember(Name = "hideLabel")] public bool HideLabel { get; set; } + [DataMember(Name = "labelOnTop")] + public bool LabelOnTop { get; set; } + [DataMember(Name = "validation")] public PropertyTypeValidation Validation { get; set; } diff --git a/src/Umbraco.Web/Models/ContentEditing/ContentPropertyDto.cs b/src/Umbraco.Web/Models/ContentEditing/ContentPropertyDto.cs index 83e5e2a9b2..9702202294 100644 --- a/src/Umbraco.Web/Models/ContentEditing/ContentPropertyDto.cs +++ b/src/Umbraco.Web/Models/ContentEditing/ContentPropertyDto.cs @@ -18,6 +18,8 @@ namespace Umbraco.Web.Models.ContentEditing public bool IsRequired { get; set; } + public bool LabelOnTop { get; set; } + public string IsRequiredMessage { get; set; } public string ValidationRegExp { get; set; } diff --git a/src/Umbraco.Web/Models/ContentEditing/PropertyTypeBasic.cs b/src/Umbraco.Web/Models/ContentEditing/PropertyTypeBasic.cs index 4252a29567..793e4e391d 100644 --- a/src/Umbraco.Web/Models/ContentEditing/PropertyTypeBasic.cs +++ b/src/Umbraco.Web/Models/ContentEditing/PropertyTypeBasic.cs @@ -65,5 +65,8 @@ namespace Umbraco.Web.Models.ContentEditing [DataMember(Name = "allowSegmentVariant")] public bool AllowSegmentVariant { get; set; } + + [DataMember(Name = "labelOnTop")] + public bool LabelOnTop { get; set; } } } diff --git a/src/Umbraco.Web/Models/Mapping/ContentPropertyDisplayMapper.cs b/src/Umbraco.Web/Models/Mapping/ContentPropertyDisplayMapper.cs index d81f81abe2..37fd2b2e28 100644 --- a/src/Umbraco.Web/Models/Mapping/ContentPropertyDisplayMapper.cs +++ b/src/Umbraco.Web/Models/Mapping/ContentPropertyDisplayMapper.cs @@ -39,6 +39,7 @@ namespace Umbraco.Web.Models.Mapping dest.Description = originalProp.PropertyType.Description; dest.Label = originalProp.PropertyType.Name; dest.HideLabel = valEditor.HideLabel; + dest.LabelOnTop = originalProp.PropertyType.LabelOnTop; //add the validation information dest.Validation.Mandatory = originalProp.PropertyType.Mandatory; diff --git a/src/Umbraco.Web/Models/Mapping/ContentPropertyDtoMapper.cs b/src/Umbraco.Web/Models/Mapping/ContentPropertyDtoMapper.cs index fd57e4dd2e..64e2ea22a3 100644 --- a/src/Umbraco.Web/Models/Mapping/ContentPropertyDtoMapper.cs +++ b/src/Umbraco.Web/Models/Mapping/ContentPropertyDtoMapper.cs @@ -27,6 +27,7 @@ namespace Umbraco.Web.Models.Mapping dest.Description = property.PropertyType.Description; dest.Label = property.PropertyType.Name; dest.DataType = DataTypeService.GetDataType(property.PropertyType.DataTypeId); + dest.LabelOnTop = property.PropertyType.LabelOnTop; } } } diff --git a/src/Umbraco.Web/Models/Mapping/ContentPropertyMapDefinition.cs b/src/Umbraco.Web/Models/Mapping/ContentPropertyMapDefinition.cs index e6290cc19e..baa9b7be69 100644 --- a/src/Umbraco.Web/Models/Mapping/ContentPropertyMapDefinition.cs +++ b/src/Umbraco.Web/Models/Mapping/ContentPropertyMapDefinition.cs @@ -38,7 +38,7 @@ namespace Umbraco.Web.Models.Mapping target.Id = source.Id; target.IsActive = true; target.Label = source.Name; -} + } private void Map(Property source, ContentPropertyBasic target, MapperContext context) { diff --git a/src/Umbraco.Web/Models/Mapping/ContentTypeMapDefinition.cs b/src/Umbraco.Web/Models/Mapping/ContentTypeMapDefinition.cs index b0d4c6b2e0..f67a5df56c 100644 --- a/src/Umbraco.Web/Models/Mapping/ContentTypeMapDefinition.cs +++ b/src/Umbraco.Web/Models/Mapping/ContentTypeMapDefinition.cs @@ -242,6 +242,7 @@ namespace Umbraco.Web.Models.Mapping target.Alias = source.Alias; target.Description = source.Description; target.SortOrder = source.SortOrder; + target.LabelOnTop = source.LabelOnTop; } // no MapAll - take care @@ -353,6 +354,7 @@ namespace Umbraco.Web.Models.Mapping target.Label = source.Label; target.SortOrder = source.SortOrder; target.Validation = source.Validation; + target.LabelOnTop = source.LabelOnTop; } // Umbraco.Code.MapAll -Editor -View -Config -ContentTypeId -ContentTypeName -Locked -DataTypeIcon -DataTypeName @@ -373,6 +375,7 @@ namespace Umbraco.Web.Models.Mapping target.MemberCanViewProperty = source.MemberCanViewProperty; target.SortOrder = source.SortOrder; target.Validation = source.Validation; + target.LabelOnTop = source.LabelOnTop; } // Umbraco.Code.MapAll -CreatorId -Level -SortOrder -Variations diff --git a/src/Umbraco.Web/Models/Mapping/PropertyTypeGroupMapper.cs b/src/Umbraco.Web/Models/Mapping/PropertyTypeGroupMapper.cs index adee6c6928..33fce221b4 100644 --- a/src/Umbraco.Web/Models/Mapping/PropertyTypeGroupMapper.cs +++ b/src/Umbraco.Web/Models/Mapping/PropertyTypeGroupMapper.cs @@ -222,6 +222,7 @@ namespace Umbraco.Web.Models.Mapping Id = p.Id, Alias = p.Alias, Description = p.Description, + LabelOnTop = p.LabelOnTop, Editor = p.PropertyEditorAlias, Validation = new PropertyTypeValidation { diff --git a/src/Umbraco.Web/PropertyEditors/BlockEditorPropertyEditor.cs b/src/Umbraco.Web/PropertyEditors/BlockEditorPropertyEditor.cs index 18ea3e1e9d..8c4ebf49c3 100644 --- a/src/Umbraco.Web/PropertyEditors/BlockEditorPropertyEditor.cs +++ b/src/Umbraco.Web/PropertyEditors/BlockEditorPropertyEditor.cs @@ -46,7 +46,7 @@ namespace Umbraco.Web.PropertyEditors internal class BlockEditorPropertyValueEditor : DataValueEditor, IDataValueReference { private readonly PropertyEditorCollection _propertyEditors; - private readonly IDataTypeService _dataTypeService; + private readonly IDataTypeService _dataTypeService; private readonly ILogger _logger; private readonly BlockEditorValues _blockEditorValues;