From dc2de4b5e7ba913d31cebb477b04fde488af097a Mon Sep 17 00:00:00 2001 From: Floris Robbemont Date: Wed, 7 Aug 2013 15:06:41 +0200 Subject: [PATCH 01/10] U4-2596: UmbracoControllerFactory method ReleaseController should be virtual --- src/Umbraco.Web/Mvc/UmbracoControllerFactory.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Umbraco.Web/Mvc/UmbracoControllerFactory.cs b/src/Umbraco.Web/Mvc/UmbracoControllerFactory.cs index 63eaaa5e9a..02ff701c8b 100644 --- a/src/Umbraco.Web/Mvc/UmbracoControllerFactory.cs +++ b/src/Umbraco.Web/Mvc/UmbracoControllerFactory.cs @@ -54,7 +54,7 @@ namespace Umbraco.Web.Mvc /// Releases the specified controller. /// /// The controller. - public void ReleaseController(IController controller) + public virtual void ReleaseController(IController controller) { _innerFactory.ReleaseController(controller); } From 89ff7d85e2336a7be4c6c39f8a07e09bf6174beb Mon Sep 17 00:00:00 2001 From: Morten Christensen Date: Fri, 9 Aug 2013 17:44:57 +0200 Subject: [PATCH 02/10] Correcting DELETE FROM query so it works with sql ce as well. --- .../Persistence/Repositories/RecycleBinRepository.cs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/Umbraco.Core/Persistence/Repositories/RecycleBinRepository.cs b/src/Umbraco.Core/Persistence/Repositories/RecycleBinRepository.cs index c62a1c71f6..2c797416ef 100644 --- a/src/Umbraco.Core/Persistence/Repositories/RecycleBinRepository.cs +++ b/src/Umbraco.Core/Persistence/Repositories/RecycleBinRepository.cs @@ -116,9 +116,12 @@ namespace Umbraco.Core.Persistence.Repositories private string FormatDeleteStatement(string tableName, string keyName) { + //This query works with sql ce and sql server: + //DELETE FROM umbracoUser2NodeNotify WHERE umbracoUser2NodeNotify.nodeId IN + //(SELECT nodeId FROM umbracoUser2NodeNotify as TB1 INNER JOIN umbracoNode as TB2 ON TB1.nodeId = TB2.id WHERE TB2.trashed = '1' AND TB2.nodeObjectType = 'C66BA18E-EAF3-4CFF-8A22-41B16D66A972') return string.Format( - "DELETE FROM {0} FROM {0} as TB1 INNER JOIN umbracoNode as TB2 ON TB1.{1} = TB2.id WHERE TB2.trashed = '1' AND TB2.nodeObjectType = @NodeObjectType", + "DELETE FROM {0} WHERE {0}.{1} IN (SELECT TB1.{1} FROM {0} as TB1 INNER JOIN umbracoNode as TB2 ON TB1.{1} = TB2.id WHERE TB2.trashed = '1' AND TB2.nodeObjectType = @NodeObjectType)", tableName, keyName); } From 30e12c1367357ac05bb7b265b0f4d8e71ed3b47d Mon Sep 17 00:00:00 2001 From: Morten Christensen Date: Sun, 11 Aug 2013 21:12:02 +0200 Subject: [PATCH 03/10] Final piece to the puzzle for U4-2571 Need to optimize empty recycle bin. Needed to hack around the ordering of items in the recycle bin because of the self-referencing constraint - parentID to id in the umbracoNode table by updating all parentID entries, which bypasses any reference issues with the foreignkey. --- .../Persistence/Repositories/RecycleBinRepository.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/Umbraco.Core/Persistence/Repositories/RecycleBinRepository.cs b/src/Umbraco.Core/Persistence/Repositories/RecycleBinRepository.cs index 2c797416ef..febfb937b0 100644 --- a/src/Umbraco.Core/Persistence/Repositories/RecycleBinRepository.cs +++ b/src/Umbraco.Core/Persistence/Repositories/RecycleBinRepository.cs @@ -56,6 +56,7 @@ namespace Umbraco.Core.Persistence.Repositories FormatDeleteStatement("cmsContentVersion", "ContentId"), FormatDeleteStatement("cmsContentXml", "nodeID"), FormatDeleteStatement("cmsContent", "NodeId"), + "UPDATE umbracoNode SET parentID = '-20' WHERE trashed = '1' AND nodeObjectType = @NodeObjectType", "DELETE FROM umbracoNode WHERE trashed = '1' AND nodeObjectType = @NodeObjectType" }; From c7f8a65a43d18da730e303f47caa2ab17d6ebf08 Mon Sep 17 00:00:00 2001 From: Shannon Date: Mon, 12 Aug 2013 11:36:11 +1000 Subject: [PATCH 04/10] removes the space from 'property editors' folder, removes file commits to App_Plugins in the UI proj. --- .../mntp/mntp.html | 0 .../mntp/mntp.js | 0 .../package.manifest | 4 +- .../relatedlinks/relatedlinks.html | 0 .../relatedlinks/relatedlinks.js | 0 .../property editors/mntp/mntp.html | 18 -------- .../App_Plugins/property editors/mntp/mntp.js | 42 ------------------- .../property editors/package.manifest | 30 ------------- 8 files changed, 2 insertions(+), 92 deletions(-) rename src/Umbraco.Web.UI.Client/src/packages/{property editors => propertyeditors}/mntp/mntp.html (100%) rename src/Umbraco.Web.UI.Client/src/packages/{property editors => propertyeditors}/mntp/mntp.js (100%) rename src/Umbraco.Web.UI.Client/src/packages/{property editors => propertyeditors}/package.manifest (82%) rename src/Umbraco.Web.UI.Client/src/packages/{property editors => propertyeditors}/relatedlinks/relatedlinks.html (100%) rename src/Umbraco.Web.UI.Client/src/packages/{property editors => propertyeditors}/relatedlinks/relatedlinks.js (100%) delete mode 100644 src/Umbraco.Web.UI/App_Plugins/property editors/mntp/mntp.html delete mode 100644 src/Umbraco.Web.UI/App_Plugins/property editors/mntp/mntp.js delete mode 100644 src/Umbraco.Web.UI/App_Plugins/property editors/package.manifest diff --git a/src/Umbraco.Web.UI.Client/src/packages/property editors/mntp/mntp.html b/src/Umbraco.Web.UI.Client/src/packages/propertyeditors/mntp/mntp.html similarity index 100% rename from src/Umbraco.Web.UI.Client/src/packages/property editors/mntp/mntp.html rename to src/Umbraco.Web.UI.Client/src/packages/propertyeditors/mntp/mntp.html diff --git a/src/Umbraco.Web.UI.Client/src/packages/property editors/mntp/mntp.js b/src/Umbraco.Web.UI.Client/src/packages/propertyeditors/mntp/mntp.js similarity index 100% rename from src/Umbraco.Web.UI.Client/src/packages/property editors/mntp/mntp.js rename to src/Umbraco.Web.UI.Client/src/packages/propertyeditors/mntp/mntp.js diff --git a/src/Umbraco.Web.UI.Client/src/packages/property editors/package.manifest b/src/Umbraco.Web.UI.Client/src/packages/propertyeditors/package.manifest similarity index 82% rename from src/Umbraco.Web.UI.Client/src/packages/property editors/package.manifest rename to src/Umbraco.Web.UI.Client/src/packages/propertyeditors/package.manifest index dcfbe80dc9..016ab2923b 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/property editors/package.manifest +++ b/src/Umbraco.Web.UI.Client/src/packages/propertyeditors/package.manifest @@ -24,7 +24,7 @@ ] , javascript: [ - '~/App_Plugins/property editors/relatedlinks/relatedlinks.js', - '~/App_Plugins/property editors/mntp/mntp.js' + '~/App_Plugins/propertyeditors/relatedlinks/relatedlinks.js', + '~/App_Plugins/propertyeditors/mntp/mntp.js' ] } \ No newline at end of file diff --git a/src/Umbraco.Web.UI.Client/src/packages/property editors/relatedlinks/relatedlinks.html b/src/Umbraco.Web.UI.Client/src/packages/propertyeditors/relatedlinks/relatedlinks.html similarity index 100% rename from src/Umbraco.Web.UI.Client/src/packages/property editors/relatedlinks/relatedlinks.html rename to src/Umbraco.Web.UI.Client/src/packages/propertyeditors/relatedlinks/relatedlinks.html diff --git a/src/Umbraco.Web.UI.Client/src/packages/property editors/relatedlinks/relatedlinks.js b/src/Umbraco.Web.UI.Client/src/packages/propertyeditors/relatedlinks/relatedlinks.js similarity index 100% rename from src/Umbraco.Web.UI.Client/src/packages/property editors/relatedlinks/relatedlinks.js rename to src/Umbraco.Web.UI.Client/src/packages/propertyeditors/relatedlinks/relatedlinks.js diff --git a/src/Umbraco.Web.UI/App_Plugins/property editors/mntp/mntp.html b/src/Umbraco.Web.UI/App_Plugins/property editors/mntp/mntp.html deleted file mode 100644 index 0ab89bc058..0000000000 --- a/src/Umbraco.Web.UI/App_Plugins/property editors/mntp/mntp.html +++ /dev/null @@ -1,18 +0,0 @@ -
- - -

