Getting some work towards being able to edit content types in to share the fun.

- includes changing settings from IDictionary<string, string> to SettingsDictionary : IDictionary<string, string> w/ GetModel<T>
- also cleaned up content type creation a little

--HG--
branch : dev
This commit is contained in:
Nathan Heskew 2010-06-22 03:36:04 -07:00
parent d126bc9f3d
commit ab81cda4eb
30 changed files with 372 additions and 88 deletions

View File

@ -16,7 +16,6 @@ using Orchard.ContentManagement.Records;
using Orchard.Localization; using Orchard.Localization;
using Orchard.Security; using Orchard.Security;
using Orchard.Tests.Modules; using Orchard.Tests.Modules;
using Orchard.Mvc.ViewModels;
using Orchard.Core.Common.ViewModels; using Orchard.Core.Common.ViewModels;
using System.Web.Mvc; using System.Web.Mvc;

View File

@ -1,7 +1,4 @@
using System; using System.Linq;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml.Linq; using System.Xml.Linq;
using NUnit.Framework; using NUnit.Framework;
using Orchard.ContentManagement.MetaData; using Orchard.ContentManagement.MetaData;

View File

@ -1,11 +1,10 @@
using System.Collections.Generic; using Orchard.ContentManagement;
using Orchard.ContentManagement;
using Orchard.ContentManagement.MetaData.Models; using Orchard.ContentManagement.MetaData.Models;
namespace Orchard.Tests.ContentManagement.Models { namespace Orchard.Tests.ContentManagement.Models {
public class Phi : ContentField { public class Phi : ContentField {
public Phi() { public Phi() {
PartFieldDefinition = new ContentPartDefinition.Field(new ContentFieldDefinition("Phi"), "Phi", new Dictionary<string, string>()); PartFieldDefinition = new ContentPartDefinition.Field(new ContentFieldDefinition("Phi"), "Phi", new SettingsDictionary());
} }
} }
} }

View File

@ -1,10 +0,0 @@
using System.ComponentModel.DataAnnotations;
namespace Orchard.Core.Contents {
public class ContentTypeDefinitionStub {
[StringLength(128)]
public string Name { get; set; }
[Required, StringLength(1024)]
public string DisplayName { get; set; }
}
}

View File

