diff --git a/.hgsubstate b/.hgsubstate index 9325fa618..3486e5808 100644 --- a/.hgsubstate +++ b/.hgsubstate @@ -1,5 +1,5 @@ ec573e5476f7e8a5a61593d6393e9985e9484fcc src/Orchard.Web/Modules/Orchard.Forms -d4e8bde4741a16cb341311395b211fcf211d2808 src/Orchard.Web/Modules/Orchard.Projections +0d1100754d594a2977eaab40630f1c46a9e8cf2c src/Orchard.Web/Modules/Orchard.Projections 01b83c05050bb731d9f69256bbe8884d458ea1c9 src/Orchard.Web/Modules/Orchard.Rules 65057c6a5cd71f7994ba9bcbeece50dbb737620e src/Orchard.Web/Modules/Orchard.TaskLease 460f08a0d0befd36a3f7e974d8b782ae3df747e7 src/Orchard.Web/Modules/Orchard.Tokens diff --git a/src/Orchard.Web/Core/Common/Views/Fields.Common.Text.cshtml b/src/Orchard.Web/Core/Common/Views/Fields.Common.Text.cshtml index 4cf10f9d6..c0bab8363 100644 --- a/src/Orchard.Web/Core/Common/Views/Fields.Common.Text.cshtml +++ b/src/Orchard.Web/Core/Common/Views/Fields.Common.Text.cshtml @@ -1,8 +1,7 @@ -@using Orchard.Utility.Extensions; -@{ - string name = Model.Name; +@{ + string name = Model.Field.DisplayName; string value = Model.Value; } @if (HasText(name) && HasText(value)) { -

@name.CamelFriendly(): @value

+

@name: @value

} \ No newline at end of file diff --git a/src/Orchard.Web/Core/Routable/Services/RoutableService.cs b/src/Orchard.Web/Core/Routable/Services/RoutableService.cs index 80c302e36..7f537098f 100644 --- a/src/Orchard.Web/Core/Routable/Services/RoutableService.cs +++ b/src/Orchard.Web/Core/Routable/Services/RoutableService.cs @@ -1,14 +1,13 @@ using System; using System.Collections.Generic; -using System.Globalization; using System.Linq; -using System.Text; using System.Text.RegularExpressions; using Orchard.ContentManagement; using Orchard.ContentManagement.Aspects; using Orchard.Core.Common.Models; using Orchard.Core.Routable.Events; using Orchard.Core.Routable.Models; +using Orchard.Utility.Extensions; namespace Orchard.Core.Routable.Services { public class RoutableService : IRoutableService { @@ -51,20 +50,6 @@ namespace Orchard.Core.Routable.Services { } } - public static string RemoveDiacritics(string slug) { - string stFormD = slug.Normalize(NormalizationForm.FormD); - var sb = new StringBuilder(); - - foreach (char t in stFormD) { - UnicodeCategory uc = CharUnicodeInfo.GetUnicodeCategory(t); - if (uc != UnicodeCategory.NonSpacingMark) { - sb.Append(t); - } - } - - return (sb.ToString().Normalize(NormalizationForm.FormC)); - } - public void FillSlugFromTitle(TModel model) where TModel : IRoutableAspect { if ((model.Slug != null && !string.IsNullOrEmpty(model.Slug.Trim())) || string.IsNullOrEmpty(model.Title)) return; @@ -84,7 +69,7 @@ namespace Orchard.Core.Routable.Services { slugContext.Slug = slugContext.Slug.Substring(0, 1000); // dots are not allowed at the begin and the end of routes - slugContext.Slug = RemoveDiacritics(slugContext.Slug.Trim('.').ToLower()); + slugContext.Slug = StringExtensions.RemoveDiacritics(slugContext.Slug.Trim('.').ToLower()); } foreach (ISlugEventHandler slugEventHandler in _slugEventHandlers) { diff --git a/src/Orchard.Web/Modules/Orchard.ContentTypes/Controllers/AdminController.cs b/src/Orchard.Web/Modules/Orchard.ContentTypes/Controllers/AdminController.cs index a6bfaabd9..be8c8e78b 100644 --- a/src/Orchard.Web/Modules/Orchard.ContentTypes/Controllers/AdminController.cs +++ b/src/Orchard.Web/Modules/Orchard.ContentTypes/Controllers/AdminController.cs @@ -10,6 +10,7 @@ using Orchard.Core.Contents.Controllers; using Orchard.Core.Contents.Settings; using Orchard.Localization; using Orchard.UI.Notify; +using Orchard.Utility.Extensions; namespace Orchard.ContentTypes.Controllers { public class AdminController : Controller, IUpdateModel { @@ -63,7 +64,7 @@ namespace Orchard.ContentTypes.Controllers { ModelState.AddModelError("Name", T("A type with the same Id already exists.").ToString()); } - if (!String.IsNullOrWhiteSpace(viewModel.Name) && !ContentDefinitionService.IsLetter(viewModel.Name[0])) { + if (!String.IsNullOrWhiteSpace(viewModel.Name) && !viewModel.Name[0].IsLetter()) { ModelState.AddModelError("Name", T("The technical name must start with a letter.").ToString()); } @@ -71,10 +72,6 @@ namespace Orchard.ContentTypes.Controllers { ModelState.AddModelError("DisplayName", T("A type with the same Display Name already exists.").ToString()); } - if (_contentDefinitionService.GetTypes().Any(t => String.Equals(t.Name, viewModel.Name, StringComparison.OrdinalIgnoreCase))) { - ModelState.AddModelError("Name", T("A type with the same Name already exists.").ToString()); - } - if (!ModelState.IsValid) { Services.TransactionManager.Cancel(); return View(viewModel); @@ -97,6 +94,10 @@ namespace Orchard.ContentTypes.Controllers { return Json(_contentDefinitionService.GenerateContentTypeNameFromDisplayName(displayName)); } + public ActionResult FieldName(string partName, string displayName) { + return Json(_contentDefinitionService.GenerateFieldNameFromDisplayName(partName, displayName)); + } + public ActionResult Edit(string id) { if (!Services.Authorizer.Authorize(Permissions.EditContentTypes, T("Not allowed to edit a content type."))) return new HttpUnauthorizedResult(); @@ -147,7 +148,6 @@ namespace Orchard.ContentTypes.Controllers { return RedirectToAction("List"); } - [HttpPost, ActionName("Edit")] [FormValueRequired("submit.Delete")] public ActionResult Delete(string id) { @@ -371,21 +371,21 @@ namespace Orchard.ContentTypes.Controllers { var viewModel = new AddFieldViewModel { Part = partViewModel, - Fields = _contentDefinitionService.GetFields() + Fields = _contentDefinitionService.GetFields().OrderBy(x => x.FieldTypeName) }; return View(viewModel); } [HttpPost, ActionName("AddFieldTo")] - public ActionResult AddFieldToPOST(string id) { + public ActionResult AddFieldToPOST(AddFieldViewModel viewModel, string id) { if (!Services.Authorizer.Authorize(Permissions.EditContentTypes, T("Not allowed to edit a content part."))) return new HttpUnauthorizedResult(); var partViewModel = _contentDefinitionService.GetPart(id); var typeViewModel = _contentDefinitionService.GetType(id); if (partViewModel == null) { - //id passed in might be that of a type w/ no implicit field + // id passed in might be that of a type w/ no implicit field if (typeViewModel != null) { partViewModel = new EditPartViewModel {Name = typeViewModel.Name}; _contentDefinitionService.AddPart(new CreatePartViewModel {Name = partViewModel.Name}); @@ -396,34 +396,137 @@ namespace Orchard.ContentTypes.Controllers { } } - var viewModel = new AddFieldViewModel(); - if (!TryUpdateModel(viewModel)) { - Services.TransactionManager.Cancel(); - return AddFieldTo(id); + viewModel.DisplayName = viewModel.DisplayName ?? String.Empty; + viewModel.DisplayName = viewModel.DisplayName.Trim(); + viewModel.Name = viewModel.Name ?? String.Empty; + + if (String.IsNullOrWhiteSpace(viewModel.DisplayName)) { + ModelState.AddModelError("DisplayName", T("The Display Name name can't be empty.").ToString()); } - try { - _contentDefinitionService.AddFieldToPart(viewModel.DisplayName, viewModel.FieldTypeName, partViewModel.Name); + if (String.IsNullOrWhiteSpace(viewModel.Name)) { + ModelState.AddModelError("Name", T("The Technical Name can't be empty.").ToString()); } - catch (Exception ex) { - Services.Notifier.Information(T("The \"{0}\" field was not added. {1}", viewModel.DisplayName, ex.Message)); - Services.TransactionManager.Cancel(); - return AddFieldTo(id); + + if (_contentDefinitionService.GetPart(partViewModel.Name).Fields.Any(t => String.Equals(t.Name.Trim(), viewModel.Name.Trim(), StringComparison.OrdinalIgnoreCase))) { + ModelState.AddModelError("Name", T("A field with the same name already exists.").ToString()); + } + + if (!String.IsNullOrWhiteSpace(viewModel.Name) && !viewModel.Name[0].IsLetter()) { + ModelState.AddModelError("Name", T("The technical name must start with a letter.").ToString()); + } + + if (!String.Equals(viewModel.Name, viewModel.Name.ToSafeName(), StringComparison.OrdinalIgnoreCase)) { + ModelState.AddModelError("Name", T("The technical name contains invalid characters.").ToString()); + } + + if (_contentDefinitionService.GetPart(partViewModel.Name).Fields.Any(t => String.Equals(t.DisplayName.Trim(), Convert.ToString(viewModel.DisplayName).Trim(), StringComparison.OrdinalIgnoreCase))) { + ModelState.AddModelError("DisplayName", T("A field with the same Display Name already exists.").ToString()); } if (!ModelState.IsValid) { + viewModel.Part = partViewModel; + viewModel.Fields = _contentDefinitionService.GetFields(); + + Services.TransactionManager.Cancel(); + + return View(viewModel); + } + + try { + _contentDefinitionService.AddFieldToPart(viewModel.Name, viewModel.FieldTypeName, partViewModel.Name); + } + catch (Exception ex) { + Services.Notifier.Information(T("The \"{0}\" field was not added. {1}", viewModel.Name, ex.Message)); Services.TransactionManager.Cancel(); return AddFieldTo(id); } - Services.Notifier.Information(T("The \"{0}\" field has been added.", viewModel.DisplayName)); + Services.Notifier.Information(T("The \"{0}\" field has been added.", viewModel.Name)); - if (typeViewModel != null) - return RedirectToAction("Edit", new { id }); + if (typeViewModel != null) { + return RedirectToAction("Edit", new {id}); + } return RedirectToAction("EditPart", new { id }); } + public ActionResult EditField(string id, string name) { + if (!Services.Authorizer.Authorize(Permissions.EditContentTypes, T("Not allowed to edit a content type."))) + return new HttpUnauthorizedResult(); + + var partViewModel = _contentDefinitionService.GetPart(id); + + if (partViewModel == null) { + return HttpNotFound(); + } + + var fieldViewModel = partViewModel.Fields.FirstOrDefault(x => x.Name == name); + + if(fieldViewModel == null) { + return HttpNotFound(); + } + + var viewModel = new EditFieldNameViewModel { + Name = fieldViewModel.Name, + DisplayName = fieldViewModel.DisplayName + }; + + return View(viewModel); + } + + [HttpPost, ActionName("EditField")] + [FormValueRequired("submit.Save")] + public ActionResult EditFieldPOST(string id, EditFieldNameViewModel viewModel) { + if (!Services.Authorizer.Authorize(Permissions.EditContentTypes, T("Not allowed to edit a content type."))) + return new HttpUnauthorizedResult(); + + if (viewModel == null) + return HttpNotFound(); + + var partViewModel = _contentDefinitionService.GetPart(id); + + if (partViewModel == null) { + return HttpNotFound(); + } + + // prevent null reference exception in validation + viewModel.DisplayName = viewModel.DisplayName ?? String.Empty; + + // remove extra spaces + viewModel.DisplayName = viewModel.DisplayName.Trim(); + + if (String.IsNullOrWhiteSpace(viewModel.DisplayName)) { + ModelState.AddModelError("DisplayName", T("The Display Name name can't be empty.").ToString()); + } + + if (_contentDefinitionService.GetPart(partViewModel.Name).Fields.Any(t => t.Name != viewModel.Name && String.Equals(t.DisplayName.Trim(), viewModel.DisplayName.Trim(), StringComparison.OrdinalIgnoreCase))) { + ModelState.AddModelError("DisplayName", T("A field with the same Display Name already exists.").ToString()); + } + + if (!ModelState.IsValid) { + return View(viewModel); + } + + var field = _contentDefinitionManager.GetPartDefinition(id).Fields.FirstOrDefault(x => x.Name == viewModel.Name); + + if(field == null) { + return HttpNotFound(); + } + + field.DisplayName = viewModel.DisplayName; + _contentDefinitionManager.StorePartDefinition(partViewModel._Definition); + + Services.Notifier.Information(T("Display name changed to {0}.", viewModel.DisplayName)); + + // redirect to the type editor if a type exists with this name + var typeViewModel = _contentDefinitionService.GetType(id); + if (typeViewModel != null) { + return RedirectToAction("Edit", new { id }); + } + + return RedirectToAction("EditPart", new { id }); + } public ActionResult RemoveFieldFrom(string id) { if (!Services.Authorizer.Authorize(Permissions.EditContentTypes, T("Not allowed to edit a content part."))) diff --git a/src/Orchard.Web/Modules/Orchard.ContentTypes/Orchard.ContentTypes.csproj b/src/Orchard.Web/Modules/Orchard.ContentTypes/Orchard.ContentTypes.csproj index 888bb95cc..d6cb327d5 100644 --- a/src/Orchard.Web/Modules/Orchard.ContentTypes/Orchard.ContentTypes.csproj +++ b/src/Orchard.Web/Modules/Orchard.ContentTypes/Orchard.ContentTypes.csproj @@ -14,6 +14,7 @@ Orchard.ContentTypes v4.0 false + false true @@ -57,6 +58,7 @@ + @@ -115,6 +117,9 @@ + + +