-
\ No newline at end of file diff --git a/src/Umbraco.Web.UI/App_Plugins/property editors/mntp/mntp.js b/src/Umbraco.Web.UI/App_Plugins/property editors/mntp/mntp.js deleted file mode 100644 index b345d6f9e0..0000000000 --- a/src/Umbraco.Web.UI/App_Plugins/property editors/mntp/mntp.js +++ /dev/null @@ -1,42 +0,0 @@ -//this controller simply tells the dialogs service to open a mediaPicker window -//with a specified callback, this callback will receive an object with a selection on it -angular.module('umbraco') -.controller("uComponents.Editors.MNTPController", - - function($scope, dialogService, entityResource){ - $scope.ids = $scope.model.value.split(','); - $scope.renderModel = []; - - entityResource.getByIds($scope.ids).then(function(data){ - $(data).each(function(i, item){ - $scope.renderModel.push({name: item.name, id: item.id, icon: item.icon}); - }); - }); - - $scope.openContentPicker =function(){ - var d = dialogService.contentPicker({scope: $scope, callback: populate}); - }; - - $scope.remove =function(index){ - $scope.renderModel.splice(index, 1); - $scope.ids.splice(index, 1); - $scope.model.value = $scope.ids.join(); - }; - - $scope.add =function(item){ - - if($scope.ids.indexOf(item.id) < 0){ - $scope.renderModel.push({name: item.name, id: item.id, icon: item.icon}) - $scope.ids.push(item.id); - - $scope.model.value = $scope.ids.join(); - } - }; - - - function populate(data){ - $(data.selection).each(function(i, item){ - $scope.add(item); - }); - } -}); \ No newline at end of file diff --git a/src/Umbraco.Web.UI/App_Plugins/property editors/package.manifest b/src/Umbraco.Web.UI/App_Plugins/property editors/package.manifest deleted file mode 100644 index dcfbe80dc9..0000000000 --- a/src/Umbraco.Web.UI/App_Plugins/property editors/package.manifest +++ /dev/null @@ -1,30 +0,0 @@ -{ - propertyEditors: [ - { - id: "7e062c13-7c41-4ad9-b389-41d88aeef87c", - name: "Multinode treepicker", - editor: { - view: "~/App_Plugins/property editors/mntp/mntp.html" - } - }, - { - id: "71b8ad1a-8dc2-425c-b6b8-faa158075e63", - name: "Related links", - editor: { - view: "~/App_Plugins/property editors/relatedlinks/relatedlinks.html" - } - }, - { - id: "71b8ad1a-8dc2-425c-b6b8-faa158075e63", - name: "Boolean", - editor: { - view: "~/Umbraco/views/propertyeditors/boolean/boolean.html" - } - } - ] - , - javascript: [ - '~/App_Plugins/property editors/relatedlinks/relatedlinks.js', - '~/App_Plugins/property editors/mntp/mntp.js' - ] -} \ No newline at end of file From 31d6575746ce17e7762369ebf9f24ab6ea365941 Mon Sep 17 00:00:00 2001 From: Shannon Date: Mon, 12 Aug 2013 11:41:33 +1000 Subject: [PATCH 05/10] removes space in 'property editors' --- .../src/packages/propertyeditors/package.manifest | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Umbraco.Web.UI.Client/src/packages/propertyeditors/package.manifest b/src/Umbraco.Web.UI.Client/src/packages/propertyeditors/package.manifest index 016ab2923b..ca44af0b4f 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/propertyeditors/package.manifest +++ b/src/Umbraco.Web.UI.Client/src/packages/propertyeditors/package.manifest @@ -4,14 +4,14 @@ id: "7e062c13-7c41-4ad9-b389-41d88aeef87c", name: "Multinode treepicker", editor: { - view: "~/App_Plugins/property editors/mntp/mntp.html" + view: "~/App_Plugins/propertyeditors/mntp/mntp.html" } }, { id: "71b8ad1a-8dc2-425c-b6b8-faa158075e63", name: "Related links", editor: { - view: "~/App_Plugins/property editors/relatedlinks/relatedlinks.html" + view: "~/App_Plugins/propertyeditors/relatedlinks/relatedlinks.html" } }, { From afe1023e19cd406abb91b196a5b374309414e1b1 Mon Sep 17 00:00:00 2001 From: Shannon Date: Mon, 12 Aug 2013 11:53:50 +1000 Subject: [PATCH 06/10] Fixes EntityController to accept multiple query string values, adds null checks to the parameter and to null (not found entities). --- src/Umbraco.Web/Editors/EntityController.cs | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/src/Umbraco.Web/Editors/EntityController.cs b/src/Umbraco.Web/Editors/EntityController.cs index f660cb5699..6fc14c2df1 100644 --- a/src/Umbraco.Web/Editors/EntityController.cs +++ b/src/Umbraco.Web/Editors/EntityController.cs @@ -1,5 +1,8 @@ -using System.Collections.Generic; +using System; +using System.Collections.Generic; +using System.Web.Http; using AutoMapper; +using Umbraco.Core.Logging; using Umbraco.Core.Services; using Umbraco.Web.Models.ContentEditing; using Umbraco.Web.Mvc; @@ -21,13 +24,11 @@ namespace Umbraco.Web.Editors return Services.EntityService.Get(id); } - public IEnumerable GetByIds(int[] ids) + public IEnumerable GetByIds([FromUri]int[] ids) { - var list = new List(); - foreach(var id in ids) - list.Add(Services.EntityService.Get(id)); + if (ids == null) throw new ArgumentNullException("ids"); - return list; + return ids.Select(id => Services.EntityService.Get(id)).Where(entity => entity != null).ToList(); } From 1e2af42ce6fc98ab98faefc326f99ca7d7fb7b90 Mon Sep 17 00:00:00 2001 From: Shannon Date: Mon, 12 Aug 2013 14:16:45 +1000 Subject: [PATCH 07/10] Ensures internal generic properties are all wired up in c# and fixes up the boolean editor, adds templatepicker html file so that something is rendered and there are no js errors. --- src/Umbraco.Core/Constants-PropertyEditors.cs | 7 +- .../src/common/mocks/resources/_utils.js | 11 +-- .../src/common/mocks/resources/media.mocks.js | 4 +- .../boolean/boolean.controller.js | 15 ++++ .../propertyeditors/boolean/boolean.html | 4 +- .../templatepicker/templatepicker.html | 4 + .../ContentEditing/ContentItemDisplay.cs | 3 + .../ContentEditing/ContentItemDisplayBase.cs | 6 ++ .../Models/Mapping/ContentModelMapper.cs | 20 ++++- .../Models/Mapping/MediaModelMapper.cs | 8 +- .../Mapping/TabsAndPropertiesResolver.cs | 83 ++++++++++++++++++- .../PropertyEditors/LabelPropertyEditor.cs | 10 +++ .../TextStringPropertyEditor.cs | 1 - src/Umbraco.Web/Umbraco.Web.csproj | 1 + 14 files changed, 161 insertions(+), 16 deletions(-) create mode 100644 src/Umbraco.Web.UI.Client/src/views/propertyeditors/boolean/boolean.controller.js create mode 100644 src/Umbraco.Web.UI.Client/src/views/propertyeditors/templatepicker/templatepicker.html create mode 100644 src/Umbraco.Web/PropertyEditors/LabelPropertyEditor.cs diff --git a/src/Umbraco.Core/Constants-PropertyEditors.cs b/src/Umbraco.Core/Constants-PropertyEditors.cs index a0e68d23a7..60e5ddfd04 100644 --- a/src/Umbraco.Core/Constants-PropertyEditors.cs +++ b/src/Umbraco.Core/Constants-PropertyEditors.cs @@ -7,7 +7,12 @@ /// public static class PropertyEditors { - /// + /// + /// Used to prefix generic properties that are internal content properties + /// + public const string InternalGenericPropertiesPrefix = "_umb_"; + + /// /// Guid for the Checkbox list datatype. /// public const string CheckBoxList = "B4471851-82B6-4C75-AFA4-39FA9C6A75E9"; diff --git a/src/Umbraco.Web.UI.Client/src/common/mocks/resources/_utils.js b/src/Umbraco.Web.UI.Client/src/common/mocks/resources/_utils.js index 14fb6d8da8..57d3692df2 100644 --- a/src/Umbraco.Web.UI.Client/src/common/mocks/resources/_utils.js +++ b/src/Umbraco.Web.UI.Client/src/common/mocks/resources/_utils.js @@ -53,7 +53,7 @@ label: "Grid", id: 4, properties: [ - { alias: "grid", label: "Grid", view: "grid", controller: "umbraco.grid", value: "test", hideLabel: true } + { alias: "grid", label: "Grid", view: "grid", value: "test", hideLabel: true } ] }, { label: "Generic Properties", @@ -62,7 +62,7 @@ { label: 'Created by', description: 'Original author', - value: 1, + value: "Administrator", view: "readonlyvalue", alias: "_umb_createdby" }, @@ -71,9 +71,6 @@ description: 'Time this document was created', value: new Date().toIsoDateTimeString(), view: "readonlyvalue", - //NOTE: No need for filters because the date is a formatted string already because - // that is how it comes from the server as a pre-formatted json string - //config: {filter: 'date', format: 'medium'}, alias: "_umb_createdate" }, { @@ -99,10 +96,10 @@ label: 'Template', value: "1234", view: "templatepicker", - alias: "_umb_template" + alias: "_umb_template" }, { - alias: "test", label: "Stuff", view: "test", controller: "umbraco.embeddedcontent", value: "", + alias: "test", label: "Stuff", view: "test", value: "", config: { fields: [ { alias: "embedded", label: "Embbeded", view: "textstring", value: "" }, diff --git a/src/Umbraco.Web.UI.Client/src/common/mocks/resources/media.mocks.js b/src/Umbraco.Web.UI.Client/src/common/mocks/resources/media.mocks.js index 4341e27e26..d09dcd261c 100644 --- a/src/Umbraco.Web.UI.Client/src/common/mocks/resources/media.mocks.js +++ b/src/Umbraco.Web.UI.Client/src/common/mocks/resources/media.mocks.js @@ -56,14 +56,14 @@ angular.module('umbraco.mocks'). alias: "tab03", id: 3, properties: [ - { alias: "grid", label: "Grid", view: "grid", controller: "umbraco.grid", value: "test", hideLabel: true } + { alias: "grid", label: "Grid", view: "grid", value: "test", hideLabel: true } ] },{ label: "WIP", alias: "tab04", id: 4, properties: [ - { alias: "tes", label: "Stuff", view: "test", controller: "umbraco.embeddedcontent", value: "", + { alias: "tes", label: "Stuff", view: "test", value: "", config: { fields: [ diff --git a/src/Umbraco.Web.UI.Client/src/views/propertyeditors/boolean/boolean.controller.js b/src/Umbraco.Web.UI.Client/src/views/propertyeditors/boolean/boolean.controller.js new file mode 100644 index 0000000000..174e3816bf --- /dev/null +++ b/src/Umbraco.Web.UI.Client/src/views/propertyeditors/boolean/boolean.controller.js @@ -0,0 +1,15 @@ +function booleanEditorController($scope, $rootScope, assetsService) { + + $scope.renderModel = { + value: false + }; + if ($scope.model && $scope.model.value && ($scope.model.value.toString() === "1" || angular.lowercase($scope.model.value) === "true")) { + $scope.renderModel.value = true; + } + + $scope.$watch("renderModel.value", function (newVal) { + $scope.model.value = newVal === true ? "1" : "0"; + }); + +} +angular.module("umbraco").controller("Umbraco.Editors.BooleanController", booleanEditorController); \ No newline at end of file diff --git a/src/Umbraco.Web.UI.Client/src/views/propertyeditors/boolean/boolean.html b/src/Umbraco.Web.UI.Client/src/views/propertyeditors/boolean/boolean.html index d01704ffe4..7f606e583c 100644 --- a/src/Umbraco.Web.UI.Client/src/views/propertyeditors/boolean/boolean.html +++ b/src/Umbraco.Web.UI.Client/src/views/propertyeditors/boolean/boolean.html @@ -1 +1,3 @@ - + + diff --git a/src/Umbraco.Web.UI.Client/src/views/propertyeditors/templatepicker/templatepicker.html b/src/Umbraco.Web.UI.Client/src/views/propertyeditors/templatepicker/templatepicker.html new file mode 100644 index 0000000000..ebd32d0748 --- /dev/null +++ b/src/Umbraco.Web.UI.Client/src/views/propertyeditors/templatepicker/templatepicker.html @@ -0,0 +1,4 @@ +
+
TODO: Implement this picker
+
+
\ No newline at end of file diff --git a/src/Umbraco.Web/Models/ContentEditing/ContentItemDisplay.cs b/src/Umbraco.Web/Models/ContentEditing/ContentItemDisplay.cs index e08540b242..ad961c4b50 100644 --- a/src/Umbraco.Web/Models/ContentEditing/ContentItemDisplay.cs +++ b/src/Umbraco.Web/Models/ContentEditing/ContentItemDisplay.cs @@ -17,6 +17,9 @@ namespace Umbraco.Web.Models.ContentEditing [DataMember(Name = "publishDate")] public DateTime? PublishDate { get; set; } + + [DataMember(Name = "template")] + public string Template { get; set; } } } \ No newline at end of file diff --git a/src/Umbraco.Web/Models/ContentEditing/ContentItemDisplayBase.cs b/src/Umbraco.Web/Models/ContentEditing/ContentItemDisplayBase.cs index c696aeb675..867f3a6ebc 100644 --- a/src/Umbraco.Web/Models/ContentEditing/ContentItemDisplayBase.cs +++ b/src/Umbraco.Web/Models/ContentEditing/ContentItemDisplayBase.cs @@ -13,6 +13,12 @@ namespace Umbraco.Web.Models.ContentEditing Notifications = new List(); } + /// + /// The name of the content type + /// + [DataMember(Name = "contentTypeName")] + public string ContentTypeName { get; set; } + /// /// This is used to add custom localized messages/strings to the response for the app to use for localized UI purposes. /// diff --git a/src/Umbraco.Web/Models/Mapping/ContentModelMapper.cs b/src/Umbraco.Web/Models/Mapping/ContentModelMapper.cs index d9fab62343..3063d9b522 100644 --- a/src/Umbraco.Web/Models/Mapping/ContentModelMapper.cs +++ b/src/Umbraco.Web/Models/Mapping/ContentModelMapper.cs @@ -1,13 +1,17 @@ using System; +using System.Linq; using System.Linq.Expressions; using AutoMapper; using Umbraco.Core; using Umbraco.Core.Models; using Umbraco.Core.Models.Mapping; +using Umbraco.Core.PropertyEditors; using Umbraco.Web.Models.ContentEditing; +using umbraco; namespace Umbraco.Web.Models.Mapping { + /// /// Declares how model mappings for content /// @@ -15,6 +19,7 @@ namespace Umbraco.Web.Models.Mapping { public override void ConfigureMappings(IConfiguration config, ApplicationContext applicationContext) { + //FROM IContent TO ContentItemDisplay config.CreateMap() .ForMember( @@ -29,11 +34,24 @@ namespace Umbraco.Web.Models.Mapping .ForMember( dto => dto.ContentTypeAlias, expression => expression.MapFrom(content => content.ContentType.Alias)) + .ForMember( + dto => dto.ContentTypeName, + expression => expression.MapFrom(content => content.ContentType.Name)) .ForMember( dto => dto.PublishDate, expression => expression.MapFrom(content => GetPublishedDate(content, applicationContext))) + .ForMember( + dto => dto.Template, + expression => expression.MapFrom(content => content.Template.Name)) .ForMember(display => display.Properties, expression => expression.Ignore()) - .ForMember(display => display.Tabs, expression => expression.ResolveUsing()); + .ForMember(display => display.Tabs, expression => expression.ResolveUsing()) + .AfterMap((content, display) => TabsAndPropertiesResolver.MapGenericProperties(content, display, new ContentPropertyDisplay + { + Alias = string.Format("{0}doctype", Constants.PropertyEditors.InternalGenericPropertiesPrefix), + Label = "Template", //TODO: localize this? + Value = display.Template, + View = "templatepicker" //TODO: Hard coding this because the templatepicker doesn't necessarily need to be a resolvable (real) property editor + })); //FROM IContent TO ContentItemBasic config.CreateMap>() diff --git a/src/Umbraco.Web/Models/Mapping/MediaModelMapper.cs b/src/Umbraco.Web/Models/Mapping/MediaModelMapper.cs index f610c08926..fe3643da87 100644 --- a/src/Umbraco.Web/Models/Mapping/MediaModelMapper.cs +++ b/src/Umbraco.Web/Models/Mapping/MediaModelMapper.cs @@ -29,9 +29,13 @@ namespace Umbraco.Web.Models.Mapping expression => expression.MapFrom(content => content.ContentType.Icon)) .ForMember( dto => dto.ContentTypeAlias, - expression => expression.MapFrom(content => content.ContentType.Alias)) + expression => expression.MapFrom(content => content.ContentType.Alias)) + .ForMember( + dto => dto.ContentTypeName, + expression => expression.MapFrom(content => content.ContentType.Name)) .ForMember(display => display.Properties, expression => expression.Ignore()) - .ForMember(display => display.Tabs, expression => expression.ResolveUsing()); + .ForMember(display => display.Tabs, expression => expression.ResolveUsing()) + .AfterMap((media, display) => TabsAndPropertiesResolver.MapGenericProperties(media, display)); //FROM IMedia TO ContentItemBasic config.CreateMap>() diff --git a/src/Umbraco.Web/Models/Mapping/TabsAndPropertiesResolver.cs b/src/Umbraco.Web/Models/Mapping/TabsAndPropertiesResolver.cs index c943cf8ff0..3f284f8a7b 100644 --- a/src/Umbraco.Web/Models/Mapping/TabsAndPropertiesResolver.cs +++ b/src/Umbraco.Web/Models/Mapping/TabsAndPropertiesResolver.cs @@ -1,8 +1,12 @@ -using System.Collections.Generic; +using System; +using System.Collections.Generic; using System.Linq; using AutoMapper; +using Umbraco.Core; using Umbraco.Core.Models; +using Umbraco.Core.PropertyEditors; using Umbraco.Web.Models.ContentEditing; +using umbraco; namespace Umbraco.Web.Models.Mapping { @@ -11,6 +15,83 @@ namespace Umbraco.Web.Models.Mapping ///
internal class TabsAndPropertiesResolver : ValueResolver>> { + /// + /// Maps properties on to the generic properties tab + /// + /// + /// + /// + /// Any additional custom properties to assign to the generic properties tab. + /// + /// + /// The generic properties tab is mapped during AfterMap and is responsible for + /// setting up the properties such as Created date, udpated date, template selected, etc... + /// + public static void MapGenericProperties( + TPersisted content, + ContentItemDisplayBase display, + params ContentPropertyDisplay[] customProperties) + where TPersisted : IContentBase + { + var genericProps = display.Tabs.Single(x => x.Id == 0); + + //store the current props to append to the newly inserted ones + var currProps = genericProps.Properties.ToArray(); + + var labelEditor = PropertyEditorResolver.Current.GetById(new Guid(Constants.PropertyEditors.NoEdit)).ValueEditor.View; + + var contentProps = new List + { + new ContentPropertyDisplay + { + Alias = string.Format("{0}creator", Constants.PropertyEditors.InternalGenericPropertiesPrefix), + Label = ui.Text("content", "createBy"), + Description = "Original author", //TODO: Localize this + Value = display.Owner.Name, + View = labelEditor + }, + new ContentPropertyDisplay + { + Alias = string.Format("{0}createdate", Constants.PropertyEditors.InternalGenericPropertiesPrefix), + Label = ui.Text("content", "createDate"), + Description = "Time this document was created", //TODO: Localize this + Value = display.CreateDate.ToIsoString(), + View = labelEditor + }, + new ContentPropertyDisplay + { + Alias = string.Format("{0}updatedate", Constants.PropertyEditors.InternalGenericPropertiesPrefix), + Label = ui.Text("content", "updateDate"), + Description = "Time this document was last updated", //TODO: Localize this + Value = display.UpdateDate.ToIsoString(), + View = labelEditor + }, + new ContentPropertyDisplay + { + Alias = string.Format("{0}id", Constants.PropertyEditors.InternalGenericPropertiesPrefix), + Label = "Id", + Value = display.Id.ToInvariantString(), + View = labelEditor + }, + new ContentPropertyDisplay + { + Alias = string.Format("{0}doctype", Constants.PropertyEditors.InternalGenericPropertiesPrefix), + Label = ui.Text("content", "documentType"), + Value = display.ContentTypeName, + View = labelEditor + } + }; + + //add the custom ones + contentProps.AddRange(customProperties); + + //now add the user props + contentProps.AddRange(currProps); + + //re-assign + genericProps.Properties = contentProps; + } + protected override IEnumerable> ResolveCore(IContentBase content) { var aggregateTabs = new List>(); diff --git a/src/Umbraco.Web/PropertyEditors/LabelPropertyEditor.cs b/src/Umbraco.Web/PropertyEditors/LabelPropertyEditor.cs new file mode 100644 index 0000000000..b4122573c4 --- /dev/null +++ b/src/Umbraco.Web/PropertyEditors/LabelPropertyEditor.cs @@ -0,0 +1,10 @@ +using Umbraco.Core; +using Umbraco.Core.PropertyEditors; + +namespace Umbraco.Web.PropertyEditors +{ + [PropertyEditor(Constants.PropertyEditors.NoEdit, "Label", "readonlyvalue")] + public class LabelPropertyEditor : PropertyEditor + { + } +} \ No newline at end of file diff --git a/src/Umbraco.Web/PropertyEditors/TextStringPropertyEditor.cs b/src/Umbraco.Web/PropertyEditors/TextStringPropertyEditor.cs index 7524c56a5c..fa6cfe0cd2 100644 --- a/src/Umbraco.Web/PropertyEditors/TextStringPropertyEditor.cs +++ b/src/Umbraco.Web/PropertyEditors/TextStringPropertyEditor.cs @@ -8,7 +8,6 @@ using Umbraco.Core.PropertyEditors; namespace Umbraco.Web.PropertyEditors { - [PropertyEditor(Constants.PropertyEditors.Textbox, "Textstring", "textstring")] public class TextStringPropertyEditor : PropertyEditor { diff --git a/src/Umbraco.Web/Umbraco.Web.csproj b/src/Umbraco.Web/Umbraco.Web.csproj index 2a730f08ba..52d20f9661 100644 --- a/src/Umbraco.Web/Umbraco.Web.csproj +++ b/src/Umbraco.Web/Umbraco.Web.csproj @@ -300,6 +300,7 @@ + From 8525468312230932ef5a1e818fc073c14a2dce16 Mon Sep 17 00:00:00 2001 From: Shannon Date: Mon, 12 Aug 2013 15:57:54 +1000 Subject: [PATCH 08/10] Get the generic property tab rendering properly with a url list as well. --- .../src/common/mocks/resources/_utils.js | 44 ++++++++++----- .../src/views/content/edit.html | 4 +- .../readonlyvalue/readonlyvalue.controller.js | 13 +++-- .../urllist/urllist.controller.js | 11 ++++ .../propertyeditors/urllist/urllist.html | 7 +++ .../ContentEditing/ContentItemDisplay.cs | 9 ++++ .../Models/Mapping/ContentModelMapper.cs | 53 ++++++++++++++++--- .../Mapping/TabsAndPropertiesResolver.cs | 20 +++---- src/Umbraco.Web/Routing/UrlProvider.cs | 2 +- .../Routing/UrlProviderExtensions.cs | 47 ++++++++++++++++ src/Umbraco.Web/Umbraco.Web.csproj | 1 + 11 files changed, 175 insertions(+), 36 deletions(-) create mode 100644 src/Umbraco.Web.UI.Client/src/views/propertyeditors/urllist/urllist.controller.js create mode 100644 src/Umbraco.Web.UI.Client/src/views/propertyeditors/urllist/urllist.html create mode 100644 src/Umbraco.Web/Routing/UrlProviderExtensions.cs diff --git a/src/Umbraco.Web.UI.Client/src/common/mocks/resources/_utils.js b/src/Umbraco.Web.UI.Client/src/common/mocks/resources/_utils.js index 57d3692df2..f8ecb582ea 100644 --- a/src/Umbraco.Web.UI.Client/src/common/mocks/resources/_utils.js +++ b/src/Umbraco.Web.UI.Client/src/common/mocks/resources/_utils.js @@ -59,6 +59,12 @@ label: "Generic Properties", id: 0, properties: [ + { + label: 'Id', + value: 1234, + view: "readonlyvalue", + alias: "_umb_id" + }, { label: 'Created by', description: 'Original author', @@ -68,36 +74,50 @@ }, { label: 'Created', - description: 'Time this document was created', + description: 'Date/time this document was created', value: new Date().toIsoDateTimeString(), view: "readonlyvalue", alias: "_umb_createdate" }, { label: 'Updated', - description: 'Time this document was last updated', + description: 'Date/time this document was created', value: new Date().toIsoDateTimeString(), view: "readonlyvalue", alias: "_umb_updatedate" - }, - { - label: 'Id', - value: 1234, - view: "readonlyvalue", - alias: "_umb_id" - }, + }, { label: 'Document Type', value: "Home page", view: "readonlyvalue", - alias: "_umb_doctype" + alias: "_umb_doctype" }, { - label: 'Template', - value: "1234", + label: 'Publish at', + description: 'Date/time to publish this document', + value: new Date().toIsoDateTimeString(), + view: "datepicker", + alias: "_umb_releasedate" + }, + { + label: 'Unpublish at', + description: 'Date/time to un-publish this document', + value: new Date().toIsoDateTimeString(), + view: "datepicker", + alias: "_umb_removedate" + }, + { + label: 'Template', + value: "1234", view: "templatepicker", alias: "_umb_template" }, + { + label: 'Link to document', + value: ["/testing" + id, "http://localhost/testing" + id, "http://mydomain.com/testing" + id].join(), + view: "urllist", + alias: "_umb_template" + }, { alias: "test", label: "Stuff", view: "test", value: "", config: { diff --git a/src/Umbraco.Web.UI.Client/src/views/content/edit.html b/src/Umbraco.Web.UI.Client/src/views/content/edit.html index 6097f57d6e..cb014917e2 100644 --- a/src/Umbraco.Web.UI.Client/src/views/content/edit.html +++ b/src/Umbraco.Web.UI.Client/src/views/content/edit.html @@ -1,4 +1,4 @@ - +
@@ -48,4 +48,4 @@ - +
diff --git a/src/Umbraco.Web.UI.Client/src/views/propertyeditors/readonlyvalue/readonlyvalue.controller.js b/src/Umbraco.Web.UI.Client/src/views/propertyeditors/readonlyvalue/readonlyvalue.controller.js index b5bfffe668..de258e25fb 100644 --- a/src/Umbraco.Web.UI.Client/src/views/propertyeditors/readonlyvalue/readonlyvalue.controller.js +++ b/src/Umbraco.Web.UI.Client/src/views/propertyeditors/readonlyvalue/readonlyvalue.controller.js @@ -1,8 +1,15 @@ angular.module('umbraco').controller("Umbraco.Editors.ReadOnlyValueController", function($rootScope, $scope, $filter){ - if ($scope.model.config && $scope.model.config.filter && $scope.model.config.format) { - $scope.displayvalue = $filter($scope.model.config.filter)($scope.model.value, $scope.model.config.filter); - }else{ + + if ($scope.model.config && $scope.model.config.filter) { + if ($scope.model.config.format) { + $scope.displayvalue = $filter($scope.model.config.filter)($scope.model.value, $scope.model.config.format); + } + else { + $scope.displayvalue = $filter($scope.model.config.filter)($scope.model.value); + } + } + else { $scope.displayvalue = $scope.model.value; } }); \ No newline at end of file diff --git a/src/Umbraco.Web.UI.Client/src/views/propertyeditors/urllist/urllist.controller.js b/src/Umbraco.Web.UI.Client/src/views/propertyeditors/urllist/urllist.controller.js new file mode 100644 index 0000000000..9abc45d2f3 --- /dev/null +++ b/src/Umbraco.Web.UI.Client/src/views/propertyeditors/urllist/urllist.controller.js @@ -0,0 +1,11 @@ +angular.module('umbraco').controller("Umbraco.Editors.UrlListController", + function($rootScope, $scope, $filter) { + + $scope.renderModel = _.map($scope.model.value.split(","), function(item) { + return { + url: item, + urlTarget : ($scope.config && $scope.config.target) ? $scope.config.target : "_blank" + }; + }); + + }); \ No newline at end of file diff --git a/src/Umbraco.Web.UI.Client/src/views/propertyeditors/urllist/urllist.html b/src/Umbraco.Web.UI.Client/src/views/propertyeditors/urllist/urllist.html new file mode 100644 index 0000000000..7255b5832f --- /dev/null +++ b/src/Umbraco.Web.UI.Client/src/views/propertyeditors/urllist/urllist.html @@ -0,0 +1,7 @@ +
+ +
\ No newline at end of file diff --git a/src/Umbraco.Web/Models/ContentEditing/ContentItemDisplay.cs b/src/Umbraco.Web/Models/ContentEditing/ContentItemDisplay.cs index ad961c4b50..5ca8ed6f6a 100644 --- a/src/Umbraco.Web/Models/ContentEditing/ContentItemDisplay.cs +++ b/src/Umbraco.Web/Models/ContentEditing/ContentItemDisplay.cs @@ -18,8 +18,17 @@ namespace Umbraco.Web.Models.ContentEditing [DataMember(Name = "publishDate")] public DateTime? PublishDate { get; set; } + [DataMember(Name = "releaseDate")] + public DateTime? ReleaseDate { get; set; } + + [DataMember(Name = "removeDate")] + public DateTime? RemoveDate { get; set; } + [DataMember(Name = "template")] public string Template { get; set; } + + [DataMember(Name = "urls")] + public string[] Urls { get; set; } } } \ No newline at end of file diff --git a/src/Umbraco.Web/Models/Mapping/ContentModelMapper.cs b/src/Umbraco.Web/Models/Mapping/ContentModelMapper.cs index 3063d9b522..0c2ed6830b 100644 --- a/src/Umbraco.Web/Models/Mapping/ContentModelMapper.cs +++ b/src/Umbraco.Web/Models/Mapping/ContentModelMapper.cs @@ -1,4 +1,5 @@ using System; +using System.Collections.Generic; using System.Linq; using System.Linq.Expressions; using AutoMapper; @@ -8,6 +9,7 @@ using Umbraco.Core.Models.Mapping; using Umbraco.Core.PropertyEditors; using Umbraco.Web.Models.ContentEditing; using umbraco; +using Umbraco.Web.Routing; namespace Umbraco.Web.Models.Mapping { @@ -40,18 +42,53 @@ namespace Umbraco.Web.Models.Mapping .ForMember( dto => dto.PublishDate, expression => expression.MapFrom(content => GetPublishedDate(content, applicationContext))) - .ForMember( + .ForMember( dto => dto.Template, expression => expression.MapFrom(content => content.Template.Name)) + .ForMember( + dto => dto.ReleaseDate, + expression => expression.MapFrom(content => content.ReleaseDate)) + .ForMember( + dto => dto.RemoveDate, + expression => expression.MapFrom(content => content.ExpireDate)) + .ForMember( + dto => dto.Urls, + expression => expression.MapFrom(content => + UmbracoContext.Current == null + ? new[] {"Cannot generate urls without a current Umbraco Context"} + : content.GetContentUrls())) .ForMember(display => display.Properties, expression => expression.Ignore()) .ForMember(display => display.Tabs, expression => expression.ResolveUsing()) - .AfterMap((content, display) => TabsAndPropertiesResolver.MapGenericProperties(content, display, new ContentPropertyDisplay - { - Alias = string.Format("{0}doctype", Constants.PropertyEditors.InternalGenericPropertiesPrefix), - Label = "Template", //TODO: localize this? - Value = display.Template, - View = "templatepicker" //TODO: Hard coding this because the templatepicker doesn't necessarily need to be a resolvable (real) property editor - })); + .AfterMap((content, display) => TabsAndPropertiesResolver.MapGenericProperties( + content, display, + new ContentPropertyDisplay + { + Alias = string.Format("{0}releasedate", Constants.PropertyEditors.InternalGenericPropertiesPrefix), + Label = ui.Text("content", "releaseDate"), + Value = display.ReleaseDate.HasValue ? display.ReleaseDate.Value.ToIsoString() : null, + View = "datepicker" //TODO: Hard coding this because the templatepicker doesn't necessarily need to be a resolvable (real) property editor + }, + new ContentPropertyDisplay + { + Alias = string.Format("{0}removedate", Constants.PropertyEditors.InternalGenericPropertiesPrefix), + Label = ui.Text("content", "removeDate"), + Value = display.RemoveDate.HasValue ? display.RemoveDate.Value.ToIsoString() : null, + View = "datepicker" //TODO: Hard coding this because the templatepicker doesn't necessarily need to be a resolvable (real) property editor + }, + new ContentPropertyDisplay + { + Alias = string.Format("{0}doctype", Constants.PropertyEditors.InternalGenericPropertiesPrefix), + Label = "Template", //TODO: localize this? + Value = display.Template, + View = "templatepicker" //TODO: Hard coding this because the templatepicker doesn't necessarily need to be a resolvable (real) property editor + }, + new ContentPropertyDisplay + { + Alias = string.Format("{0}urls", Constants.PropertyEditors.InternalGenericPropertiesPrefix), + Label = ui.Text("content", "urls"), + Value = string.Join(",", display.Urls), + View = "urllist" //TODO: Hard coding this because the templatepicker doesn't necessarily need to be a resolvable (real) property editor + })); //FROM IContent TO ContentItemBasic config.CreateMap>() diff --git a/src/Umbraco.Web/Models/Mapping/TabsAndPropertiesResolver.cs b/src/Umbraco.Web/Models/Mapping/TabsAndPropertiesResolver.cs index 3f284f8a7b..26fc6f63cf 100644 --- a/src/Umbraco.Web/Models/Mapping/TabsAndPropertiesResolver.cs +++ b/src/Umbraco.Web/Models/Mapping/TabsAndPropertiesResolver.cs @@ -42,6 +42,13 @@ namespace Umbraco.Web.Models.Mapping var contentProps = new List { + new ContentPropertyDisplay + { + Alias = string.Format("{0}id", Constants.PropertyEditors.InternalGenericPropertiesPrefix), + Label = "Id", + Value = display.Id.ToInvariantString(), + View = labelEditor + }, new ContentPropertyDisplay { Alias = string.Format("{0}creator", Constants.PropertyEditors.InternalGenericPropertiesPrefix), @@ -54,7 +61,7 @@ namespace Umbraco.Web.Models.Mapping { Alias = string.Format("{0}createdate", Constants.PropertyEditors.InternalGenericPropertiesPrefix), Label = ui.Text("content", "createDate"), - Description = "Time this document was created", //TODO: Localize this + Description = "Date/time this document was created", //TODO: Localize this Value = display.CreateDate.ToIsoString(), View = labelEditor }, @@ -62,17 +69,10 @@ namespace Umbraco.Web.Models.Mapping { Alias = string.Format("{0}updatedate", Constants.PropertyEditors.InternalGenericPropertiesPrefix), Label = ui.Text("content", "updateDate"), - Description = "Time this document was last updated", //TODO: Localize this + Description = "Date/time this document was created", //TODO: Localize this Value = display.UpdateDate.ToIsoString(), View = labelEditor - }, - new ContentPropertyDisplay - { - Alias = string.Format("{0}id", Constants.PropertyEditors.InternalGenericPropertiesPrefix), - Label = "Id", - Value = display.Id.ToInvariantString(), - View = labelEditor - }, + }, new ContentPropertyDisplay { Alias = string.Format("{0}doctype", Constants.PropertyEditors.InternalGenericPropertiesPrefix), diff --git a/src/Umbraco.Web/Routing/UrlProvider.cs b/src/Umbraco.Web/Routing/UrlProvider.cs index 62d4142ec6..b8020ff04f 100644 --- a/src/Umbraco.Web/Routing/UrlProvider.cs +++ b/src/Umbraco.Web/Routing/UrlProvider.cs @@ -1,8 +1,8 @@ using System; using System.Collections.Generic; using System.Linq; -using Umbraco.Core.Configuration; using Umbraco.Web.PublishedCache; +using UmbracoSettings = Umbraco.Core.Configuration.UmbracoSettings; namespace Umbraco.Web.Routing { diff --git a/src/Umbraco.Web/Routing/UrlProviderExtensions.cs b/src/Umbraco.Web/Routing/UrlProviderExtensions.cs new file mode 100644 index 0000000000..4bd1ac3c8c --- /dev/null +++ b/src/Umbraco.Web/Routing/UrlProviderExtensions.cs @@ -0,0 +1,47 @@ +using System.Collections.Generic; +using Umbraco.Core.Models; +using umbraco; + +namespace Umbraco.Web.Routing +{ + internal static class UrlProviderExtensions + { + /// + /// Gets the URLs for the content item + /// + /// + /// + /// + /// Use this when displaying URLs, if there are errors genertaing the urls the urls themselves will + /// contain the errors. + /// + public static IEnumerable GetContentUrls(this IContent content) + { + var urlProvider = UmbracoContext.Current.RoutingContext.UrlProvider; + var url = urlProvider.GetUrl(content.Id); + var urls = new List(); + if (url == "#") + { + // document as a published version yet it's url is "#" => a parent must be + // unpublished, walk up the tree until we find it, and report. + var parent = content; + do + { + parent = parent.ParentId > 0 ? content.Parent() : null; + } + while (parent != null && parent.Published); + + if (parent == null) // oops - internal error + urls.Add(ui.Text("content", "parentNotPublishedAnomaly", UmbracoContext.Current.Security.CurrentUser)); + else + urls.Add(ui.Text("content", "parentNotPublished", parent.Name, UmbracoContext.Current.Security.CurrentUser)); + } + else + { + urls.Add(url); + urls.AddRange(urlProvider.GetOtherUrls(content.Id)); + } + return urls; + } + } +} \ No newline at end of file diff --git a/src/Umbraco.Web/Umbraco.Web.csproj b/src/Umbraco.Web/Umbraco.Web.csproj index 52d20f9661..c75d8fe75f 100644 --- a/src/Umbraco.Web/Umbraco.Web.csproj +++ b/src/Umbraco.Web/Umbraco.Web.csproj @@ -301,6 +301,7 @@ + From c3e773b5985c05d92dd1d212cb82b4f68912ff7d Mon Sep 17 00:00:00 2001 From: Shannon Date: Mon, 12 Aug 2013 16:45:00 +1000 Subject: [PATCH 09/10] Wires up release and expire dates to be persisted, template is wired up but need to get the picker rendering. --- .../src/common/mocks/resources/_utils.js | 4 ++-- .../src/common/services/util.service.js | 19 ++++++++++++++++ .../templatepicker/templatepicker.html | 2 +- src/Umbraco.Web/Editors/ContentController.cs | 22 ++++++++++++++++--- src/Umbraco.Web/Editors/MediaController.cs | 2 +- .../ContentEditing/ContentItemDisplay.cs | 21 ++++++++++++++++-- .../Models/ContentEditing/ContentItemSave.cs | 15 ++++++++++++- .../Models/Mapping/ContentModelMapper.cs | 22 +++++++++---------- 8 files changed, 86 insertions(+), 21 deletions(-) diff --git a/src/Umbraco.Web.UI.Client/src/common/mocks/resources/_utils.js b/src/Umbraco.Web.UI.Client/src/common/mocks/resources/_utils.js index f8ecb582ea..1eb4460da8 100644 --- a/src/Umbraco.Web.UI.Client/src/common/mocks/resources/_utils.js +++ b/src/Umbraco.Web.UI.Client/src/common/mocks/resources/_utils.js @@ -104,11 +104,11 @@ description: 'Date/time to un-publish this document', value: new Date().toIsoDateTimeString(), view: "datepicker", - alias: "_umb_removedate" + alias: "_umb_expiredate" }, { label: 'Template', - value: "1234", + value: "{id: 1234, alias: 'myTemplate', name: 'My Template'}", view: "templatepicker", alias: "_umb_template" }, diff --git a/src/Umbraco.Web.UI.Client/src/common/services/util.service.js b/src/Umbraco.Web.UI.Client/src/common/services/util.service.js index e5393069c9..d7297da114 100644 --- a/src/Umbraco.Web.UI.Client/src/common/services/util.service.js +++ b/src/Umbraco.Web.UI.Client/src/common/services/util.service.js @@ -276,6 +276,7 @@ angular.module('umbraco.services').factory('umbImageHelper', umbImageHelper); **/ function umbDataFormatter() { return { + /** formats the display model used to display the content to the model used to save the content */ formatContentPostData: function (displayModel, action) { //NOTE: the display model inherits from the save model so we can in theory just post up the display model but @@ -289,6 +290,7 @@ function umbDataFormatter() { //set the action on the save model action: action }; + _.each(displayModel.tabs, function (tab) { _.each(tab.properties, function (prop) { @@ -301,6 +303,23 @@ function umbDataFormatter() { value: prop.value }); } + else { + //here we need to map some of our internal properties to the content save item + + switch (prop.alias) { + case "_umb_expiredate": + saveModel.expireDate = prop.value; + break; + case "_umb_releasedate": + saveModel.releaseDate = prop.value; + break; + case "_umb_template": + //this will be a json string + var json = angular.toJson(prop.value); + saveModel.templateAlias = json.alias; + break; + } + } }); }); diff --git a/src/Umbraco.Web.UI.Client/src/views/propertyeditors/templatepicker/templatepicker.html b/src/Umbraco.Web.UI.Client/src/views/propertyeditors/templatepicker/templatepicker.html index ebd32d0748..c974776bae 100644 --- a/src/Umbraco.Web.UI.Client/src/views/propertyeditors/templatepicker/templatepicker.html +++ b/src/Umbraco.Web.UI.Client/src/views/propertyeditors/templatepicker/templatepicker.html @@ -1,4 +1,4 @@
TODO: Implement this picker
-
+
{{model.value | json}}
\ No newline at end of file diff --git a/src/Umbraco.Web/Editors/ContentController.cs b/src/Umbraco.Web/Editors/ContentController.cs index 9ccb07b99c..c64e035b79 100644 --- a/src/Umbraco.Web/Editors/ContentController.cs +++ b/src/Umbraco.Web/Editors/ContentController.cs @@ -192,7 +192,23 @@ namespace Umbraco.Web.Editors //TODO: We need to support 'send to publish' //TODO: We'll need to save the new template, publishat, etc... values here - + contentItem.PersistedContent.ExpireDate = contentItem.ExpireDate; + contentItem.PersistedContent.ReleaseDate = contentItem.ReleaseDate; + //only set the template if it didn't change + if (contentItem.PersistedContent.Template.Alias != contentItem.TemplateAlias) + { + var template = Services.FileService.GetTemplate(contentItem.TemplateAlias); + if (template == null) + { + //ModelState.AddModelError("Template", "No template exists with the specified alias: " + contentItem.TemplateAlias); + LogHelper.Warn("No template exists with the specified alias: " + contentItem.TemplateAlias); + } + else + { + contentItem.PersistedContent.Template = template; + } + } + MapPropertyValues(contentItem); //We need to manually check the validation results here because: @@ -232,12 +248,12 @@ namespace Umbraco.Web.Editors if (contentItem.Action == ContentSaveAction.Save || contentItem.Action == ContentSaveAction.SaveNew) { //save the item - Services.ContentService.Save(contentItem.PersistedContent); + Services.ContentService.Save(contentItem.PersistedContent, (int)Security.CurrentUser.Id); } else { //publish the item and check if it worked, if not we will show a diff msg below - publishStatus = ((ContentService)Services.ContentService).SaveAndPublishInternal(contentItem.PersistedContent); + publishStatus = ((ContentService)Services.ContentService).SaveAndPublishInternal(contentItem.PersistedContent, (int)Security.CurrentUser.Id); } diff --git a/src/Umbraco.Web/Editors/MediaController.cs b/src/Umbraco.Web/Editors/MediaController.cs index af6e1f8512..7c04ecc434 100644 --- a/src/Umbraco.Web/Editors/MediaController.cs +++ b/src/Umbraco.Web/Editors/MediaController.cs @@ -157,7 +157,7 @@ namespace Umbraco.Web.Editors } //save the item - Services.MediaService.Save(contentItem.PersistedContent); + Services.MediaService.Save(contentItem.PersistedContent, (int)Security.CurrentUser.Id); //return the updated model var display = Mapper.Map(contentItem.PersistedContent); diff --git a/src/Umbraco.Web/Models/ContentEditing/ContentItemDisplay.cs b/src/Umbraco.Web/Models/ContentEditing/ContentItemDisplay.cs index 5ca8ed6f6a..57bfcbe006 100644 --- a/src/Umbraco.Web/Models/ContentEditing/ContentItemDisplay.cs +++ b/src/Umbraco.Web/Models/ContentEditing/ContentItemDisplay.cs @@ -5,6 +5,7 @@ using System.Runtime.Serialization; using System.Web.Http; using System.Web.Http.ModelBinding; using Umbraco.Core.Models; +using Umbraco.Core.Models.Validation; namespace Umbraco.Web.Models.ContentEditing { @@ -22,13 +23,29 @@ namespace Umbraco.Web.Models.ContentEditing public DateTime? ReleaseDate { get; set; } [DataMember(Name = "removeDate")] - public DateTime? RemoveDate { get; set; } + public DateTime? ExpireDate { get; set; } [DataMember(Name = "template")] - public string Template { get; set; } + public TemplateBasic Template { get; set; } [DataMember(Name = "urls")] public string[] Urls { get; set; } } + + [DataContract(Name = "template", Namespace = "")] + public class TemplateBasic + { + [DataMember(Name = "id", IsRequired = true)] + [Required] + public int Id { get; set; } + + [DataMember(Name = "name", IsRequired = true)] + [Required(AllowEmptyStrings = false)] + public string Name { get; set; } + + [DataMember(Name = "alias", IsRequired = true)] + [Required(AllowEmptyStrings = false)] + public string Alias { get; set; } + } } \ No newline at end of file diff --git a/src/Umbraco.Web/Models/ContentEditing/ContentItemSave.cs b/src/Umbraco.Web/Models/ContentEditing/ContentItemSave.cs index b462c75280..9c04a3adcf 100644 --- a/src/Umbraco.Web/Models/ContentEditing/ContentItemSave.cs +++ b/src/Umbraco.Web/Models/ContentEditing/ContentItemSave.cs @@ -1,4 +1,5 @@ -using System.Collections.Generic; +using System; +using System.Collections.Generic; using System.Runtime.Serialization; using Newtonsoft.Json; using System.ComponentModel.DataAnnotations; @@ -25,6 +26,18 @@ namespace Umbraco.Web.Models.ContentEditing [Required] public ContentSaveAction Action { get; set; } + /// + /// The template alias to save + /// + [DataMember(Name = "templateAlias")] + public string TemplateAlias { get; set; } + + [DataMember(Name = "releaseDate")] + public DateTime? ReleaseDate { get; set; } + + [DataMember(Name = "expireDate")] + public DateTime? ExpireDate { get; set; } + /// /// The collection of files uploaded /// diff --git a/src/Umbraco.Web/Models/Mapping/ContentModelMapper.cs b/src/Umbraco.Web/Models/Mapping/ContentModelMapper.cs index 0c2ed6830b..bdcaa6de7c 100644 --- a/src/Umbraco.Web/Models/Mapping/ContentModelMapper.cs +++ b/src/Umbraco.Web/Models/Mapping/ContentModelMapper.cs @@ -3,6 +3,7 @@ using System.Collections.Generic; using System.Linq; using System.Linq.Expressions; using AutoMapper; +using Newtonsoft.Json; using Umbraco.Core; using Umbraco.Core.Models; using Umbraco.Core.Models.Mapping; @@ -44,13 +45,12 @@ namespace Umbraco.Web.Models.Mapping expression => expression.MapFrom(content => GetPublishedDate(content, applicationContext))) .ForMember( dto => dto.Template, - expression => expression.MapFrom(content => content.Template.Name)) - .ForMember( - dto => dto.ReleaseDate, - expression => expression.MapFrom(content => content.ReleaseDate)) - .ForMember( - dto => dto.RemoveDate, - expression => expression.MapFrom(content => content.ExpireDate)) + expression => expression.MapFrom(content => new TemplateBasic + { + Alias = content.Template.Alias, + Id = content.Template.Id, + Name = content.Template.Name + })) .ForMember( dto => dto.Urls, expression => expression.MapFrom(content => @@ -70,16 +70,16 @@ namespace Umbraco.Web.Models.Mapping }, new ContentPropertyDisplay { - Alias = string.Format("{0}removedate", Constants.PropertyEditors.InternalGenericPropertiesPrefix), + Alias = string.Format("{0}expiredate", Constants.PropertyEditors.InternalGenericPropertiesPrefix), Label = ui.Text("content", "removeDate"), - Value = display.RemoveDate.HasValue ? display.RemoveDate.Value.ToIsoString() : null, + Value = display.ExpireDate.HasValue ? display.ExpireDate.Value.ToIsoString() : null, View = "datepicker" //TODO: Hard coding this because the templatepicker doesn't necessarily need to be a resolvable (real) property editor }, new ContentPropertyDisplay { - Alias = string.Format("{0}doctype", Constants.PropertyEditors.InternalGenericPropertiesPrefix), + Alias = string.Format("{0}template", Constants.PropertyEditors.InternalGenericPropertiesPrefix), Label = "Template", //TODO: localize this? - Value = display.Template, + Value = JsonConvert.SerializeObject(display.Template), View = "templatepicker" //TODO: Hard coding this because the templatepicker doesn't necessarily need to be a resolvable (real) property editor }, new ContentPropertyDisplay From 50aa9d714456bf029298ee4dc21d1a8dd90ea596 Mon Sep 17 00:00:00 2001 From: Shannon Date: Mon, 12 Aug 2013 18:09:16 +1000 Subject: [PATCH 10/10] Adds more functionality to prop editors to be able to flag the value editor as readonly so no bound values will be persisted (ie. for the label property editor) --- src/Umbraco.Core/ObjectExtensions.cs | 2 +- .../PropertyEditors/ValueEditor.cs | 8 ++++++++ .../readonlyvalue/readonlyvalue.controller.js | 8 +++++++- .../Editors/ContentControllerBase.cs | 10 +++++++++- .../PropertyEditors/LabelPropertyEditor.cs | 15 ++++++++++++++- .../PropertyEditors/LabelValueEditor.cs | 18 ++++++++++++++++++ src/Umbraco.Web/Umbraco.Web.csproj | 1 + 7 files changed, 58 insertions(+), 4 deletions(-) create mode 100644 src/Umbraco.Web/PropertyEditors/LabelValueEditor.cs diff --git a/src/Umbraco.Core/ObjectExtensions.cs b/src/Umbraco.Core/ObjectExtensions.cs index c852111f9f..5f5e41b1ef 100644 --- a/src/Umbraco.Core/ObjectExtensions.cs +++ b/src/Umbraco.Core/ObjectExtensions.cs @@ -367,7 +367,7 @@ namespace Umbraco.Core /// internal static string ToXmlString(this object value, Type type) { - if (type == typeof(string)) return ((string)value).IsNullOrWhiteSpace() ? "" : (string)value; + if (type == typeof(string)) return (value.ToString().IsNullOrWhiteSpace() ? "" : value.ToString()); if (type == typeof(bool)) return XmlConvert.ToString((bool)value); if (type == typeof(byte)) return XmlConvert.ToString((byte)value); if (type == typeof(char)) return XmlConvert.ToString((char)value); diff --git a/src/Umbraco.Core/PropertyEditors/ValueEditor.cs b/src/Umbraco.Core/PropertyEditors/ValueEditor.cs index 258444ba69..c0d1aa39ec 100644 --- a/src/Umbraco.Core/PropertyEditors/ValueEditor.cs +++ b/src/Umbraco.Core/PropertyEditors/ValueEditor.cs @@ -102,6 +102,14 @@ namespace Umbraco.Core.PropertyEditors } } + /// + /// Set this to true if the property editor is for display purposes only + /// + public virtual bool IsReadOnly + { + get { return false; } + } + /// /// Used to try to convert the string value to the correct CLR type based on the DatabaseDataType specified for this value editor /// diff --git a/src/Umbraco.Web.UI.Client/src/views/propertyeditors/readonlyvalue/readonlyvalue.controller.js b/src/Umbraco.Web.UI.Client/src/views/propertyeditors/readonlyvalue/readonlyvalue.controller.js index de258e25fb..e09b1fcc76 100644 --- a/src/Umbraco.Web.UI.Client/src/views/propertyeditors/readonlyvalue/readonlyvalue.controller.js +++ b/src/Umbraco.Web.UI.Client/src/views/propertyeditors/readonlyvalue/readonlyvalue.controller.js @@ -1,7 +1,13 @@ angular.module('umbraco').controller("Umbraco.Editors.ReadOnlyValueController", function($rootScope, $scope, $filter){ - if ($scope.model.config && $scope.model.config.filter) { + if ($scope.model.config && + angular.isArray($scope.model.config) && + $scope.model.config.length > 0 && + $scope.model.config[0] && + $scope.model.config.filter) + { + if ($scope.model.config.format) { $scope.displayvalue = $filter($scope.model.config.filter)($scope.model.value, $scope.model.config.format); } diff --git a/src/Umbraco.Web/Editors/ContentControllerBase.cs b/src/Umbraco.Web/Editors/ContentControllerBase.cs index c465edc758..2241105821 100644 --- a/src/Umbraco.Web/Editors/ContentControllerBase.cs +++ b/src/Umbraco.Web/Editors/ContentControllerBase.cs @@ -4,10 +4,12 @@ using System.Linq; using System.Net; using System.Net.Http; using System.Web.Http; +using System.Web.Mvc; using Umbraco.Core; using Umbraco.Core.Logging; using Umbraco.Core.Models; using Umbraco.Core.Models.Editors; +using Umbraco.Core.PropertyEditors; using Umbraco.Web.Models.ContentEditing; using Umbraco.Web.WebApi.Filters; @@ -101,7 +103,13 @@ namespace Umbraco.Web.Editors } else { - dboProperty.Value = p.PropertyEditor.ValueEditor.DeserializeValue(data, dboProperty.Value); + var valueEditor = p.PropertyEditor.ValueEditor; + //don't persist any bound value if the editor is readonly + if (valueEditor.IsReadOnly == false) + { + dboProperty.Value = p.PropertyEditor.ValueEditor.DeserializeValue(data, dboProperty.Value); + } + } } } diff --git a/src/Umbraco.Web/PropertyEditors/LabelPropertyEditor.cs b/src/Umbraco.Web/PropertyEditors/LabelPropertyEditor.cs index b4122573c4..53c5ee94ad 100644 --- a/src/Umbraco.Web/PropertyEditors/LabelPropertyEditor.cs +++ b/src/Umbraco.Web/PropertyEditors/LabelPropertyEditor.cs @@ -1,4 +1,6 @@ -using Umbraco.Core; +using System.ComponentModel; +using System.Web.Mvc; +using Umbraco.Core; using Umbraco.Core.PropertyEditors; namespace Umbraco.Web.PropertyEditors @@ -6,5 +8,16 @@ namespace Umbraco.Web.PropertyEditors [PropertyEditor(Constants.PropertyEditors.NoEdit, "Label", "readonlyvalue")] public class LabelPropertyEditor : PropertyEditor { + + protected override ValueEditor CreateValueEditor() + { + var baseEditor = base.CreateValueEditor(); + + return new LabelValueEditor + { + View = baseEditor.View + }; + } + } } \ No newline at end of file diff --git a/src/Umbraco.Web/PropertyEditors/LabelValueEditor.cs b/src/Umbraco.Web/PropertyEditors/LabelValueEditor.cs new file mode 100644 index 0000000000..2e514c4463 --- /dev/null +++ b/src/Umbraco.Web/PropertyEditors/LabelValueEditor.cs @@ -0,0 +1,18 @@ +using Umbraco.Core.PropertyEditors; + +namespace Umbraco.Web.PropertyEditors +{ + /// + /// Custom value editor to mark it as readonly + /// + internal class LabelValueEditor : ValueEditor + { + /// + /// This editor is for display purposes only, any values bound to it will not be saved back to the database + /// + public override bool IsReadOnly + { + get { return true; } + } + } +} \ No newline at end of file diff --git a/src/Umbraco.Web/Umbraco.Web.csproj b/src/Umbraco.Web/Umbraco.Web.csproj index c75d8fe75f..9c34f2c0ff 100644 --- a/src/Umbraco.Web/Umbraco.Web.csproj +++ b/src/Umbraco.Web/Umbraco.Web.csproj @@ -301,6 +301,7 @@ +