@ -3,12 +3,13 @@ using System.Linq;
using System.Web.Mvc; using System.Web.Mvc;
using System.Web.Routing; using System.Web.Routing;
using Orchard.ContentManagement; using Orchard.ContentManagement;
using Orchard.ContentManagement.MetaData; using Orchard.ContentManagement.MetaData.Models;
using Orchard.Core.Contents.Services; using Orchard.Core.Contents.Services;
using Orchard.Core.Contents.ViewModels; using Orchard.Core.Contents.ViewModels;
using Orchard.Data; using Orchard.Data;
using Orchard.Localization; using Orchard.Localization;
using Orchard.Logging; using Orchard.Logging;
using Orchard.Mvc.Results;
using Orchard.Mvc.ViewModels; using Orchard.Mvc.ViewModels;
using Orchard.UI.Notify; using Orchard.UI.Notify;
@ -51,19 +52,19 @@ namespace Orchard.Core.Contents.Controllers {
}); });
} }
public ActionResult CreateType(CreateTypeViewModel viewModel) { public ActionResult CreateType() {
if (!Services.Authorizer.Authorize(Permissions.CreateContentType, T("Not allowed to create a content type."))) if (!Services.Authorizer.Authorize(Permissions.CreateContentTypes, T("Not allowed to create a content type.")))
return new HttpUnauthorizedResult(); return new HttpUnauthorizedResult();
return View(viewModel); return View(new CreateTypeViewModel());
} }
[HttpPost, ActionName("CreateType")] [HttpPost, ActionName("CreateType")]
public ActionResult CreateTypePOST(CreateTypeViewModel viewModel) { public ActionResult CreateTypePOST(CreateTypeViewModel viewModel) {
if (!Services.Authorizer.Authorize(Permissions.CreateContentType, T("Not allowed to create a content type."))) if (!Services.Authorizer.Authorize(Permissions.CreateContentTypes, T("Not allowed to create a content type.")))
return new HttpUnauthorizedResult(); return new HttpUnauthorizedResult();
var model = new ContentTypeDefinitionStub(); var model = new ContentTypeDefinition("");
TryUpdateModel(model); TryUpdateModel(model);
if (!ModelState.IsValid) { if (!ModelState.IsValid) {
@ -76,9 +77,69 @@ namespace Orchard.Core.Contents.Controllers {
return RedirectToAction("Index"); return RedirectToAction("Index");
} }
public ActionResult EditType(string id) {
if (!Services.Authorizer.Authorize(Permissions.CreateContentTypes, T("Not allowed to edit a content type.")))
return new HttpUnauthorizedResult();
var contentTypeDefinition = _contentDefinitionService.GetTypeDefinition(id);
if (contentTypeDefinition == null)
return new NotFoundResult();
return View(new EditTypeViewModel(contentTypeDefinition));
}
[HttpPost, ActionName("EditType")]
public ActionResult EditTypePOST(string id) {
if (!Services.Authorizer.Authorize(Permissions.CreateContentTypes, T("Not allowed to edit a content type.")))
return new HttpUnauthorizedResult();
var contentTypeDefinition = _contentDefinitionService.GetTypeDefinition(id);
if (contentTypeDefinition == null)
return new NotFoundResult();
var viewModel = new EditTypeViewModel();
TryUpdateModel(viewModel);
if (!ModelState.IsValid) {
return EditType(id);
}
//todo: apply the changes along the lines of but definately not resembling
// for now this _might_ just get a little messy ->
_contentDefinitionService.AlterTypeDefinition(
new ContentTypeDefinition(
viewModel.Name,
viewModel.DisplayName,
viewModel.Parts.Select(
p => new ContentTypeDefinition.Part(
new ContentPartDefinition(
p.PartDefinition.Name,
p.PartDefinition.Fields.Select(
f => new ContentPartDefinition.Field(
new ContentFieldDefinition(f.FieldDefinition.Name),
f.Name,
f.Settings
)
),
p.PartDefinition.Settings
),
p.Settings
)
),
viewModel.Settings
)
);
// little == lot
return RedirectToAction("Index");
}
#endregion #endregion
#region Content #region Content
#endregion #endregion
public ActionResult List(ListContentsViewModel model) { public ActionResult List(ListContentsViewModel model) {

View File

@ -3,15 +3,17 @@ using Orchard.Security.Permissions;
namespace Orchard.Core.Contents { namespace Orchard.Core.Contents {
public class Permissions : IPermissionProvider { public class Permissions : IPermissionProvider {
public static readonly Permission CreateContentType = new Permission { Name = "CreateContentType", Description = "Create custom content type." }; public static readonly Permission CreateContentTypes = new Permission { Name = "CreateContentTypes", Description = "Create custom content types." };
public static readonly Permission EditContentTypes = new Permission { Name = "EditContentTypes", Description = "Edit content types." };
public string ModuleName { public string ModuleName {
get { return "Contents"; } get { return "Contents"; }
} }
public IEnumerable<Permission> GetPermissions() { public IEnumerable<Permission> GetPermissions() {
return new Permission[] { return new [] {
CreateContentType, CreateContentTypes,
EditContentTypes,
}; };
} }
@ -19,7 +21,7 @@ namespace Orchard.Core.Contents {
return new[] { return new[] {
new PermissionStereotype { new PermissionStereotype {
Name = "Administrator", Name = "Administrator",
Permissions = new[] {CreateContentType} Permissions = GetPermissions()
} }
}; };
} }

View File

@ -25,25 +25,30 @@ namespace Orchard.Core.Contents.Services {
} }
public ContentTypeDefinition GetTypeDefinition(string name) { public ContentTypeDefinition GetTypeDefinition(string name) {
throw new NotImplementedException(); return _contentDefinitionManager.GetTypeDefinition(name);
} }
public void AddTypeDefinition(ContentTypeDefinitionStub definitionStub) { public void AddTypeDefinition(ContentTypeDefinition contentTypeDefinition) {
if (string.IsNullOrWhiteSpace(definitionStub.Name)) var typeName = string.IsNullOrWhiteSpace(contentTypeDefinition.Name)
definitionStub.Name = GenerateTypeName(definitionStub.DisplayName); ? GenerateTypeName(contentTypeDefinition.DisplayName)
: contentTypeDefinition.Name;
while (_contentDefinitionManager.GetTypeDefinition(definitionStub.Name) != null) while (_contentDefinitionManager.GetTypeDefinition(typeName) != null)
definitionStub.Name = VersionTypeName(definitionStub.Name); typeName = VersionTypeName(typeName);
//just giving the new type some default parts for now //just giving the new type some default parts for now
_contentDefinitionManager.AlterTypeDefinition( _contentDefinitionManager.AlterTypeDefinition(
definitionStub.Name, typeName,
cfg => cfg.Named(definitionStub.Name, definitionStub.DisplayName) cfg => cfg.Named(typeName, contentTypeDefinition.DisplayName)
.WithPart("CommonAspect") .WithPart("CommonAspect")
//.WithPart("RoutableAspect") //need to go the new routable route //.WithPart("RoutableAspect") //need to go the new routable route
.WithPart("BodyAspect")); .WithPart("BodyAspect"));
Services.Notifier.Information(T("Created content type: {0}", definitionStub.DisplayName)); Services.Notifier.Information(T("Created content type: {0}", contentTypeDefinition.DisplayName));
}
public void AlterTypeDefinition(ContentTypeDefinition contentTypeDefinition) {
_contentDefinitionManager.StoreTypeDefinition(contentTypeDefinition);
} }
public void RemoveTypeDefinition(string name) { public void RemoveTypeDefinition(string name) {
@ -69,7 +74,7 @@ namespace Orchard.Core.Contents.Services {
} }
private static string VersionTypeName(string name) { private static string VersionTypeName(string name) {
var version = 2; int version;
var nameParts = name.Split(new[] { '-' }, StringSplitOptions.RemoveEmptyEntries); var nameParts = name.Split(new[] { '-' }, StringSplitOptions.RemoveEmptyEntries);
if (nameParts.Length > 1 && int.TryParse(nameParts.Last(), out version)) { if (nameParts.Length > 1 && int.TryParse(nameParts.Last(), out version)) {
@ -77,6 +82,9 @@ namespace Orchard.Core.Contents.Services {
//this could unintentionally chomp something that looks like a version //this could unintentionally chomp something that looks like a version
name = string.Join("-", nameParts.Take(nameParts.Length - 1)); name = string.Join("-", nameParts.Take(nameParts.Length - 1));
} }
else {
version = 2;
}
return string.Format("{0}-{1}", name, version); return string.Format("{0}-{1}", name, version);
} }

View File

@ -5,7 +5,8 @@ namespace Orchard.Core.Contents.Services {
public interface IContentDefinitionService : IDependency { public interface IContentDefinitionService : IDependency {
IEnumerable<ContentTypeDefinition> GetTypeDefinitions(); IEnumerable<ContentTypeDefinition> GetTypeDefinitions();
ContentTypeDefinition GetTypeDefinition(string name); ContentTypeDefinition GetTypeDefinition(string name);
void AddTypeDefinition(ContentTypeDefinitionStub contentTypeDefinition); void AddTypeDefinition(ContentTypeDefinition contentTypeDefinition);
void AlterTypeDefinition(ContentTypeDefinition contentTypeDefinition);
void RemoveTypeDefinition(string name); void RemoveTypeDefinition(string name);
} }
} }

View File

@ -0,0 +1,6 @@
.contents #main h2 {
margin:1.5em 0 .5em;
}
.manage.add-to-type {
margin-top:-4em;
}

View File

@ -0,0 +1,77 @@
using System.Collections.Generic;
using System.Linq;
using Orchard.ContentManagement.MetaData.Models;
using Orchard.Mvc.ViewModels;
namespace Orchard.Core.Contents.ViewModels {
public class EditTypeViewModel : BaseViewModel {
public EditTypeViewModel() {
Settings = new SettingsDictionary();
Parts = new List<EditTypePartViewModel>();
}
public EditTypeViewModel(ContentTypeDefinition contentTypeDefinition) {
Name = contentTypeDefinition.Name;
DisplayName = contentTypeDefinition.DisplayName;
Settings = contentTypeDefinition.Settings;
Parts = contentTypeDefinition.Parts.Select(p => new EditTypePartViewModel(p));
}
public string Name { get; set; }
public string DisplayName { get; set; }
public SettingsDictionary Settings { get; set; }
public IEnumerable<EditTypePartViewModel> Parts { get; set; }
}
public class EditTypePartViewModel {
public EditTypePartViewModel() {
Settings = new SettingsDictionary();
}
public EditTypePartViewModel(ContentTypeDefinition.Part part) {
PartDefinition = new EditPartViewModel(part.PartDefinition);
Settings = part.Settings;
}
public EditPartViewModel PartDefinition { get; set; }
public SettingsDictionary Settings { get; set; }
}
public class EditPartViewModel {
public EditPartViewModel() {
Fields = new List<EditPartFieldViewModel>();
Settings = new SettingsDictionary();
}
public EditPartViewModel(ContentPartDefinition contentPartDefinition) {
Name = contentPartDefinition.Name;
Fields = contentPartDefinition.Fields.Select(f => new EditPartFieldViewModel(f));
Settings = contentPartDefinition.Settings;
}
public string Name { get; set; }
public IEnumerable<EditPartFieldViewModel> Fields { get; set; }
public SettingsDictionary Settings { get; set; }
}
public class EditPartFieldViewModel {
public EditPartFieldViewModel() {
Settings = new SettingsDictionary();
}
public EditPartFieldViewModel(ContentPartDefinition.Field field) {
Name = field.Name;
FieldDefinition = new EditFieldViewModel(field.FieldDefinition);
Settings = field.Settings;
}
public string Name { get; set; }
public EditFieldViewModel FieldDefinition { get; set; }
public SettingsDictionary Settings { get; set; }
}
public class EditFieldViewModel {
public EditFieldViewModel() { }
public EditFieldViewModel(ContentFieldDefinition contentFieldDefinition) {
Name = Name;
}
public string Name { get; set; }
}
}

View File

@ -0,0 +1,23 @@
<%@ Control Language="C#" Inherits="Orchard.Mvc.ViewUserControl<EditTypeViewModel>" %>
<%@ Import Namespace="Orchard.Core.Contents.ViewModels" %><%
Html.RegisterStyle("admin.css"); %>
<h1><%:Html.TitleForPage(T("Edit Content Type").ToString())%></h1><%
using (Html.BeginFormAntiForgeryPost()) { %>
<%:Html.ValidationSummary() %>
<fieldset>
<label for="DisplayName"><%:T("Display Name") %></label>
<%:Html.TextBoxFor(m => m.DisplayName, new {@class = "textMedium"}) %>
<label for="Name"><%:T("Name") %></label>
<%:Html.TextBoxFor(m => m.Name, new {@class = "textMedium"}) %>
</fieldset>
<%:Html.EditorFor(m => m.Settings) %>
<h2><%:T("Parts") %></h2>
<div class="manage add-to-type"><%: Html.ActionLink(T("Add").Text, "AddPart", new { }, new { @class = "button" })%></div>
<%:Html.EditorFor(m => m.Parts, "Parts", "") %>
<h2><%:T("Fields") %></h2>
<div class="manage add-to-type"><%: Html.ActionLink(T("Add").Text, "AddField", new { }, new { @class = "button" })%></div>
<%--<%:Html.EditorFor(m => m.Fields, "ContentTypeFields")%>--%>
<fieldset>
<button class="primaryAction" type="submit"><%:T("Save") %></button>
</fieldset><%
} %>

View File

@ -6,7 +6,7 @@
</div> </div>
<div class="related"> <div class="related">
<%:Html.ActionLink(T("List Items").ToString(), "List", new {area = "Contents", id = Model.Name})%><%:T(" | ")%> <%:Html.ActionLink(T("List Items").ToString(), "List", new {area = "Contents", id = Model.Name})%><%:T(" | ")%>
<%:Html.ActionLink(T("[Edit]").ToString(), "EditType", new {area = "Contents", id = Model.Name})%><%:T(" | ") %> <%:Html.ActionLink(T("Edit").ToString(), "EditType", new {area = "Contents", id = Model.Name})%><%:T(" | ") %>
<% using (Html.BeginFormAntiForgeryPost(Url.Action("RemoveType", new {area = "Contents", id = Model.Name}), FormMethod.Post, new { @class = "inline link" })) { %> <% using (Html.BeginFormAntiForgeryPost(Url.Action("RemoveType", new {area = "Contents", id = Model.Name}), FormMethod.Post, new { @class = "inline link" })) { %>
<button type="submit" class="linkButton" title="<%:T("Delete") %>"><%:T("[Delete]")%></button><% <button type="submit" class="linkButton" title="<%:T("Delete") %>"><%:T("[Delete]")%></button><%
} %> } %>

View File

@ -0,0 +1,13 @@
<%@ Control Language="C#" Inherits="Orchard.Mvc.ViewUserControl<ContentTypeDefinition.Part>" %>
<%@ Import Namespace="Orchard.ContentManagement.MetaData.Models" %>
<fieldset>
<h3><%:Model.PartDefinition.Name %></h3>
<div class="manage add-to-type">
<%--// these inline forms can't be here. should probably have some JavaScript in here to build up the forms and add the "remove" link.
// get the antiforgery token from the edit type form and mark up the part in a semantic way so I can get some info from the DOM --%>
<% using (Html.BeginFormAntiForgeryPost(Url.Action("RemovePart", new { area = "Contents" }), FormMethod.Post, new {@class = "inline link"})) { %>
<%=Html.Hidden("name", Model.PartDefinition.Name, new { id = "" }) %>
<button type="submit" title="<%:T("Remove") %>"><%:T("Remove") %></button>
<% } %>
</div>
</fieldset>

View File

@ -0,0 +1,14 @@
<%@ Control Language="C#" Inherits="Orchard.Mvc.ViewUserControl<ContentPartDefinition.Field>" %>
<%@ Import Namespace="Orchard.ContentManagement.MetaData.Models" %>
<fieldset>
<h3><%:Model.FieldDefinition.Name %></h3>
<div class="manage add-to-type">
<%--// these inline forms can't be here. should probably have some JavaScript in here to build up the forms and add the "remove" link.
// get the antiforgery token from the edit type form and mark up the part in a semantic way so I can get some info from the DOM --%>
<%:Html.Link("[remove]", "#forshowonlyandnotintendedtowork!") %>
<%-- <% using (Html.BeginFormAntiForgeryPost(Url.Action("RemovePart", new { area = "Contents" }), FormMethod.Post, new {@class = "inline link"})) { %>
<%=Html.Hidden("name", Model.PartDefinition.Name, new { id = "" }) %>
<button type="submit" title="<%:T("Remove") %>"><%:T("Remove") %></button>
<% } %> --%>
</div>
</fieldset>

View File

@ -0,0 +1,10 @@
<%@ Control Language="C#" Inherits="Orchard.Mvc.ViewUserControl<IEnumerable<EditPartFieldViewModel>>" %>
<%@ Import Namespace="Orchard.Core.Contents.ViewModels" %><%
if (Model.Any()) { %>
<fieldset><%
foreach (var field in Model) {
var f = field; %>
<%:Html.EditorFor(m => f, "FieldOnPart") %><%
} %>
</fieldset><%
} %>

View File

@ -0,0 +1,21 @@
<%@ Control Language="C#" Inherits="Orchard.Mvc.ViewUserControl<EditTypePartViewModel>" %>
<%@ Import Namespace="Orchard.Core.Contents.ViewModels" %>
<fieldset>
<h3><%:Model.PartDefinition.Name %></h3>
<div class="manage add-to-type">
<%--// these inline forms can't be here. should probably have some JavaScript in here to build up the forms and add the "remove" link.
// get the antiforgery token from the edit type form and mark up the part in a semantic way so I can get some info from the DOM --%>
<%:Html.Link("[remove]", "#forshowonlyandnotintendedtowork") %>
<%-- <% using (Html.BeginFormAntiForgeryPost(Url.Action("RemovePart", new { area = "Contents" }), FormMethod.Post, new {@class = "inline link"})) { %>
<%:Html.Hidden("name", Model.PartDefinition.Name, new { id = "" }) %>
<button type="submit" title="<%:T("Remove") %>"><%:T("Remove") %></button>
<% } %> --%>
</div>
<%--
what is this settings for?
<%:Html.EditorFor(m => m.PartDefinition.Settings, "Settings") %>--%>
<%:Html.EditorFor(m => m.Settings, "Settings", "") %>
<%:Html.EditorFor(m => m.PartDefinition.Fields, "FieldsOnPart") %>
<%:Html.Hidden("PartDefinition.Name", Model.PartDefinition.Name) %>
<%:Html.Hidden("PartDefinition.Name", Model.PartDefinition.Name) %>
</fieldset>

View File

@ -0,0 +1,12 @@
<%@ Control Language="C#" Inherits="Orchard.Mvc.ViewUserControl<IEnumerable<EditTypePartViewModel>>" %>
<%@ Import Namespace="Orchard.Core.Contents.ViewModels" %><%
if (Model.Any()) { %>
<fieldset><%
var pi = 0;
foreach (var part in Model) {
var p = part;
var htmlFieldName = string.Format("Parts[{0}]", pi++); %>
<%:Html.EditorFor(m => p, "Part", htmlFieldName) %><%
} %>
</fieldset><%
} %>

View File

@ -0,0 +1,14 @@
<%@ Control Language="C#" Inherits="Orchard.Mvc.ViewUserControl<Orchard.ContentManagement.MetaData.Models.SettingsDictionary>" %><%
if (Model.Any()) { %>
<fieldset><%
var si = 0;
foreach (var setting in Model) {
var s = setting;
var htmlFieldName = string.Format("Settings[{0}]", si++); %>
<%--// doesn't gen a similarly sanitized id as the other inputs...--%>
<label for="<%:ViewData.TemplateInfo.GetFullHtmlFieldId(htmlFieldName + ".Value") %>"><%:s.Key %></label>
<%:Html.Hidden(htmlFieldName + ".Key", s.Key) %>
<%:Html.TextBox(htmlFieldName + ".Value", s.Value)%><%
} %>
</fieldset><%
} %>

View File

@ -72,12 +72,12 @@
<Compile Include="Common\ViewModels\ContainerEditorViewModel.cs" /> <Compile Include="Common\ViewModels\ContainerEditorViewModel.cs" />
<Compile Include="Common\ViewModels\TextContentFieldDisplayViewModel.cs" /> <Compile Include="Common\ViewModels\TextContentFieldDisplayViewModel.cs" />
<Compile Include="Common\ViewModels\TextContentFieldEditorViewModel.cs" /> <Compile Include="Common\ViewModels\TextContentFieldEditorViewModel.cs" />
<Compile Include="Contents\ContentTypeDefinitionStub.cs" />
<Compile Include="Contents\Controllers\ItemController.cs" /> <Compile Include="Contents\Controllers\ItemController.cs" />
<Compile Include="Contents\Handlers\ContentsModuleHandler.cs" /> <Compile Include="Contents\Handlers\ContentsModuleHandler.cs" />
<Compile Include="Contents\Permissions.cs" /> <Compile Include="Contents\Permissions.cs" />
<Compile Include="Contents\Services\ContentDefinitionService.cs" /> <Compile Include="Contents\Services\ContentDefinitionService.cs" />
<Compile Include="Contents\Services\IContentDefinitionService.cs" /> <Compile Include="Contents\Services\IContentDefinitionService.cs" />
<Compile Include="Contents\ViewModels\EditTypeViewModel.cs" />
<Compile Include="Contents\ViewModels\CreateTypeViewModel.cs" /> <Compile Include="Contents\ViewModels\CreateTypeViewModel.cs" />
<Compile Include="Contents\ViewModels\ListContentsViewModel.cs" /> <Compile Include="Contents\ViewModels\ListContentsViewModel.cs" />
<Compile Include="Contents\ViewModels\ListContentTypesViewModel.cs" /> <Compile Include="Contents\ViewModels\ListContentTypesViewModel.cs" />
@ -207,6 +207,8 @@
<Content Include="Common\Views\EditorTemplates\Parts\Common.Container.ascx" /> <Content Include="Common\Views\EditorTemplates\Parts\Common.Container.ascx" />
<Content Include="Common\Views\EditorTemplates\Parts\Common.TextContentField.ascx" /> <Content Include="Common\Views\EditorTemplates\Parts\Common.TextContentField.ascx" />
<Content Include="Contents\Module.txt" /> <Content Include="Contents\Module.txt" />
<Content Include="Contents\Styles\admin.css" />
<Content Include="Contents\Views\Admin\EditType.ascx" />
<Content Include="Contents\Views\Admin\CreateType.ascx" /> <Content Include="Contents\Views\Admin\CreateType.ascx" />
<Content Include="Contents\Views\Admin\Types.ascx" /> <Content Include="Contents\Views\Admin\Types.ascx" />
<Content Include="Contents\Views\Admin\List.aspx" /> <Content Include="Contents\Views\Admin\List.aspx" />
@ -215,6 +217,11 @@
<Content Include="Contents\Views\Admin\Create.aspx" /> <Content Include="Contents\Views\Admin\Create.aspx" />
<Content Include="Contents\Views\DisplayTemplates\ContentTypeDefinition.ascx" /> <Content Include="Contents\Views\DisplayTemplates\ContentTypeDefinition.ascx" />
<Content Include="Contents\Views\DisplayTemplates\Items\Contents.Item.ascx" /> <Content Include="Contents\Views\DisplayTemplates\Items\Contents.Item.ascx" />
<Content Include="Contents\Views\EditorTemplates\Settings.ascx" />
<Content Include="Contents\Views\EditorTemplates\FieldsOnPart.ascx" />
<Content Include="Contents\Views\EditorTemplates\FieldOnPart.ascx" />
<Content Include="Contents\Views\EditorTemplates\Parts.ascx" />
<Content Include="Contents\Views\EditorTemplates\Part.ascx" />
<Content Include="Contents\Views\EditorTemplates\Items\Contents.Item.ascx" /> <Content Include="Contents\Views\EditorTemplates\Items\Contents.Item.ascx" />
<Content Include="Contents\Views\Item\Preview.aspx" /> <Content Include="Contents\Views\Item\Preview.aspx" />
<Content Include="Contents\Views\Item\Display.aspx" /> <Content Include="Contents\Views\Item\Display.aspx" />

View File

@ -14,15 +14,15 @@ namespace Orchard.Core.Settings.Metadata {
private readonly IRepository<ContentTypeDefinitionRecord> _typeDefinitionRepository; private readonly IRepository<ContentTypeDefinitionRecord> _typeDefinitionRepository;
private readonly IRepository<ContentPartDefinitionRecord> _partDefinitionRepository; private readonly IRepository<ContentPartDefinitionRecord> _partDefinitionRepository;
private readonly IRepository<ContentFieldDefinitionRecord> _fieldDefinitionRepository; private readonly IRepository<ContentFieldDefinitionRecord> _fieldDefinitionRepository;
private readonly IMapper<XElement, IDictionary<string, string>> _settingsReader; private readonly IMapper<XElement, SettingsDictionary> _settingsReader;
private readonly IMapper<IDictionary<string, string>, XElement> _settingsWriter; private readonly IMapper<SettingsDictionary, XElement> _settingsWriter;
public ContentDefinitionManager( public ContentDefinitionManager(
IRepository<ContentTypeDefinitionRecord> typeDefinitionRepository, IRepository<ContentTypeDefinitionRecord> typeDefinitionRepository,
IRepository<ContentPartDefinitionRecord> partDefinitionRepository, IRepository<ContentPartDefinitionRecord> partDefinitionRepository,
IRepository<ContentFieldDefinitionRecord> fieldDefinitionRepository, IRepository<ContentFieldDefinitionRecord> fieldDefinitionRepository,
IMapper<XElement, IDictionary<string, string>> settingsReader, IMapper<XElement, SettingsDictionary> settingsReader,
IMapper<IDictionary<string, string>, XElement> settingsWriter) { IMapper<SettingsDictionary, XElement> settingsWriter) {
_typeDefinitionRepository = typeDefinitionRepository; _typeDefinitionRepository = typeDefinitionRepository;
_partDefinitionRepository = partDefinitionRepository; _partDefinitionRepository = partDefinitionRepository;
_fieldDefinitionRepository = fieldDefinitionRepository; _fieldDefinitionRepository = fieldDefinitionRepository;

View File

@ -1,5 +1,4 @@
using System.Collections.Generic; using System.Linq;
using System.Linq;
using Orchard.ContentManagement.MetaData.Models; using Orchard.ContentManagement.MetaData.Models;
namespace Orchard.ContentManagement.Handlers { namespace Orchard.ContentManagement.Handlers {
@ -26,7 +25,7 @@ namespace Orchard.ContentManagement.Handlers {
if (typePartDefinition == null) { if (typePartDefinition == null) {
typePartDefinition = new ContentTypeDefinition.Part( typePartDefinition = new ContentTypeDefinition.Part(
new ContentPartDefinition(partName), new ContentPartDefinition(partName),
new Dictionary<string, string>()); new SettingsDictionary());
} }
var part = new TPart { var part = new TPart {

View File

@ -7,7 +7,7 @@ namespace Orchard.ContentManagement.MetaData.Builders {
public class ContentPartDefinitionBuilder { public class ContentPartDefinitionBuilder {
private string _name; private string _name;
private readonly IList<ContentPartDefinition.Field> _fields; private readonly IList<ContentPartDefinition.Field> _fields;
private readonly IDictionary<string, string> _settings; private readonly SettingsDictionary _settings;
public ContentPartDefinitionBuilder() public ContentPartDefinitionBuilder()
: this(new ContentPartDefinition(null)) { : this(new ContentPartDefinition(null)) {
@ -16,12 +16,12 @@ namespace Orchard.ContentManagement.MetaData.Builders {
public ContentPartDefinitionBuilder(ContentPartDefinition existing) { public ContentPartDefinitionBuilder(ContentPartDefinition existing) {
if (existing == null) { if (existing == null) {
_fields = new List<ContentPartDefinition.Field>(); _fields = new List<ContentPartDefinition.Field>();
_settings = new Dictionary<string, string>(); _settings = new SettingsDictionary();
} }
else { else {
_name = existing.Name; _name = existing.Name;
_fields = existing.Fields.ToList(); _fields = existing.Fields.ToList();
_settings = existing.Settings.ToDictionary(kv => kv.Key, kv => kv.Value); _settings = new SettingsDictionary(existing.Settings.ToDictionary(kv => kv.Key, kv => kv.Value));
} }
} }
@ -58,7 +58,7 @@ namespace Orchard.ContentManagement.MetaData.Builders {
_fields.Remove(existingField); _fields.Remove(existingField);
} }
else { else {
existingField = new ContentPartDefinition.Field(fieldDefinition, fieldName, new Dictionary<string, string>()); existingField = new ContentPartDefinition.Field(fieldDefinition, fieldName, new SettingsDictionary());
} }
var configurer = new FieldConfigurerImpl(existingField); var configurer = new FieldConfigurerImpl(existingField);
configuration(configurer); configuration(configurer);
@ -67,10 +67,10 @@ namespace Orchard.ContentManagement.MetaData.Builders {
} }
public abstract class FieldConfigurer { public abstract class FieldConfigurer {
protected readonly IDictionary<string, string> _settings; protected readonly SettingsDictionary _settings;
protected FieldConfigurer(ContentPartDefinition.Field field) { protected FieldConfigurer(ContentPartDefinition.Field field) {
_settings = field.Settings.ToDictionary(kv => kv.Key, kv => kv.Value); _settings = new SettingsDictionary(field.Settings.ToDictionary(kv => kv.Key, kv => kv.Value));
} }
public FieldConfigurer WithSetting(string name, string value) { public FieldConfigurer WithSetting(string name, string value) {

View File

@ -8,7 +8,7 @@ namespace Orchard.ContentManagement.MetaData.Builders {
private string _name; private string _name;
private string _displayName; private string _displayName;
private readonly IList<ContentTypeDefinition.Part> _parts; private readonly IList<ContentTypeDefinition.Part> _parts;
private readonly IDictionary<string, string> _settings; private readonly SettingsDictionary _settings;
public ContentTypeDefinitionBuilder() public ContentTypeDefinitionBuilder()
: this(new ContentTypeDefinition(null)) { : this(new ContentTypeDefinition(null)) {
@ -17,13 +17,13 @@ namespace Orchard.ContentManagement.MetaData.Builders {
public ContentTypeDefinitionBuilder(ContentTypeDefinition existing) { public ContentTypeDefinitionBuilder(ContentTypeDefinition existing) {
if (existing == null) { if (existing == null) {
_parts = new List<ContentTypeDefinition.Part>(); _parts = new List<ContentTypeDefinition.Part>();
_settings = new Dictionary<string, string>(); _settings = new SettingsDictionary();
} }
else { else {
_name = existing.Name; _name = existing.Name;
_displayName = existing.DisplayName; _displayName = existing.DisplayName;
_parts = existing.Parts.ToList(); _parts = existing.Parts.ToList();
_settings = existing.Settings.ToDictionary(kv => kv.Key, kv => kv.Value); _settings = new SettingsDictionary(existing.Settings.ToDictionary(kv => kv.Key, kv => kv.Value));
} }
} }
@ -68,7 +68,7 @@ namespace Orchard.ContentManagement.MetaData.Builders {
_parts.Remove(existingPart); _parts.Remove(existingPart);
} }
else { else {
existingPart = new ContentTypeDefinition.Part(partDefinition, new Dictionary<string, string>()); existingPart = new ContentTypeDefinition.Part(partDefinition, new SettingsDictionary());
} }
var configurer = new PartConfigurerImpl(existingPart); var configurer = new PartConfigurerImpl(existingPart);
configuration(configurer); configuration(configurer);
@ -77,10 +77,10 @@ namespace Orchard.ContentManagement.MetaData.Builders {
} }
public abstract class PartConfigurer { public abstract class PartConfigurer {
protected readonly IDictionary<string, string> _settings; protected readonly SettingsDictionary _settings;
protected PartConfigurer(ContentTypeDefinition.Part part) { protected PartConfigurer(ContentTypeDefinition.Part part) {
_settings = part.Settings.ToDictionary(kv => kv.Key, kv => kv.Value); _settings = new SettingsDictionary(part.Settings.ToDictionary(kv => kv.Key, kv => kv.Value));
} }
public PartConfigurer WithSetting(string name, string value) { public PartConfigurer WithSetting(string name, string value) {

View File

@ -4,7 +4,7 @@ using Orchard.Utility.Extensions;
namespace Orchard.ContentManagement.MetaData.Models { namespace Orchard.ContentManagement.MetaData.Models {
public class ContentPartDefinition { public class ContentPartDefinition {
public ContentPartDefinition(string name, IEnumerable<Field> fields, IDictionary<string, string> settings) { public ContentPartDefinition(string name, IEnumerable<Field> fields, SettingsDictionary settings) {
Name = name; Name = name;
Fields = fields.ToReadOnlyCollection(); Fields = fields.ToReadOnlyCollection();
Settings = settings; Settings = settings;
@ -13,15 +13,15 @@ namespace Orchard.ContentManagement.MetaData.Models {
public ContentPartDefinition(string name) { public ContentPartDefinition(string name) {
Name = name; Name = name;
Fields = Enumerable.Empty<Field>(); Fields = Enumerable.Empty<Field>();
Settings = new Dictionary<string, string>(); Settings = new SettingsDictionary();
} }
public string Name { get; private set; } public string Name { get; private set; }
public IEnumerable<Field> Fields { get; private set; } public IEnumerable<Field> Fields { get; private set; }
public IDictionary<string, string> Settings { get; private set; } public SettingsDictionary Settings { get; private set; }
public class Field { public class Field {
public Field(ContentFieldDefinition contentFieldDefinition, string name, IDictionary<string, string> settings) { public Field(ContentFieldDefinition contentFieldDefinition, string name, SettingsDictionary settings) {
FieldDefinition = contentFieldDefinition; FieldDefinition = contentFieldDefinition;
Name = name; Name = name;
Settings = settings; Settings = settings;
@ -29,7 +29,7 @@ namespace Orchard.ContentManagement.MetaData.Models {
public string Name { get; private set; } public string Name { get; private set; }
public ContentFieldDefinition FieldDefinition { get; private set; } public ContentFieldDefinition FieldDefinition { get; private set; }
public IDictionary<string, string> Settings { get; private set; } public SettingsDictionary Settings { get; private set; }
} }
} }
} }

View File

@ -1,9 +1,10 @@
using System.Collections.Generic; using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.Linq; using System.Linq;
namespace Orchard.ContentManagement.MetaData.Models { namespace Orchard.ContentManagement.MetaData.Models {
public class ContentTypeDefinition { public class ContentTypeDefinition {
public ContentTypeDefinition(string name, string displayName, IEnumerable<Part> parts, IDictionary<string, string> settings) { public ContentTypeDefinition(string name, string displayName, IEnumerable<Part> parts, SettingsDictionary settings) {
Name = name; Name = name;
DisplayName = displayName; DisplayName = displayName;
Parts = parts; Parts = parts;
@ -13,22 +14,29 @@ namespace Orchard.ContentManagement.MetaData.Models {
public ContentTypeDefinition(string name) { public ContentTypeDefinition(string name) {
Name = name; Name = name;
Parts = Enumerable.Empty<Part>(); Parts = Enumerable.Empty<Part>();
Settings = new Dictionary<string, string>(); Settings = new SettingsDictionary();
} }
[StringLength(128)]
public string Name { get; private set; } public string Name { get; private set; }
[Required, StringLength(1024)]
public string DisplayName { get; set; } public string DisplayName { get; set; }
public IEnumerable<Part> Parts { get; private set; } public IEnumerable<Part> Parts { get; private set; }
public IDictionary<string, string> Settings { get; private set; } public SettingsDictionary Settings { get; private set; }
public class Part { public class Part {
public Part(ContentPartDefinition contentPartDefinition, IDictionary<string, string> settings) {
public Part(ContentPartDefinition contentPartDefinition, SettingsDictionary settings) {
PartDefinition = contentPartDefinition; PartDefinition = contentPartDefinition;
Settings = settings; Settings = settings;
} }
public Part() {
Settings = new SettingsDictionary();
}
public ContentPartDefinition PartDefinition { get; private set; } public ContentPartDefinition PartDefinition { get; private set; }
public IDictionary<string, string> Settings { get; private set; } public SettingsDictionary Settings { get; private set; }
} }
} }
} }

View File

@ -0,0 +1,24 @@
using System.Collections.Generic;
using System.Web.Mvc;
namespace Orchard.ContentManagement.MetaData.Models {
public class SettingsDictionary : Dictionary<string, string> {
public SettingsDictionary() {}
public SettingsDictionary(IDictionary<string, string> dictionary) : base(dictionary) {}
public T GetModel<T>() {
return GetModel<T>(null);
}
public T GetModel<T>(string key) {
var binder = new DefaultModelBinder();
var controllerContext = new ControllerContext();
var context = new ModelBindingContext {
ModelMetadata = ModelMetadataProviders.Current.GetMetadataForType(null, typeof (T)),
ModelName = key,
ValueProvider = new DictionaryValueProvider<string>(this, null)
};
return (T) binder.BindModel(controllerContext, context);
}
}
}

View File

@ -1,13 +1,13 @@
using System.Collections.Generic; using System.Xml;
using System.Xml;
using System.Xml.Linq; using System.Xml.Linq;
using Orchard.ContentManagement.MetaData.Builders; using Orchard.ContentManagement.MetaData.Builders;
using Orchard.ContentManagement.MetaData.Models;
namespace Orchard.ContentManagement.MetaData.Services { namespace Orchard.ContentManagement.MetaData.Services {
public class ContentDefinitionReader : IContentDefinitionReader { public class ContentDefinitionReader : IContentDefinitionReader {
private readonly IMapper<XElement, IDictionary<string, string>> _settingsReader; private readonly IMapper<XElement, SettingsDictionary> _settingsReader;
public ContentDefinitionReader(IMapper<XElement, IDictionary<string, string>> settingsReader) { public ContentDefinitionReader(IMapper<XElement, SettingsDictionary> settingsReader) {
_settingsReader = settingsReader; _settingsReader = settingsReader;
} }

View File

@ -1,14 +1,12 @@
using System; using System.Xml;
using System.Collections.Generic;
using System.Xml;
using System.Xml.Linq; using System.Xml.Linq;
using Orchard.ContentManagement.MetaData.Models; using Orchard.ContentManagement.MetaData.Models;
namespace Orchard.ContentManagement.MetaData.Services { namespace Orchard.ContentManagement.MetaData.Services {
public class ContentDefinitionWriter : IContentDefinitionWriter { public class ContentDefinitionWriter : IContentDefinitionWriter {
private readonly IMapper<IDictionary<string, string>, XElement> _settingsWriter; private readonly IMapper<SettingsDictionary, XElement> _settingsWriter;
public ContentDefinitionWriter(IMapper<IDictionary<string, string>, XElement> settingsWriter) { public ContentDefinitionWriter(IMapper<SettingsDictionary, XElement> settingsWriter) {
_settingsWriter = settingsWriter; _settingsWriter = settingsWriter;
} }
@ -31,7 +29,7 @@ namespace Orchard.ContentManagement.MetaData.Services {
return partElement; return partElement;
} }
private XElement NewElement(string name, IDictionary<string, string> settings) { private XElement NewElement(string name, SettingsDictionary settings) {
var element = new XElement(XmlConvert.EncodeLocalName(name)); var element = new XElement(XmlConvert.EncodeLocalName(name));
foreach(var settingAttribute in _settingsWriter.Map(settings).Attributes()) { foreach(var settingAttribute in _settingsWriter.Map(settings).Attributes()) {
element.Add(settingAttribute); element.Add(settingAttribute);

View File

@ -1,21 +1,21 @@
using System.Collections.Generic; using System.Linq;
using System.Linq;
using System.Xml; using System.Xml;
using System.Xml.Linq; using System.Xml.Linq;
using Orchard.ContentManagement.MetaData.Models;
namespace Orchard.ContentManagement.MetaData.Services { namespace Orchard.ContentManagement.MetaData.Services {
public class SettingsFormatter : public class SettingsFormatter :
IMapper<XElement, IDictionary<string, string>>, IMapper<XElement, SettingsDictionary>,
IMapper<IDictionary<string, string>, XElement> { IMapper<SettingsDictionary, XElement> {
public IDictionary<string, string> Map(XElement source) { public SettingsDictionary Map(XElement source) {
if (source == null) if (source == null)
return new Dictionary<string, string>(); return new SettingsDictionary();
return source.Attributes().ToDictionary(attr => XmlConvert.DecodeName(attr.Name.LocalName), attr => attr.Value); return new SettingsDictionary(source.Attributes().ToDictionary(attr => XmlConvert.DecodeName(attr.Name.LocalName), attr => attr.Value));
} }
public XElement Map(IDictionary<string, string> source) { public XElement Map(SettingsDictionary source) {
if (source == null) if (source == null)
return new XElement("settings"); return new XElement("settings");

View File

@ -305,6 +305,7 @@
<Compile Include="ContentManagement\MetaData\ContentPartInfo.cs"> <Compile Include="ContentManagement\MetaData\ContentPartInfo.cs">
<SubType>Code</SubType> <SubType>Code</SubType>
</Compile> </Compile>
<Compile Include="ContentManagement\MetaData\Models\SettingsDictionary.cs" />
<Compile Include="ContentManagement\MetaData\Services\ContentDefinitionWriter.cs" /> <Compile Include="ContentManagement\MetaData\Services\ContentDefinitionWriter.cs" />
<Compile Include="ContentManagement\MetaData\IContentDefinitionManager.cs" /> <Compile Include="ContentManagement\MetaData\IContentDefinitionManager.cs" />
<Compile Include="ContentManagement\MetaData\IContentDefinitionReader.cs" /> <Compile Include="ContentManagement\MetaData\IContentDefinitionReader.cs" />