From 75449c1abe501819fd5f5b15c204968f1c789548 Mon Sep 17 00:00:00 2001 From: Louis DeJardin Date: Wed, 9 Jun 2010 15:18:12 -0700 Subject: [PATCH 1/8] Migrating some existing Routable aspect functionality to Core.Routable module Exposing user interface for Title and Slug Calculating Path based on Slug (and container's Path, if present) Migrating some of the slugify action and jquery support to Core.Routable module Making a driver for CommonAspect, adding rough placeholder textbox to input container id --HG-- branch : dev --- .../Core/Common/Drivers/CommonDriver.cs | 104 ++++++++++++++++ .../Common/Handlers/CommonAspectHandler.cs | 74 ++++++------ .../ViewModels/ContainerEditorViewModel.cs | 8 ++ .../Parts/Common.Container.ascx | 7 ++ src/Orchard.Web/Core/Orchard.Core.csproj | 8 ++ .../Routable/Controllers/ItemController.cs | 42 ++++++- .../Core/Routable/Drivers/RoutableDriver.cs | 114 ++++++++++++------ .../Core/Routable/Scripts/jquery.slugify.js | 24 ++++ .../Routable/Services/IRoutableService.cs | 28 +++++ .../Core/Routable/Services/RoutableService.cs | 113 +++++++++++++++++ .../ViewModels/RoutableDisplayViewModel.cs | 2 +- .../ViewModels/RoutableEditorViewModel.cs | 17 +++ .../Parts/Routable.IsRoutable.ascx | 31 +++++ src/Orchard/Mvc/Html/HtmlHelperExtensions.cs | 8 ++ 14 files changed, 502 insertions(+), 78 deletions(-) create mode 100644 src/Orchard.Web/Core/Common/Drivers/CommonDriver.cs create mode 100644 src/Orchard.Web/Core/Common/ViewModels/ContainerEditorViewModel.cs create mode 100644 src/Orchard.Web/Core/Common/Views/EditorTemplates/Parts/Common.Container.ascx create mode 100644 src/Orchard.Web/Core/Routable/Scripts/jquery.slugify.js create mode 100644 src/Orchard.Web/Core/Routable/Services/IRoutableService.cs create mode 100644 src/Orchard.Web/Core/Routable/Services/RoutableService.cs create mode 100644 src/Orchard.Web/Core/Routable/ViewModels/RoutableEditorViewModel.cs create mode 100644 src/Orchard.Web/Core/Routable/Views/EditorTemplates/Parts/Routable.IsRoutable.ascx diff --git a/src/Orchard.Web/Core/Common/Drivers/CommonDriver.cs b/src/Orchard.Web/Core/Common/Drivers/CommonDriver.cs new file mode 100644 index 000000000..b8078ffce --- /dev/null +++ b/src/Orchard.Web/Core/Common/Drivers/CommonDriver.cs @@ -0,0 +1,104 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Web; +using Orchard.ContentManagement; +using Orchard.ContentManagement.Drivers; +using Orchard.Core.Common.Models; +using Orchard.Core.Common.ViewModels; +using Orchard.Localization; +using Orchard.Security; +using Orchard.Services; + +namespace Orchard.Core.Common.Drivers { + public class CommonDriver : ContentPartDriver { + private readonly IContentManager _contentManager; + private readonly IAuthenticationService _authenticationService; + private readonly IAuthorizationService _authorizationService; + private readonly IMembershipService _membershipService; + private readonly IClock _clock; + + public CommonDriver( + IContentManager contentManager, + IAuthenticationService authenticationService, + IAuthorizationService authorizationService, + IMembershipService membershipService, + IClock clock) { + _contentManager = contentManager; + _authenticationService = authenticationService; + _authorizationService = authorizationService; + _membershipService = membershipService; + _clock = clock; + T = NullLocalizer.Instance; + } + + public Localizer T { get; set; } + + protected override DriverResult Editor(CommonAspect part) { + return Combined(OwnerEditor(part, null), ContainerEditor(part, null)); + } + + protected override DriverResult Editor(CommonAspect instance, ContentManagement.IUpdateModel updater) { + // this event is hooked so the modified timestamp is changed when an edit-post occurs. + instance.ModifiedUtc = _clock.UtcNow; + instance.VersionModifiedUtc = _clock.UtcNow; + + return Combined(OwnerEditor(instance, updater), ContainerEditor(instance, updater)); + } + + DriverResult OwnerEditor(CommonAspect part, IUpdateModel updater) { + var currentUser = _authenticationService.GetAuthenticatedUser(); + if (!_authorizationService.TryCheckAccess(Permissions.ChangeOwner, currentUser, part)) { + return null; + } + + var model = new OwnerEditorViewModel(); + if (part.Owner != null) + model.Owner = part.Owner.UserName; + + if (updater != null) { + var priorOwner = model.Owner; + updater.TryUpdateModel(model, "CommonAspect", null, null); + + if (model.Owner != null && model.Owner != priorOwner) { + var newOwner = _membershipService.GetUser(model.Owner); + if (newOwner == null) { + updater.AddModelError("CommonAspect.Owner", T("Invalid user name")); + } + else { + part.Owner = newOwner; + } + } + } + + return ContentPartTemplate(model, "Parts/Common.Owner", "CommonAspect").Location("primary", "10"); + } + + DriverResult ContainerEditor(CommonAspect part, IUpdateModel updater) { + var currentUser = _authenticationService.GetAuthenticatedUser(); + if (!_authorizationService.TryCheckAccess(Permissions.ChangeOwner, currentUser, part)) { + return null; + } + + var model = new ContainerEditorViewModel(); + if (part.Container != null) + model.ContainerId = part.Container.ContentItem.Id; + + if (updater != null) { + var priorContainerId = model.ContainerId; + updater.TryUpdateModel(model, "CommonAspect", null, null); + + if (model.ContainerId != null && model.ContainerId != priorContainerId) { + var newContainer = _contentManager.Get((int)model.ContainerId, VersionOptions.Latest); + if (newContainer == null) { + updater.AddModelError("CommonAspect.ContainerId", T("Invalid container")); + } + else { + part.Container = newContainer; + } + } + } + return ContentPartTemplate(model, "Parts/Common.Container", "CommonAspect").Location("primary", "10.1"); + } + } +} \ No newline at end of file diff --git a/src/Orchard.Web/Core/Common/Handlers/CommonAspectHandler.cs b/src/Orchard.Web/Core/Common/Handlers/CommonAspectHandler.cs index f3db7095e..7ec96d6da 100644 --- a/src/Orchard.Web/Core/Common/Handlers/CommonAspectHandler.cs +++ b/src/Orchard.Web/Core/Common/Handlers/CommonAspectHandler.cs @@ -52,8 +52,8 @@ namespace Orchard.Core.Common.Handlers { OnPublishing>(AssignPublishingDates); //OnGetDisplayViewModel(); - OnGetEditorViewModel(GetEditor); - OnUpdateEditorViewModel(UpdateEditor); + //OnGetEditorViewModel(GetEditor); + //OnUpdateEditorViewModel(UpdateEditor); OnIndexing((context, commonAspect) => context.IndexDocument .Add("type", commonAspect.ContentItem.ContentType).Analyze(false) @@ -157,48 +157,48 @@ namespace Orchard.Core.Common.Handlers { } - private void GetEditor(BuildEditorModelContext context, CommonAspect instance) { - var currentUser = _authenticationService.GetAuthenticatedUser(); - if (!_authorizationService.TryCheckAccess(Permissions.ChangeOwner, currentUser, instance)) { - return; - } - var viewModel = new OwnerEditorViewModel(); - if (instance.Owner != null) - viewModel.Owner = instance.Owner.UserName; + //private void GetEditor(BuildEditorModelContext context, CommonAspect instance) { + // var currentUser = _authenticationService.GetAuthenticatedUser(); + // if (!_authorizationService.TryCheckAccess(Permissions.ChangeOwner, currentUser, instance)) { + // return; + // } + // var viewModel = new OwnerEditorViewModel(); + // if (instance.Owner != null) + // viewModel.Owner = instance.Owner.UserName; - context.AddEditor(new TemplateViewModel(viewModel, "CommonAspect") { TemplateName = "Parts/Common.Owner", ZoneName = "primary", Position = "999" }); - } + // context.AddEditor(new TemplateViewModel(viewModel, "CommonAspect") { TemplateName = "Parts/Common.Owner", ZoneName = "primary", Position = "999" }); + //} - private void UpdateEditor(UpdateEditorModelContext context, CommonAspect instance) { - // this event is hooked so the modified timestamp is changed when an edit-post occurs. - // kind of a loose rule of thumb. may not be sufficient - instance.ModifiedUtc = _clock.UtcNow; - instance.VersionModifiedUtc = _clock.UtcNow; + //private void UpdateEditor(UpdateEditorModelContext context, CommonAspect instance) { + // // this event is hooked so the modified timestamp is changed when an edit-post occurs. + // // kind of a loose rule of thumb. may not be sufficient + // instance.ModifiedUtc = _clock.UtcNow; + // instance.VersionModifiedUtc = _clock.UtcNow; - var currentUser = _authenticationService.GetAuthenticatedUser(); - if (!_authorizationService.TryCheckAccess(Permissions.ChangeOwner, currentUser, instance)) { - return; - } + // var currentUser = _authenticationService.GetAuthenticatedUser(); + // if (!_authorizationService.TryCheckAccess(Permissions.ChangeOwner, currentUser, instance)) { + // return; + // } - var viewModel = new OwnerEditorViewModel(); - if (instance.Owner != null) - viewModel.Owner = instance.Owner.UserName; + // var viewModel = new OwnerEditorViewModel(); + // if (instance.Owner != null) + // viewModel.Owner = instance.Owner.UserName; - var priorOwner = viewModel.Owner; - context.Updater.TryUpdateModel(viewModel, "CommonAspect", null, null); + // var priorOwner = viewModel.Owner; + // context.Updater.TryUpdateModel(viewModel, "CommonAspect", null, null); - if (viewModel.Owner != null && viewModel.Owner != priorOwner) { - var newOwner = _membershipService.GetUser(viewModel.Owner); - if (newOwner == null) { - context.Updater.AddModelError("CommonAspect.Owner", T("Invalid user name")); - } - else { - instance.Owner = newOwner; - } - } + // if (viewModel.Owner != null && viewModel.Owner != priorOwner) { + // var newOwner = _membershipService.GetUser(viewModel.Owner); + // if (newOwner == null) { + // context.Updater.AddModelError("CommonAspect.Owner", T("Invalid user name")); + // } + // else { + // instance.Owner = newOwner; + // } + // } - context.AddEditor(new TemplateViewModel(viewModel, "CommonAspect") { TemplateName = "Parts/Common.Owner", ZoneName = "primary", Position = "999" }); - } + // context.AddEditor(new TemplateViewModel(viewModel, "CommonAspect") { TemplateName = "Parts/Common.Owner", ZoneName = "primary", Position = "999" }); + //} } } \ No newline at end of file diff --git a/src/Orchard.Web/Core/Common/ViewModels/ContainerEditorViewModel.cs b/src/Orchard.Web/Core/Common/ViewModels/ContainerEditorViewModel.cs new file mode 100644 index 000000000..1cdb19a7d --- /dev/null +++ b/src/Orchard.Web/Core/Common/ViewModels/ContainerEditorViewModel.cs @@ -0,0 +1,8 @@ +using System.ComponentModel.DataAnnotations; + +namespace Orchard.Core.Common.ViewModels { + public class ContainerEditorViewModel { + + public int? ContainerId { get; set; } + } +} \ No newline at end of file diff --git a/src/Orchard.Web/Core/Common/Views/EditorTemplates/Parts/Common.Container.ascx b/src/Orchard.Web/Core/Common/Views/EditorTemplates/Parts/Common.Container.ascx new file mode 100644 index 000000000..fbefbac2d --- /dev/null +++ b/src/Orchard.Web/Core/Common/Views/EditorTemplates/Parts/Common.Container.ascx @@ -0,0 +1,7 @@ +<%@ Control Language="C#" Inherits="Orchard.Mvc.ViewUserControl" %> +<%@ Import Namespace="Orchard.Core.Common.ViewModels" %> +
+ <%=Html.LabelFor(m=>m.ContainerId) %> + <%=Html.EditorFor(m=>m.ContainerId) %> + <%=Html.ValidationMessageFor(m=>m.ContainerId) %> +
diff --git a/src/Orchard.Web/Core/Orchard.Core.csproj b/src/Orchard.Web/Core/Orchard.Core.csproj index 86497731a..4077ae6aa 100644 --- a/src/Orchard.Web/Core/Orchard.Core.csproj +++ b/src/Orchard.Web/Core/Orchard.Core.csproj @@ -66,9 +66,11 @@ + + @@ -155,8 +157,11 @@ + + + @@ -201,6 +206,7 @@ + @@ -214,6 +220,8 @@ + + diff --git a/src/Orchard.Web/Core/Routable/Controllers/ItemController.cs b/src/Orchard.Web/Core/Routable/Controllers/ItemController.cs index 856f53052..690ad156f 100644 --- a/src/Orchard.Web/Core/Routable/Controllers/ItemController.cs +++ b/src/Orchard.Web/Core/Routable/Controllers/ItemController.cs @@ -6,16 +6,20 @@ using Orchard.ContentManagement.Aspects; using Orchard.Core.Common.Models; using Orchard.Core.Routable.Models; using Orchard.Core.Routable.ViewModels; +using Orchard.Data; +using Orchard.Localization; using Orchard.Mvc.ViewModels; namespace Orchard.Core.Routable.Controllers { [ValidateInput(false)] - public class ItemController : Controller { + public class ItemController : Controller, IUpdateModel { private readonly IContentManager _contentManager; + private readonly ITransactionManager _transactionManager; private readonly IRoutablePathConstraint _routablePathConstraint; - public ItemController(IContentManager contentManager, IRoutablePathConstraint routablePathConstraint) { + public ItemController(IContentManager contentManager, ITransactionManager transactionManager, IRoutablePathConstraint routablePathConstraint) { _contentManager = contentManager; + _transactionManager = transactionManager; _routablePathConstraint = routablePathConstraint; } @@ -47,5 +51,39 @@ namespace Orchard.Core.Routable.Controllers { itemViewModel.TemplateName = "Items/Contents.Item"; } } + + public ActionResult Slugify(string contentType, int? id, int? containerId) { + const string slug = ""; + ContentItem contentItem = null; + + if (string.IsNullOrEmpty(contentType)) + return Json(slug); + + if (id != null) + contentItem = _contentManager.Get((int)id, VersionOptions.Latest); + + if (contentItem == null) { + contentItem = _contentManager.New(contentType); + + if (containerId != null) { + var containerItem = _contentManager.Get((int)containerId); + contentItem.As().Container = containerItem; + } + } + + _contentManager.UpdateEditorModel(contentItem, this); + _transactionManager.Cancel(); + + return Json(contentItem.As().Slug ?? slug); + } + + + bool IUpdateModel.TryUpdateModel(TModel model, string prefix, string[] includeProperties, string[] excludeProperties) { + return TryUpdateModel(model, prefix, includeProperties, excludeProperties); + } + + void IUpdateModel.AddModelError(string key, LocalizedString errorMessage) { + ModelState.AddModelError(key, errorMessage.ToString()); + } } } \ No newline at end of file diff --git a/src/Orchard.Web/Core/Routable/Drivers/RoutableDriver.cs b/src/Orchard.Web/Core/Routable/Drivers/RoutableDriver.cs index b3a2f6e02..b315fdd11 100644 --- a/src/Orchard.Web/Core/Routable/Drivers/RoutableDriver.cs +++ b/src/Orchard.Web/Core/Routable/Drivers/RoutableDriver.cs @@ -1,61 +1,99 @@ using JetBrains.Annotations; using Orchard.ContentManagement; +using Orchard.ContentManagement.Aspects; using Orchard.ContentManagement.Drivers; using Orchard.Core.Common.Models; -using Orchard.Core.Common.ViewModels; -using Orchard.Core.Common.Services; using Orchard.Core.Routable.Models; +using Orchard.Core.Routable.Services; +using Orchard.Core.Routable.ViewModels; using Orchard.Localization; using Orchard.UI.Notify; namespace Orchard.Core.Routable.Drivers { public class RoutableDriver : ContentPartDriver { - protected override DriverResult Editor(IsRoutable part, IUpdateModel updater) { - part.Record.Title = "Routable #" + part.ContentItem.Id; - part.Record.Slug = "routable" + part.ContentItem.Id; - part.Record.Path = "routable" + part.ContentItem.Id; - return base.Editor(part, updater); + private readonly IOrchardServices _services; + private readonly IRoutableService _routableService; + + public RoutableDriver(IOrchardServices services, IRoutableService routableService) { + _services = services; + _routableService = routableService; + T = NullLocalizer.Instance; } - //private const string TemplateName = "Parts/Common.Routable"; - //private readonly IOrchardServices _services; - //private readonly IRoutableService _routableService; - //public Localizer T { get; set; } + private const string TemplateName = "Parts/Routable.IsRoutable"; - //protected override string Prefix { - // get { return "Routable"; } - //} + public Localizer T { get; set; } - //public Routable(IOrchardServices services, IRoutableService routableService) - //{ - // _services = services; - // _routableService = routableService; + protected override string Prefix { + get { return "Routable"; } + } - // T = NullLocalizer.Instance; - //} + int? GetContainerId(IContent item) { + var commonAspect = item.As(); + if (commonAspect != null && commonAspect.Container != null) { + return commonAspect.Container.ContentItem.Id; + } + return null; + } - //protected override DriverResult Editor(RoutableAspect part) { - // var model = new RoutableEditorViewModel { Prefix = Prefix, RoutableAspect = part }; - // return ContentPartTemplate(model, TemplateName, Prefix).Location("primary", "before.5"); - //} + string GetContainerSlug(IContent item) { + var commonAspect = item.As(); + if (commonAspect != null && commonAspect.Container != null) { + var routable = commonAspect.Container.As(); + if (routable != null) { + return routable.Slug; + } + } + return null; + } - //protected override DriverResult Editor(RoutableAspect part, IUpdateModel updater) { - // var model = new RoutableEditorViewModel { Prefix = Prefix, RoutableAspect = part }; - // updater.TryUpdateModel(model, Prefix, null, null); + protected override DriverResult Editor(IsRoutable part) { + var model = new RoutableEditorViewModel { + ContentType = part.ContentItem.ContentType, + Id = part.ContentItem.Id, + Slug = part.Slug, + Title = part.Title, + ContainerId = GetContainerId(part), + }; - // if (!_routableService.IsSlugValid(part.Slug)){ - // updater.AddModelError("Routable.Slug", T("Please do not use any of the following characters in your slugs: \"/\", \":\", \"?\", \"#\", \"[\", \"]\", \"@\", \"!\", \"$\", \"&\", \"'\", \"(\", \")\", \"*\", \"+\", \",\", \";\", \"=\". No spaces are allowed (please use dashes or underscores instead).").ToString()); - // } + // TEMP: path format patterns replaces this logic + var path = part.Record.Path; + if (path.EndsWith(part.Slug)) { + model.DisplayLeadingPath = path.Substring(0, path.Length - part.Slug.Length); + } - // string originalSlug = part.Slug; - // if(!_routableService.ProcessSlug(part)) { - // _services.Notifier.Warning(T("Slugs in conflict. \"{0}\" is already set for a previously created {2} so now it has the slug \"{1}\"", - // originalSlug, part.Slug, part.ContentItem.ContentType)); - // } - - // return ContentPartTemplate(model, TemplateName, Prefix).Location("primary", "before.5"); - //} + return ContentPartTemplate(model, TemplateName, Prefix).Location("primary", "before.5"); + } + + protected override DriverResult Editor(IsRoutable part, IUpdateModel updater) { + + var model = new RoutableEditorViewModel(); + updater.TryUpdateModel(model, Prefix, null, null); + part.Title = model.Title; + part.Slug = model.Slug; + + // TEMP: path format patterns replaces this logic + var containerSlug = GetContainerSlug(part); + if (string.IsNullOrEmpty(containerSlug)) { + part.Record.Path = model.Slug; + } + else { + part.Record.Path = containerSlug + "/" + model.Slug; + } + + if (!_routableService.IsSlugValid(part.Slug)) { + updater.AddModelError("Routable.Slug", T("Please do not use any of the following characters in your slugs: \"/\", \":\", \"?\", \"#\", \"[\", \"]\", \"@\", \"!\", \"$\", \"&\", \"'\", \"(\", \")\", \"*\", \"+\", \",\", \";\", \"=\". No spaces are allowed (please use dashes or underscores instead).").ToString()); + } + + string originalSlug = part.Slug; + if (!_routableService.ProcessSlug(part)) { + _services.Notifier.Warning(T("Slugs in conflict. \"{0}\" is already set for a previously created {2} so now it has the slug \"{1}\"", + originalSlug, part.Slug, part.ContentItem.ContentType)); + } + + return Editor(part); + } } } \ No newline at end of file diff --git a/src/Orchard.Web/Core/Routable/Scripts/jquery.slugify.js b/src/Orchard.Web/Core/Routable/Scripts/jquery.slugify.js new file mode 100644 index 000000000..070202125 --- /dev/null +++ b/src/Orchard.Web/Core/Routable/Scripts/jquery.slugify.js @@ -0,0 +1,24 @@ +jQuery.fn.extend({ + slugify: function(options) { + //todo: (heskew) need messaging system + if (!options.target || !options.url) + return; + + var args = { + "contentType": options.contentType, + "id": options.id, + "containerId": options.containerId, + __RequestVerificationToken: $("input[name=__RequestVerificationToken]").val() + }; + args[$(this).attr("name")] = $(this).val(); + + jQuery.post( + options.url, + args, + function(data) { + options.target.val(data); + }, + "json" + ); + } +}); \ No newline at end of file diff --git a/src/Orchard.Web/Core/Routable/Services/IRoutableService.cs b/src/Orchard.Web/Core/Routable/Services/IRoutableService.cs new file mode 100644 index 000000000..4daa265b6 --- /dev/null +++ b/src/Orchard.Web/Core/Routable/Services/IRoutableService.cs @@ -0,0 +1,28 @@ +using System; +using System.Collections.Generic; +using Orchard.Core.Routable.Models; + +namespace Orchard.Core.Routable.Services { + public interface IRoutableService : IDependency { + void FillSlug(TModel model) where TModel : IsRoutable; + void FillSlug(TModel model, Func generateSlug) where TModel : IsRoutable; + string GenerateUniqueSlug(string slugCandidate, IEnumerable existingSlugs); + + /// + /// Returns any content item of the specified content type with similar slugs + /// + IEnumerable GetSimilarSlugs(string contentType, string slug); + + /// + /// Validates the given slug + /// + bool IsSlugValid(string slug); + + /// + /// Defines the slug of a RoutableAspect and validate its unicity + /// + /// True if the slug has been created, False if a conflict occured + bool ProcessSlug(IsRoutable part); + + } +} \ 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 new file mode 100644 index 000000000..4b27b4d1e --- /dev/null +++ b/src/Orchard.Web/Core/Routable/Services/RoutableService.cs @@ -0,0 +1,113 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text.RegularExpressions; +using JetBrains.Annotations; +using Orchard.ContentManagement; +using Orchard.Core.Common.Models; +using Orchard.Core.Routable.Models; +using Orchard.Localization; +using Orchard.UI.Notify; + +namespace Orchard.Core.Routable.Services { + [UsedImplicitly] + public class RoutableService : IRoutableService { + private readonly IContentManager _contentManager; + + public RoutableService(IContentManager contentManager) { + _contentManager = contentManager; + } + + public void FillSlug(TModel model) where TModel : IsRoutable { + if (!string.IsNullOrEmpty(model.Slug) || string.IsNullOrEmpty(model.Title)) + return; + + var slug = model.Title; + var dissallowed = new Regex(@"[/:?#\[\]@!$&'()*+,;=\s]+"); + + slug = dissallowed.Replace(slug, "-"); + slug = slug.Trim('-'); + + if (slug.Length > 1000) + slug = slug.Substring(0, 1000); + + model.Slug = slug.ToLowerInvariant(); + } + + public void FillSlug(TModel model, Func generateSlug) where TModel : IsRoutable { + if (!string.IsNullOrEmpty(model.Slug) || string.IsNullOrEmpty(model.Title)) + return; + + model.Slug = generateSlug(model.Title).ToLowerInvariant(); + } + + public string GenerateUniqueSlug(string slugCandidate, IEnumerable existingSlugs) { + if (existingSlugs == null || !existingSlugs.Contains(slugCandidate)) + return slugCandidate; + + int? version = existingSlugs.Select(s => GetSlugVersion(slugCandidate, s)).OrderBy(i => i).LastOrDefault(); + + return version != null + ? string.Format("{0}-{1}", slugCandidate, version) + : slugCandidate; + } + + private static int? GetSlugVersion(string slugCandidate, string slug) { + int v; + string[] slugParts = slug.Split(new []{slugCandidate}, StringSplitOptions.RemoveEmptyEntries); + + if (slugParts.Length == 0) + return 2; + + return int.TryParse(slugParts[0].TrimStart('-'), out v) + ? (int?)++v + : null; + } + + public IEnumerable GetSimilarSlugs(string contentType, string slug) + { + return + _contentManager.Query(contentType).Join() + .List() + .Select(i => i.As()) + .Where(routable => routable.Slug.StartsWith(slug, StringComparison.OrdinalIgnoreCase)) // todo: for some reason the filter doesn't work within the query, even without StringComparison or StartsWith + .ToArray(); + } + + public bool IsSlugValid(string slug) { + // see http://tools.ietf.org/html/rfc3987 for prohibited chars + return slug == null || String.IsNullOrEmpty(slug.Trim()) || Regex.IsMatch(slug, @"^[^/:?#\[\]@!$&'()*+,;=\s]+$"); + } + + public bool ProcessSlug(IsRoutable part) + { + FillSlug(part); + + if (string.IsNullOrEmpty(part.Slug)) + { + return true; + } + + var slugsLikeThis = GetSimilarSlugs(part.ContentItem.ContentType, part.Slug); + + // If the part is already a valid content item, don't include it in the list + // of slug to consider for conflict detection + if (part.ContentItem.Id != 0) + slugsLikeThis = slugsLikeThis.Where(p => p.ContentItem.Id != part.ContentItem.Id); + + //todo: (heskew) need better messages + if (slugsLikeThis.Count() > 0) + { + var originalSlug = part.Slug; + //todo: (heskew) make auto-uniqueness optional + part.Slug = GenerateUniqueSlug(part.Slug, slugsLikeThis.Select(p => p.Slug)); + + if (originalSlug != part.Slug) { + return false; + } + } + + return true; + } + } +} \ No newline at end of file diff --git a/src/Orchard.Web/Core/Routable/ViewModels/RoutableDisplayViewModel.cs b/src/Orchard.Web/Core/Routable/ViewModels/RoutableDisplayViewModel.cs index e07d266f5..7dafe4573 100644 --- a/src/Orchard.Web/Core/Routable/ViewModels/RoutableDisplayViewModel.cs +++ b/src/Orchard.Web/Core/Routable/ViewModels/RoutableDisplayViewModel.cs @@ -2,7 +2,7 @@ using Orchard.Mvc.ViewModels; namespace Orchard.Core.Routable.ViewModels { - public class RoutableDisplayViewModel : BaseViewModel { + public class RoutableDisplayViewModel : BaseViewModel { public ContentItemViewModel Routable {get;set;} } } \ No newline at end of file diff --git a/src/Orchard.Web/Core/Routable/ViewModels/RoutableEditorViewModel.cs b/src/Orchard.Web/Core/Routable/ViewModels/RoutableEditorViewModel.cs new file mode 100644 index 000000000..16bb56c98 --- /dev/null +++ b/src/Orchard.Web/Core/Routable/ViewModels/RoutableEditorViewModel.cs @@ -0,0 +1,17 @@ +using System; +using System.ComponentModel.DataAnnotations; + +namespace Orchard.Core.Routable.ViewModels { + public class RoutableEditorViewModel { + + public int Id { get; set; } + public string ContentType { get; set; } + + [Required] + public string Title { get; set; } + public string Slug { get; set; } + public int? ContainerId { get; set; } + + public string DisplayLeadingPath { get; set; } + } +} \ No newline at end of file diff --git a/src/Orchard.Web/Core/Routable/Views/EditorTemplates/Parts/Routable.IsRoutable.ascx b/src/Orchard.Web/Core/Routable/Views/EditorTemplates/Parts/Routable.IsRoutable.ascx new file mode 100644 index 000000000..7eb8638d5 --- /dev/null +++ b/src/Orchard.Web/Core/Routable/Views/EditorTemplates/Parts/Routable.IsRoutable.ascx @@ -0,0 +1,31 @@ +<%@ Control Language="C#" Inherits="Orchard.Mvc.ViewUserControl" %> +<%@ Import Namespace="Orchard.Utility.Extensions"%> +<%@ Import Namespace="Orchard.ContentManagement.Extenstions"%> + +<% Html.RegisterFootScript("jquery.slugify.js"); %> +
+ <%=Html.LabelFor(m => m.Title) %> + <%=Html.TextBoxFor(m => m.Title, new { @class = "large text" }) %> +
+ + + +<% using (this.Capture("end-of-page-scripts")) { %> + +<% } %> diff --git a/src/Orchard/Mvc/Html/HtmlHelperExtensions.cs b/src/Orchard/Mvc/Html/HtmlHelperExtensions.cs index c302658aa..b38925545 100644 --- a/src/Orchard/Mvc/Html/HtmlHelperExtensions.cs +++ b/src/Orchard/Mvc/Html/HtmlHelperExtensions.cs @@ -23,6 +23,14 @@ namespace Orchard.Mvc.Html { return Reflect.NameOf(html.ViewData.Model, expression); } + public static string FieldNameFor(this HtmlHelper html, Expression> expression) { + return html.ViewData.TemplateInfo.GetFullHtmlFieldName(ExpressionHelper.GetExpressionText(expression)); + } + public static string FieldIdFor(this HtmlHelper html, Expression> expression) { + return html.ViewData.TemplateInfo.GetFullHtmlFieldId(ExpressionHelper.GetExpressionText(expression)); + } + + public static MvcHtmlString SelectOption(this HtmlHelper html, T currentValue, T optionValue, string text) { return SelectOption(html, optionValue, object.Equals(optionValue, currentValue), text); } From a190d9bc64f040f87e04f8234881cdd1e2b336a1 Mon Sep 17 00:00:00 2001 From: Louis DeJardin Date: Wed, 9 Jun 2010 15:21:50 -0700 Subject: [PATCH 2/8] Integrating some localizer support for encoding and pluralization Formatter internally encodes information passed as object[] args as appropriate Resulting LocalizedString marked as html-encoded to prevent double-encoding Extension method for <%:T.Plural("1 thing", "{0} things", n, ...)%> --HG-- branch : dev --- src/Orchard/Localization/LocalizedString.cs | 10 +++++++-- src/Orchard/Localization/Localizer.cs | 10 ++++++++- src/Orchard/Localization/Text.cs | 25 ++++++++++++++++++--- 3 files changed, 39 insertions(+), 6 deletions(-) diff --git a/src/Orchard/Localization/LocalizedString.cs b/src/Orchard/Localization/LocalizedString.cs index 8197f4219..e5db95112 100644 --- a/src/Orchard/Localization/LocalizedString.cs +++ b/src/Orchard/Localization/LocalizedString.cs @@ -1,7 +1,8 @@ using System; +using System.Web; namespace Orchard.Localization { - public class LocalizedString : MarshalByRefObject { + public class LocalizedString : MarshalByRefObject, IHtmlString { private readonly string _localized; public LocalizedString(string localized) { @@ -20,6 +21,10 @@ namespace Orchard.Localization { return _localized; } + string IHtmlString.ToHtmlString() { + return _localized; + } + public override int GetHashCode() { var hashCode = 0; if (_localized != null) @@ -31,8 +36,9 @@ namespace Orchard.Localization { if (obj == null || obj.GetType() != GetType()) return false; - var that = (LocalizedString) obj; + var that = (LocalizedString)obj; return string.Equals(_localized, that._localized); } + } } diff --git a/src/Orchard/Localization/Localizer.cs b/src/Orchard/Localization/Localizer.cs index 48cba242c..0e2221263 100644 --- a/src/Orchard/Localization/Localizer.cs +++ b/src/Orchard/Localization/Localizer.cs @@ -1,3 +1,11 @@ +using System.Linq; + namespace Orchard.Localization { public delegate LocalizedString Localizer(string text, params object[] args); -} \ No newline at end of file + + public static class LocalizerExtensions { + public static LocalizedString Plural(this Localizer T, string textSingular, string textPlural, int count, params object[] args) { + return T(count == 1 ? textSingular : textPlural, new object[] { count }.Concat(args).ToArray()); + } + } +} diff --git a/src/Orchard/Localization/Text.cs b/src/Orchard/Localization/Text.cs index 8403d25c4..80bc672dc 100644 --- a/src/Orchard/Localization/Text.cs +++ b/src/Orchard/Localization/Text.cs @@ -1,3 +1,6 @@ +using System; +using System.Globalization; +using System.Linq; using System.Web; using Orchard.Localization.Services; using Orchard.Logging; @@ -23,9 +26,25 @@ namespace Orchard.Localization { string currentCulture = _cultureManager.GetCurrentCulture(HttpContext.Current); var localizedFormat = _resourceManager.GetLocalizedString(_scope, textHint, currentCulture); - return args.Length < 1 - ? new LocalizedString(localizedFormat) - : new LocalizedString(string.Format(localizedFormat, args)); + return args.Length == 0 + ? new LocalizedString(localizedFormat) + : string.Format(GetFormatProvider(currentCulture), localizedFormat, args.Select(Encode).ToArray()); + } + + private static IFormatProvider GetFormatProvider(string currentCulture) { + try { + return CultureInfo.GetCultureInfoByIetfLanguageTag(currentCulture); + } + catch { + return null; + } + } + + static object Encode(object arg) { + if (arg is IFormattable || arg is IHtmlString) { + return arg; + } + return HttpUtility.HtmlEncode(arg); } } } \ No newline at end of file From 85a0f45c5de54c6bc2b6bd70813ad7028a8398a1 Mon Sep 17 00:00:00 2001 From: Louis DeJardin Date: Wed, 9 Jun 2010 15:39:35 -0700 Subject: [PATCH 3/8] Using T.Plural in code --HG-- branch : dev --- .../Modules/Orchard.Blogs/Views/BlogAdmin/List.ascx | 12 +++++++----- .../DisplayTemplates/Items/Blogs.Blog.Summary.ascx | 2 +- .../Extensions/HtmlHelperExtensions.cs | 7 ++++--- .../Views/DisplayTemplates/Parts/Comments.Count.ascx | 2 +- .../DisplayTemplates/Parts/Comments.HasComments.ascx | 2 +- .../DisplayTemplates/Items/Blogs.Blog.Summary.ascx | 2 +- .../DisplayTemplates/Items/Blogs.Blog.Summary.ascx | 2 +- .../DisplayTemplates/Parts/Comments.HasComments.ascx | 3 ++- .../DisplayTemplates/Parts/Comments.HasComments.ascx | 2 +- .../DisplayTemplates/Items/Blogs.Blog.Summary.ascx | 2 +- src/Orchard/Localization/Localizer.cs | 6 +++++- 11 files changed, 25 insertions(+), 17 deletions(-) diff --git a/src/Orchard.Web/Modules/Orchard.Blogs/Views/BlogAdmin/List.ascx b/src/Orchard.Web/Modules/Orchard.Blogs/Views/BlogAdmin/List.ascx index 6c0951db7..7540f1460 100644 --- a/src/Orchard.Web/Modules/Orchard.Blogs/Views/BlogAdmin/List.ascx +++ b/src/Orchard.Web/Modules/Orchard.Blogs/Views/BlogAdmin/List.ascx @@ -10,16 +10,18 @@ if (Model.Entries.Count() > 0) { %> entry.ContentItemViewModel.Zones.AddAction("meta", html => { int draftCount = entry.TotalPostCount - entry.ContentItemViewModel.Item.PostCount; int totalPostCount = entry.TotalPostCount; - var draftText = (draftCount == 0 ? "": string.Format(" ({0} draft{1})", draftCount, draftCount == 1 ? "" : "s")); + + var linkText = T.Plural("1 post", "{0} posts", totalPostCount).ToString(); + if (draftCount==0){ + linkText = linkText + " (" + T.Plural("1 draft", "{0} drafts", draftCount).ToString() + ")"; + } - var linkContent = _Encoded("{0} post{1}{2}", totalPostCount, totalPostCount == 1 ? "" : "s", draftText); - - html.ViewContext.Writer.Write(html.Link(linkContent.ToString(), Url.BlogForAdmin(entry.ContentItemViewModel.Item.Slug))); + html.ViewContext.Writer.Write(html.Link(linkText, Url.BlogForAdmin(entry.ContentItemViewModel.Item.Slug))); }); // Display the summary for the blog post return Html.DisplayForItem(entry.ContentItemViewModel).ToHtmlString(); }, "blogs contentItems")%><% } else { %> -
<%=T("There are no blogs for you to see. Want to add one?", Url.BlogCreate()).ToString()%>
<% +
<%:T("There are no blogs for you to see. Want to add one?", Url.BlogCreate())%>
<% } %> \ No newline at end of file diff --git a/src/Orchard.Web/Modules/Orchard.Blogs/Views/DisplayTemplates/Items/Blogs.Blog.Summary.ascx b/src/Orchard.Web/Modules/Orchard.Blogs/Views/DisplayTemplates/Items/Blogs.Blog.Summary.ascx index dbdf5061d..0e1e9c710 100644 --- a/src/Orchard.Web/Modules/Orchard.Blogs/Views/DisplayTemplates/Items/Blogs.Blog.Summary.ascx +++ b/src/Orchard.Web/Modules/Orchard.Blogs/Views/DisplayTemplates/Items/Blogs.Blog.Summary.ascx @@ -4,4 +4,4 @@ <%@ Import Namespace="Orchard.Blogs.Models"%>

<%=Html.Link(Html.Encode(Model.Item.Name), Url.Blog(Model.Item.Slug)) %>

<% if (!string.IsNullOrEmpty(Model.Item.Description)) { %>

<%: Model.Item.Description %>

<% } %> - + diff --git a/src/Orchard.Web/Modules/Orchard.Comments/Extensions/HtmlHelperExtensions.cs b/src/Orchard.Web/Modules/Orchard.Comments/Extensions/HtmlHelperExtensions.cs index f519b9517..eca6edfde 100644 --- a/src/Orchard.Web/Modules/Orchard.Comments/Extensions/HtmlHelperExtensions.cs +++ b/src/Orchard.Web/Modules/Orchard.Comments/Extensions/HtmlHelperExtensions.cs @@ -2,6 +2,7 @@ using System.Web.Mvc; using System.Web.Mvc.Html; using Orchard.ContentManagement; using Orchard.Localization; +using Orchard.Mvc.Html; using Orchard.Utility.Extensions; namespace Orchard.Comments.Extensions { @@ -11,14 +12,14 @@ namespace Orchard.Comments.Extensions { if (item.Id != 0) { var totalCommentCount = commentCount + pendingCount; - + var totalCommentText = T.Plural("1 comment", "{0} comments", totalCommentCount); if (totalCommentCount == 0) { - commentText += html.Encode(T("0 comments")); + commentText += totalCommentText.ToString(); } else { commentText += html.ActionLink( - T("{0} comment{1}", totalCommentCount, totalCommentCount == 1 ? "" : "s").ToString(), + totalCommentText.ToString(), "Details", new { Area = "Orchard.Comments", diff --git a/src/Orchard.Web/Modules/Orchard.Comments/Views/DisplayTemplates/Parts/Comments.Count.ascx b/src/Orchard.Web/Modules/Orchard.Comments/Views/DisplayTemplates/Parts/Comments.Count.ascx index 74163a22b..b0da5d88c 100644 --- a/src/Orchard.Web/Modules/Orchard.Comments/Views/DisplayTemplates/Parts/Comments.Count.ascx +++ b/src/Orchard.Web/Modules/Orchard.Comments/Views/DisplayTemplates/Parts/Comments.Count.ascx @@ -1,3 +1,3 @@ <%@ Control Language="C#" Inherits="Orchard.Mvc.ViewUserControl" %> <%@ Import Namespace="Orchard.Comments.ViewModels"%> -<%: T("{0} Comment{1}", Model.CommentCount, Model.CommentCount == 1 ? "" : "s")%> +<%: T.Plural("1 Comment", "{0} Comments", Model.CommentCount)%> diff --git a/src/Orchard.Web/Modules/Orchard.Comments/Views/DisplayTemplates/Parts/Comments.HasComments.ascx b/src/Orchard.Web/Modules/Orchard.Comments/Views/DisplayTemplates/Parts/Comments.HasComments.ascx index aa0a996b5..f991fc8f5 100644 --- a/src/Orchard.Web/Modules/Orchard.Comments/Views/DisplayTemplates/Parts/Comments.HasComments.ascx +++ b/src/Orchard.Web/Modules/Orchard.Comments/Views/DisplayTemplates/Parts/Comments.HasComments.ascx @@ -5,7 +5,7 @@ <%@ Import Namespace="Orchard.Utility.Extensions" %> <%-- todo: clean up this template - waaay too much going on in here :/ --%><% if (Model.Comments.Count > 0) { %> -

<%: T("{0} Comment{1}", Model.Comments.Count, Model.Comments.Count == 1 ? "" : "s")%>

+

<%: T.Plural("1 Comment", "{0} Comments", Model.Comments.Count)%>

<% Html.RenderPartial("ListOfComments", Model.Comments); } diff --git a/src/Orchard.Web/Themes/Classic/Views/DisplayTemplates/Items/Blogs.Blog.Summary.ascx b/src/Orchard.Web/Themes/Classic/Views/DisplayTemplates/Items/Blogs.Blog.Summary.ascx index 5f1d2a340..35e33132a 100644 --- a/src/Orchard.Web/Themes/Classic/Views/DisplayTemplates/Items/Blogs.Blog.Summary.ascx +++ b/src/Orchard.Web/Themes/Classic/Views/DisplayTemplates/Items/Blogs.Blog.Summary.ascx @@ -4,5 +4,5 @@ <%@ Import Namespace="Orchard.Blogs.Models"%>

<%=Html.Link(Html.Encode(Model.Item.Name), Url.Blog(Model.Item.Slug)) %>

- +

<%: Model.Item.Description %>

diff --git a/src/Orchard.Web/Themes/ClassicDark/Views/DisplayTemplates/Items/Blogs.Blog.Summary.ascx b/src/Orchard.Web/Themes/ClassicDark/Views/DisplayTemplates/Items/Blogs.Blog.Summary.ascx index 5f1d2a340..35e33132a 100644 --- a/src/Orchard.Web/Themes/ClassicDark/Views/DisplayTemplates/Items/Blogs.Blog.Summary.ascx +++ b/src/Orchard.Web/Themes/ClassicDark/Views/DisplayTemplates/Items/Blogs.Blog.Summary.ascx @@ -4,5 +4,5 @@ <%@ Import Namespace="Orchard.Blogs.Models"%>

<%=Html.Link(Html.Encode(Model.Item.Name), Url.Blog(Model.Item.Slug)) %>

- +

<%: Model.Item.Description %>

diff --git a/src/Orchard.Web/Themes/Contoso/Views/DisplayTemplates/Parts/Comments.HasComments.ascx b/src/Orchard.Web/Themes/Contoso/Views/DisplayTemplates/Parts/Comments.HasComments.ascx index 77c91cdeb..37a92c0c5 100644 --- a/src/Orchard.Web/Themes/Contoso/Views/DisplayTemplates/Parts/Comments.HasComments.ascx +++ b/src/Orchard.Web/Themes/Contoso/Views/DisplayTemplates/Parts/Comments.HasComments.ascx @@ -2,9 +2,10 @@ <%@ Import Namespace="Orchard.Comments"%> <%@ Import Namespace="Orchard.Security" %> <%@ Import Namespace="Orchard.Comments.Models" %> + <%-- todo: clean up this template - waaay too much going on in here :/ --%><% if (Model.Comments.Count > 0) { %> -

<%: T("{0} Comment{1}", Model.Comments.Count, Model.Comments.Count == 1 ? "" : "s")%>

+

<%: T.Plural("1 Comment", "{0} Comments", Model.Comments.Count)%>

<% Html.RenderPartial("ListOfComments", Model.Comments); } diff --git a/src/Orchard.Web/Themes/Corporate/Views/DisplayTemplates/Parts/Comments.HasComments.ascx b/src/Orchard.Web/Themes/Corporate/Views/DisplayTemplates/Parts/Comments.HasComments.ascx index 77c91cdeb..77525b3b8 100644 --- a/src/Orchard.Web/Themes/Corporate/Views/DisplayTemplates/Parts/Comments.HasComments.ascx +++ b/src/Orchard.Web/Themes/Corporate/Views/DisplayTemplates/Parts/Comments.HasComments.ascx @@ -4,7 +4,7 @@ <%@ Import Namespace="Orchard.Comments.Models" %> <%-- todo: clean up this template - waaay too much going on in here :/ --%><% if (Model.Comments.Count > 0) { %> -

<%: T("{0} Comment{1}", Model.Comments.Count, Model.Comments.Count == 1 ? "" : "s")%>

+

<%: T.Plural("1 Comment", "{0} Comments", Model.Comments.Count)%>

<% Html.RenderPartial("ListOfComments", Model.Comments); } diff --git a/src/Orchard.Web/Themes/Green/Views/DisplayTemplates/Items/Blogs.Blog.Summary.ascx b/src/Orchard.Web/Themes/Green/Views/DisplayTemplates/Items/Blogs.Blog.Summary.ascx index a8b2731fd..c3b42f92e 100644 --- a/src/Orchard.Web/Themes/Green/Views/DisplayTemplates/Items/Blogs.Blog.Summary.ascx +++ b/src/Orchard.Web/Themes/Green/Views/DisplayTemplates/Items/Blogs.Blog.Summary.ascx @@ -3,5 +3,5 @@ <%@ Import Namespace="Orchard.Blogs.Extensions"%> <%@ Import Namespace="Orchard.Blogs.Models"%>

<%=Html.Link(Html.Encode(Model.Item.Name), Url.Blog(Model.Item.Slug)) %>

- +

<%: Model.Item.Description %>

diff --git a/src/Orchard/Localization/Localizer.cs b/src/Orchard/Localization/Localizer.cs index 0e2221263..2a28913b2 100644 --- a/src/Orchard/Localization/Localizer.cs +++ b/src/Orchard/Localization/Localizer.cs @@ -1,11 +1,15 @@ using System.Linq; +using Orchard.Localization; namespace Orchard.Localization { public delegate LocalizedString Localizer(string text, params object[] args); +} + +namespace Orchard.Mvc.Html { public static class LocalizerExtensions { public static LocalizedString Plural(this Localizer T, string textSingular, string textPlural, int count, params object[] args) { return T(count == 1 ? textSingular : textPlural, new object[] { count }.Concat(args).ToArray()); } } -} +} \ No newline at end of file From 39c62e142fcfd7b2e5e0e4930af4e38996977a4e Mon Sep 17 00:00:00 2001 From: Nathan Heskew Date: Thu, 10 Jun 2010 11:36:44 -0700 Subject: [PATCH 4/8] Localized (and properly pluralized) a couple of HtmlHelper extensions (around friendly published datetimes) --HG-- branch : dev --- .../Extensions/HtmlHelperExtensions.cs | 17 +++++----- .../Items/Blogs.BlogPost.Summary.ascx | 4 +-- .../Items/Blogs.BlogPost.SummaryAdmin.ascx | 11 +++---- .../Blogs.BlogPost.Metadata.Summary.ascx | 2 +- .../Parts/Blogs.BlogPost.Metadata.ascx | 2 +- .../Views/ListOfComments.ascx | 2 +- .../Orchard.Pages/Views/Admin/List.aspx | 9 +++-- .../Orchard.Search/Views/Admin/Index.ascx | 2 +- .../Items/Blogs.BlogPost.Summary.ascx | 4 +-- .../Parts/Blogs.BlogPost.Metadata.ascx | 9 +++-- .../Items/Blogs.BlogPost.Summary.ascx | 4 +-- .../Parts/Blogs.BlogPost.Metadata.ascx | 9 +++-- .../Themes/Contoso/Views/ListOfComments.ascx | 15 ++++----- .../Corporate/Views/ListOfComments.ascx | 15 ++++----- .../Items/Blogs.BlogPost.Summary.ascx | 9 ++--- .../Parts/Blogs.BlogPost.Metadata.ascx | 9 +++-- .../Themes/Green/Views/ListOfComments.ascx | 15 ++++----- src/Orchard/Mvc/Html/HtmlHelperExtensions.cs | 33 ++++++++++--------- 18 files changed, 74 insertions(+), 97 deletions(-) diff --git a/src/Orchard.Web/Modules/Orchard.Blogs/Extensions/HtmlHelperExtensions.cs b/src/Orchard.Web/Modules/Orchard.Blogs/Extensions/HtmlHelperExtensions.cs index 30724ae32..7560d079f 100644 --- a/src/Orchard.Web/Modules/Orchard.Blogs/Extensions/HtmlHelperExtensions.cs +++ b/src/Orchard.Web/Modules/Orchard.Blogs/Extensions/HtmlHelperExtensions.cs @@ -2,24 +2,25 @@ using System.Web.Mvc; using Orchard.Blogs.Models; using Orchard.ContentManagement; using Orchard.ContentManagement.Aspects; +using Orchard.Localization; using Orchard.Mvc.Html; namespace Orchard.Blogs.Extensions { public static class HtmlHelperExtensions { - public static string PublishedState(this HtmlHelper htmlHelper) { - return htmlHelper.PublishedState(htmlHelper.ViewData.Model); + public static LocalizedString PublishedState(this HtmlHelper htmlHelper, Localizer T) { + return htmlHelper.PublishedState(htmlHelper.ViewData.Model, T); } - public static string PublishedState(this HtmlHelper htmlHelper, BlogPost blogPost) { - return htmlHelper.DateTime(blogPost.As().VersionPublishedUtc, "Draft"); + public static LocalizedString PublishedState(this HtmlHelper htmlHelper, BlogPost blogPost, Localizer T) { + return htmlHelper.DateTime(blogPost.As().VersionPublishedUtc, T("Draft")); } - public static string PublishedWhen(this HtmlHelper htmlHelper) { - return htmlHelper.PublishedWhen(htmlHelper.ViewData.Model); + public static LocalizedString PublishedWhen(this HtmlHelper htmlHelper, Localizer T) { + return htmlHelper.PublishedWhen(htmlHelper.ViewData.Model, T); } - public static string PublishedWhen(this HtmlHelper htmlHelper, BlogPost blogPost) { - return htmlHelper.DateTimeRelative(blogPost.As().VersionPublishedUtc, "as a Draft"); + public static LocalizedString PublishedWhen(this HtmlHelper htmlHelper, BlogPost blogPost, Localizer T) { + return htmlHelper.DateTimeRelative(blogPost.As().VersionPublishedUtc, T("as a Draft"), T); } } } \ No newline at end of file diff --git a/src/Orchard.Web/Modules/Orchard.Blogs/Views/DisplayTemplates/Items/Blogs.BlogPost.Summary.ascx b/src/Orchard.Web/Modules/Orchard.Blogs/Views/DisplayTemplates/Items/Blogs.BlogPost.Summary.ascx index 31650d86f..ab3177a20 100644 --- a/src/Orchard.Web/Modules/Orchard.Blogs/Views/DisplayTemplates/Items/Blogs.BlogPost.Summary.ascx +++ b/src/Orchard.Web/Modules/Orchard.Blogs/Views/DisplayTemplates/Items/Blogs.BlogPost.Summary.ascx @@ -1,9 +1,7 @@ <%@ Control Language="C#" Inherits="Orchard.Mvc.ViewUserControl>" %> -<%@ Import Namespace="Orchard.ContentManagement"%> -<%@ Import Namespace="Orchard.Core.Common.Models"%> <%@ Import Namespace="Orchard.Mvc.ViewModels"%> <%@ Import Namespace="Orchard.Blogs.Extensions"%> <%@ Import Namespace="Orchard.Blogs.Models"%>

<%=Html.Link(Html.Encode(Model.Item.Title), Url.BlogPost(Model.Item)) %>

-
<%=Html.PublishedState(Model.Item) %> | <%Html.Zone("meta");%>
+
<%=Html.PublishedState(Model.Item, T) %> | <%Html.Zone("meta");%>
<% Html.Zone("primary", ":manage :metadata");%>
diff --git a/src/Orchard.Web/Modules/Orchard.Blogs/Views/DisplayTemplates/Items/Blogs.BlogPost.SummaryAdmin.ascx b/src/Orchard.Web/Modules/Orchard.Blogs/Views/DisplayTemplates/Items/Blogs.BlogPost.SummaryAdmin.ascx index 748288226..a75a35aa9 100644 --- a/src/Orchard.Web/Modules/Orchard.Blogs/Views/DisplayTemplates/Items/Blogs.BlogPost.SummaryAdmin.ascx +++ b/src/Orchard.Web/Modules/Orchard.Blogs/Views/DisplayTemplates/Items/Blogs.BlogPost.SummaryAdmin.ascx @@ -1,7 +1,6 @@ <%@ Control Language="C#" Inherits="Orchard.Mvc.ViewUserControl>" %> <%@ Import Namespace="Orchard.ContentManagement.Aspects"%> <%@ Import Namespace="Orchard.ContentManagement"%> -<%@ Import Namespace="Orchard.Core.Common.Models"%> <%@ Import Namespace="Orchard.Mvc.ViewModels"%> <%@ Import Namespace="Orchard.Blogs.Extensions"%> <%@ Import Namespace="Orchard.Blogs.Models"%> @@ -11,15 +10,15 @@
  • <% if (Model.Item.HasPublished) { %> - " alt="<%: T("Online") %>" title="<%: T("The page is currently online") %>" /><%: T(" Published")%><% + " alt="<%: T("Online") %>" title="<%: T("The page is currently online") %>" /> <%: T("Published")%><% } else { %> - " alt="<%: T("Offline") %>" title="<%: T("The page is currently offline") %>" /><%: T(" Not Published")%><% + " alt="<%: T("Offline") %>" title="<%: T("The page is currently offline") %>" /> <%: T("Not Published")%><% } %> | 
  • <% if (Model.Item.HasDraft) { %> - " alt="<%: T("Draft") %>" title="<%: T("The post has a draft") %>" /><%=Html.PublishedState(Model.Item)%><% + " alt="<%: T("Draft") %>" title="<%: T("The post has a draft") %>" /><%=Html.PublishedState(Model.Item, T) %><% } else { %> <%: T("No draft")%><% @@ -31,10 +30,10 @@ <%=Html.DateTime(Model.Item.ScheduledPublishUtc.Value, "M/d/yyyy h:mm tt")%><% } else if (Model.Item.IsPublished) { %> - <%: T("Published: ") + Html.DateTimeRelative(Model.Item.As().VersionPublishedUtc.Value)%><% + <%: T("Published: {0}", Html.DateTimeRelative(Model.Item.As().VersionPublishedUtc.Value, T)) %><% } else { %> - <%: T("Last modified: ") + Html.DateTimeRelative(Model.Item.As().ModifiedUtc.Value) %><% + <%: T("Last modified: {0}", Html.DateTimeRelative(Model.Item.As().ModifiedUtc.Value, T)) %><% } %> | 
  • <%: T("By {0}", Model.Item.Creator.UserName)%>
  • diff --git a/src/Orchard.Web/Modules/Orchard.Blogs/Views/DisplayTemplates/Parts/Blogs.BlogPost.Metadata.Summary.ascx b/src/Orchard.Web/Modules/Orchard.Blogs/Views/DisplayTemplates/Parts/Blogs.BlogPost.Metadata.Summary.ascx index c46697732..402274d10 100644 --- a/src/Orchard.Web/Modules/Orchard.Blogs/Views/DisplayTemplates/Parts/Blogs.BlogPost.Metadata.Summary.ascx +++ b/src/Orchard.Web/Modules/Orchard.Blogs/Views/DisplayTemplates/Parts/Blogs.BlogPost.Metadata.Summary.ascx @@ -2,5 +2,5 @@ <%@ Import Namespace="Orchard.Blogs.Extensions"%> <%@ Import Namespace="Orchard.Blogs.Models"%><% if (Model.Creator != null) { - %><%: T("Posted by {0} {1}", Model.Creator.UserName, Html.PublishedWhen(Model)) %> | <% + %><%: T("Posted by {0} {1}", Model.Creator.UserName, Html.PublishedWhen(Model, T)) %> | <% } %> \ No newline at end of file diff --git a/src/Orchard.Web/Modules/Orchard.Blogs/Views/DisplayTemplates/Parts/Blogs.BlogPost.Metadata.ascx b/src/Orchard.Web/Modules/Orchard.Blogs/Views/DisplayTemplates/Parts/Blogs.BlogPost.Metadata.ascx index ae7698531..a54802281 100644 --- a/src/Orchard.Web/Modules/Orchard.Blogs/Views/DisplayTemplates/Parts/Blogs.BlogPost.Metadata.ascx +++ b/src/Orchard.Web/Modules/Orchard.Blogs/Views/DisplayTemplates/Parts/Blogs.BlogPost.Metadata.ascx @@ -3,6 +3,6 @@ <%@ Import Namespace="Orchard.Blogs.Models"%> \ No newline at end of file diff --git a/src/Orchard.Web/Modules/Orchard.Comments/Views/ListOfComments.ascx b/src/Orchard.Web/Modules/Orchard.Comments/Views/ListOfComments.ascx index b92e64e06..789fc37d7 100644 --- a/src/Orchard.Web/Modules/Orchard.Comments/Views/ListOfComments.ascx +++ b/src/Orchard.Web/Modules/Orchard.Comments/Views/ListOfComments.ascx @@ -6,7 +6,7 @@ foreach (var comment in Model) { %>
    <%=Html.LinkOrDefault(Html.Encode(comment.Record.UserName), Html.Encode(comment.Record.SiteName), new { rel = "nofollow" })%> <%-- todo: (heskew) need comment permalink --%> - said <%=Html.Link(Html.DateTimeRelative(comment.Record.CommentDateUtc.GetValueOrDefault()), "#")%> + said <%=Html.Link(Html.DateTimeRelative(comment.Record.CommentDateUtc.GetValueOrDefault(), T).Text, "#")%>
    <%-- todo: (heskew) comment text needs processing depending on comment markup style --%> diff --git a/src/Orchard.Web/Modules/Orchard.Pages/Views/Admin/List.aspx b/src/Orchard.Web/Modules/Orchard.Pages/Views/Admin/List.aspx index 2851aaa6f..f9f514bd2 100644 --- a/src/Orchard.Web/Modules/Orchard.Pages/Views/Admin/List.aspx +++ b/src/Orchard.Web/Modules/Orchard.Pages/Views/Admin/List.aspx @@ -1,7 +1,6 @@ <%@ Page Language="C#" Inherits="Orchard.Mvc.ViewPage" %> <%@ Import Namespace="Orchard.ContentManagement.Aspects"%> <%@ Import Namespace="Orchard.ContentManagement"%> -<%@ Import Namespace="Orchard.Core.Common.Models"%> <%@ Import Namespace="Orchard.Mvc.Html"%> <%@ Import Namespace="Orchard.Pages.ViewModels"%><% Html.RegisterStyle("admin.css"); %> @@ -45,10 +44,10 @@ using (Html.BeginFormAntiForgeryPost()) { %>
  • <% // Published or not if (pageEntry.Page.HasPublished) { %> - " alt="<%: T("Online") %>" title="<%: T("The page is currently online") %>" /><%: T("Published") %> | <% + " alt="<%: T("Online") %>" title="<%: T("The page is currently online") %>" /> <%: T("Published") %> | <% } else { %> - " alt="<%: T("Offline") %>" title="<%: T("The page is currently offline") %>" /><%: T("Not Published")%> | <% + " alt="<%: T("Offline") %>" title="<%: T("The page is currently offline") %>" /> <%: T("Not Published")%> | <% } %>
  • <% @@ -66,10 +65,10 @@ using (Html.BeginFormAntiForgeryPost()) { %> <%=Html.DateTime(pageEntry.Page.ScheduledPublishUtc.Value, "M/d/yyyy h:mm tt")%><% } else if (pageEntry.Page.IsPublished) { %> - <%: T("Published: ") + Html.DateTimeRelative(pageEntry.Page.As().VersionPublishedUtc.Value) %><% + <%: T("Published: {0}", Html.DateTimeRelative(pageEntry.Page.As().VersionPublishedUtc.Value, T)) %><% } else { %> - <%: T("Last modified: ") + Html.DateTimeRelative(pageEntry.Page.As().ModifiedUtc.Value) %><% + <%: T("Last modified: {0}", Html.DateTimeRelative(pageEntry.Page.As().ModifiedUtc.Value, T)) %><% } %> | 
  • <%: T("By {0}", pageEntry.Page.Creator.UserName)%>
  • diff --git a/src/Orchard.Web/Modules/Orchard.Search/Views/Admin/Index.ascx b/src/Orchard.Web/Modules/Orchard.Search/Views/Admin/Index.ascx index 151100a64..e7202166b 100644 --- a/src/Orchard.Web/Modules/Orchard.Search/Views/Admin/Index.ascx +++ b/src/Orchard.Web/Modules/Orchard.Search/Views/Admin/Index.ascx @@ -4,7 +4,7 @@ Html.RegisterStyle("admin.css"); %>

    <%=Html.TitleForPage(T("Search Index Management").ToString()) %>

    <% using (Html.BeginForm("update", "admin", FormMethod.Post, new {area = "Orchard.Search"})) { %>
    -

    <%=T("The search index was last updated {0}. ", Html.DateTimeRelative(Model.IndexUpdatedUtc))%>

    +

    <%=T("The search index was last updated {0}. ", Html.DateTimeRelative(Model.IndexUpdatedUtc, T))%>

    <%=Html.AntiForgeryTokenOrchard() %>
    <% } diff --git a/src/Orchard.Web/Themes/Classic/Views/DisplayTemplates/Items/Blogs.BlogPost.Summary.ascx b/src/Orchard.Web/Themes/Classic/Views/DisplayTemplates/Items/Blogs.BlogPost.Summary.ascx index 2037687d2..637da3b4b 100644 --- a/src/Orchard.Web/Themes/Classic/Views/DisplayTemplates/Items/Blogs.BlogPost.Summary.ascx +++ b/src/Orchard.Web/Themes/Classic/Views/DisplayTemplates/Items/Blogs.BlogPost.Summary.ascx @@ -1,12 +1,10 @@ <%@ Control Language="C#" Inherits="Orchard.Mvc.ViewUserControl>" %> -<%@ Import Namespace="Orchard.ContentManagement"%> -<%@ Import Namespace="Orchard.Core.Common.Models"%> <%@ Import Namespace="Orchard.Mvc.ViewModels"%> <%@ Import Namespace="Orchard.Blogs.Extensions"%> <%@ Import Namespace="Orchard.Blogs.Models"%> <%Model.Zones.AddRenderPartial("zonetest", "ZoneTest", Model); %>

    <%=Html.Link(Html.Encode(Model.Item.Title), Url.BlogPost(Model.Item)) %>

    -
    <%=Html.PublishedState(Model.Item) %> | <%Html.Zone("meta");%>
    +
    <%=Html.PublishedState(Model.Item, T) %> | <%Html.Zone("meta");%>
    <% Html.Zone("primary"); %>
    \ No newline at end of file diff --git a/src/Orchard.Web/Themes/Classic/Views/DisplayTemplates/Parts/Blogs.BlogPost.Metadata.ascx b/src/Orchard.Web/Themes/Classic/Views/DisplayTemplates/Parts/Blogs.BlogPost.Metadata.ascx index 623e3985c..e91472533 100644 --- a/src/Orchard.Web/Themes/Classic/Views/DisplayTemplates/Parts/Blogs.BlogPost.Metadata.ascx +++ b/src/Orchard.Web/Themes/Classic/Views/DisplayTemplates/Parts/Blogs.BlogPost.Metadata.ascx @@ -1,7 +1,6 @@ <%@ Control Language="C#" Inherits="Orchard.Mvc.ViewUserControl" %> <%@ Import Namespace="Orchard.Blogs.Extensions"%> -<%@ Import Namespace="Orchard.Blogs.Models"%> -<% - if (Model.Creator != null) { - %><%: T("Posted by {0} {1}", Model.Creator.UserName, "|", Html.PublishedWhen(Model)) %><% - } %> +<%@ Import Namespace="Orchard.Blogs.Models"%><% +if (Model.Creator != null) { + %><%: T("Posted by {0} {1}", Model.Creator.UserName, Html.PublishedWhen(Model, T)) %><% +} %> \ No newline at end of file diff --git a/src/Orchard.Web/Themes/ClassicDark/Views/DisplayTemplates/Items/Blogs.BlogPost.Summary.ascx b/src/Orchard.Web/Themes/ClassicDark/Views/DisplayTemplates/Items/Blogs.BlogPost.Summary.ascx index 2037687d2..637da3b4b 100644 --- a/src/Orchard.Web/Themes/ClassicDark/Views/DisplayTemplates/Items/Blogs.BlogPost.Summary.ascx +++ b/src/Orchard.Web/Themes/ClassicDark/Views/DisplayTemplates/Items/Blogs.BlogPost.Summary.ascx @@ -1,12 +1,10 @@ <%@ Control Language="C#" Inherits="Orchard.Mvc.ViewUserControl>" %> -<%@ Import Namespace="Orchard.ContentManagement"%> -<%@ Import Namespace="Orchard.Core.Common.Models"%> <%@ Import Namespace="Orchard.Mvc.ViewModels"%> <%@ Import Namespace="Orchard.Blogs.Extensions"%> <%@ Import Namespace="Orchard.Blogs.Models"%> <%Model.Zones.AddRenderPartial("zonetest", "ZoneTest", Model); %>

    <%=Html.Link(Html.Encode(Model.Item.Title), Url.BlogPost(Model.Item)) %>

    -
    <%=Html.PublishedState(Model.Item) %> | <%Html.Zone("meta");%>
    +
    <%=Html.PublishedState(Model.Item, T) %> | <%Html.Zone("meta");%>
    <% Html.Zone("primary"); %>
    \ No newline at end of file diff --git a/src/Orchard.Web/Themes/ClassicDark/Views/DisplayTemplates/Parts/Blogs.BlogPost.Metadata.ascx b/src/Orchard.Web/Themes/ClassicDark/Views/DisplayTemplates/Parts/Blogs.BlogPost.Metadata.ascx index 623e3985c..e91472533 100644 --- a/src/Orchard.Web/Themes/ClassicDark/Views/DisplayTemplates/Parts/Blogs.BlogPost.Metadata.ascx +++ b/src/Orchard.Web/Themes/ClassicDark/Views/DisplayTemplates/Parts/Blogs.BlogPost.Metadata.ascx @@ -1,7 +1,6 @@ <%@ Control Language="C#" Inherits="Orchard.Mvc.ViewUserControl" %> <%@ Import Namespace="Orchard.Blogs.Extensions"%> -<%@ Import Namespace="Orchard.Blogs.Models"%> -<% - if (Model.Creator != null) { - %><%: T("Posted by {0} {1}", Model.Creator.UserName, "|", Html.PublishedWhen(Model)) %><% - } %> +<%@ Import Namespace="Orchard.Blogs.Models"%><% +if (Model.Creator != null) { + %><%: T("Posted by {0} {1}", Model.Creator.UserName, Html.PublishedWhen(Model, T)) %><% +} %> \ No newline at end of file diff --git a/src/Orchard.Web/Themes/Contoso/Views/ListOfComments.ascx b/src/Orchard.Web/Themes/Contoso/Views/ListOfComments.ascx index c86a1eea1..17545b07d 100644 --- a/src/Orchard.Web/Themes/Contoso/Views/ListOfComments.ascx +++ b/src/Orchard.Web/Themes/Contoso/Views/ListOfComments.ascx @@ -3,15 +3,12 @@
      <% foreach (var comment in Model) { %>
    • - -
      -

      <%: comment.Record.CommentText %>

      -
      - -
      -<%=Html.LinkOrDefault(Html.Encode(comment.Record.UserName), Html.Encode(comment.Record.SiteName), new { rel = "nofollow" })%> said <%=Html.Link(Html.DateTimeRelative(comment.Record.CommentDateUtc.GetValueOrDefault()), "#")%> -
      - +
      +

      <%: comment.Record.CommentText %>

      +
      +
      + <%=Html.LinkOrDefault(Html.Encode(comment.Record.UserName), Html.Encode(comment.Record.SiteName), new { rel = "nofollow" })%> said <%=Html.Link(Html.DateTimeRelative(comment.Record.CommentDateUtc.GetValueOrDefault(), T).Text, "#")%> +
    • <% } %>
    diff --git a/src/Orchard.Web/Themes/Corporate/Views/ListOfComments.ascx b/src/Orchard.Web/Themes/Corporate/Views/ListOfComments.ascx index c86a1eea1..17545b07d 100644 --- a/src/Orchard.Web/Themes/Corporate/Views/ListOfComments.ascx +++ b/src/Orchard.Web/Themes/Corporate/Views/ListOfComments.ascx @@ -3,15 +3,12 @@
      <% foreach (var comment in Model) { %>
    • - -
      -

      <%: comment.Record.CommentText %>

      -
      - -
      -<%=Html.LinkOrDefault(Html.Encode(comment.Record.UserName), Html.Encode(comment.Record.SiteName), new { rel = "nofollow" })%> said <%=Html.Link(Html.DateTimeRelative(comment.Record.CommentDateUtc.GetValueOrDefault()), "#")%> -
      - +
      +

      <%: comment.Record.CommentText %>

      +
      +
      + <%=Html.LinkOrDefault(Html.Encode(comment.Record.UserName), Html.Encode(comment.Record.SiteName), new { rel = "nofollow" })%> said <%=Html.Link(Html.DateTimeRelative(comment.Record.CommentDateUtc.GetValueOrDefault(), T).Text, "#")%> +
    • <% } %>
    diff --git a/src/Orchard.Web/Themes/Green/Views/DisplayTemplates/Items/Blogs.BlogPost.Summary.ascx b/src/Orchard.Web/Themes/Green/Views/DisplayTemplates/Items/Blogs.BlogPost.Summary.ascx index 52e19c18c..bd4a18de9 100644 --- a/src/Orchard.Web/Themes/Green/Views/DisplayTemplates/Items/Blogs.BlogPost.Summary.ascx +++ b/src/Orchard.Web/Themes/Green/Views/DisplayTemplates/Items/Blogs.BlogPost.Summary.ascx @@ -1,14 +1,9 @@ <%@ Control Language="C#" Inherits="Orchard.Mvc.ViewUserControl>" %> -<%@ Import Namespace="Orchard.ContentManagement"%> -<%@ Import Namespace="Orchard.Core.Common.Models"%> <%@ Import Namespace="Orchard.Mvc.ViewModels"%> <%@ Import Namespace="Orchard.Blogs.Extensions"%> <%@ Import Namespace="Orchard.Blogs.Models"%> -

    <%=Html.Link(Html.Encode(Model.Item.Title), Url.BlogPost(Model.Item)) %>

    - -
    <%=Html.PublishedState(Model.Item) %> | <%Html.Zone("meta");%>
    - +
    <%=Html.PublishedState(Model.Item, T) %> | <%Html.Zone("meta");%>
    <% Html.Zone("primary"); %> -
    +
    \ No newline at end of file diff --git a/src/Orchard.Web/Themes/Green/Views/DisplayTemplates/Parts/Blogs.BlogPost.Metadata.ascx b/src/Orchard.Web/Themes/Green/Views/DisplayTemplates/Parts/Blogs.BlogPost.Metadata.ascx index 623e3985c..e91472533 100644 --- a/src/Orchard.Web/Themes/Green/Views/DisplayTemplates/Parts/Blogs.BlogPost.Metadata.ascx +++ b/src/Orchard.Web/Themes/Green/Views/DisplayTemplates/Parts/Blogs.BlogPost.Metadata.ascx @@ -1,7 +1,6 @@ <%@ Control Language="C#" Inherits="Orchard.Mvc.ViewUserControl" %> <%@ Import Namespace="Orchard.Blogs.Extensions"%> -<%@ Import Namespace="Orchard.Blogs.Models"%> -<% - if (Model.Creator != null) { - %><%: T("Posted by {0} {1}", Model.Creator.UserName, "|", Html.PublishedWhen(Model)) %><% - } %> +<%@ Import Namespace="Orchard.Blogs.Models"%><% +if (Model.Creator != null) { + %><%: T("Posted by {0} {1}", Model.Creator.UserName, Html.PublishedWhen(Model, T)) %><% +} %> \ No newline at end of file diff --git a/src/Orchard.Web/Themes/Green/Views/ListOfComments.ascx b/src/Orchard.Web/Themes/Green/Views/ListOfComments.ascx index c86a1eea1..17545b07d 100644 --- a/src/Orchard.Web/Themes/Green/Views/ListOfComments.ascx +++ b/src/Orchard.Web/Themes/Green/Views/ListOfComments.ascx @@ -3,15 +3,12 @@
      <% foreach (var comment in Model) { %>
    • - -
      -

      <%: comment.Record.CommentText %>

      -
      - -
      -<%=Html.LinkOrDefault(Html.Encode(comment.Record.UserName), Html.Encode(comment.Record.SiteName), new { rel = "nofollow" })%> said <%=Html.Link(Html.DateTimeRelative(comment.Record.CommentDateUtc.GetValueOrDefault()), "#")%> -
      - +
      +

      <%: comment.Record.CommentText %>

      +
      +
      + <%=Html.LinkOrDefault(Html.Encode(comment.Record.UserName), Html.Encode(comment.Record.SiteName), new { rel = "nofollow" })%> said <%=Html.Link(Html.DateTimeRelative(comment.Record.CommentDateUtc.GetValueOrDefault(), T).Text, "#")%> +
    • <% } %>
    diff --git a/src/Orchard/Mvc/Html/HtmlHelperExtensions.cs b/src/Orchard/Mvc/Html/HtmlHelperExtensions.cs index b38925545..cdd150db4 100644 --- a/src/Orchard/Mvc/Html/HtmlHelperExtensions.cs +++ b/src/Orchard/Mvc/Html/HtmlHelperExtensions.cs @@ -7,6 +7,7 @@ using System.Web.Mvc; using System.Web.Mvc.Html; using System.Web.Routing; using Orchard.Collections; +using Orchard.Localization; using Orchard.Mvc.ViewModels; using Orchard.Services; using Orchard.Settings; @@ -178,44 +179,44 @@ namespace Orchard.Mvc.Html { #region Format Date/Time - public static string DateTimeRelative(this HtmlHelper htmlHelper, DateTime? value, string defaultIfNull) { - return value.HasValue ? htmlHelper.DateTimeRelative(value.Value) : defaultIfNull; + public static LocalizedString DateTimeRelative(this HtmlHelper htmlHelper, DateTime? value, LocalizedString defaultIfNull, Localizer T) { + return value.HasValue ? htmlHelper.DateTimeRelative(value.Value, T) : defaultIfNull; } //TODO: (erikpo) This method needs localized - public static string DateTimeRelative(this HtmlHelper htmlHelper, DateTime value) { - TimeSpan time = htmlHelper.Resolve().UtcNow - value; + public static LocalizedString DateTimeRelative(this HtmlHelper htmlHelper, DateTime value, Localizer T) { + var time = htmlHelper.Resolve().UtcNow - value; if (time.TotalDays > 7) - return "on " + htmlHelper.DateTime(value, "MMM d yyyy 'at' h:mm tt"); + return htmlHelper.DateTime(value, T("'on' MMM d yyyy 'at' h:mm tt")); if (time.TotalHours > 24) - return string.Format("{0} day{1} ago", time.Days, time.Days == 1 ? "" : "s"); + return T.Plural("1 day ago", "{0} days ago", time.Days); if (time.TotalMinutes > 60) - return string.Format("{0} hour{1} ago", time.Hours, time.Hours == 1 ? "" : "s"); + return T.Plural("1 hour ago", "{0} hours ago", time.Hours); if (time.TotalSeconds > 60) - return string.Format("{0} minute{1} ago", time.Minutes, time.Minutes == 1 ? "" : "s"); + return T.Plural("1 minute ago", "{0} minutes ago", time.Minutes); if (time.TotalSeconds > 10) - return string.Format("{0} second{1} ago", time.Seconds, time.Seconds == 1 ? "" : "s"); + return T.Plural("1 second ago", "{0} seconds ago", time.Seconds); - return "a moment ago"; + return T("a moment ago"); } - public static string DateTime(this HtmlHelper htmlHelper, DateTime? value, string defaultIfNull) { + public static LocalizedString DateTime(this HtmlHelper htmlHelper, DateTime? value, LocalizedString defaultIfNull) { return value.HasValue ? htmlHelper.DateTime(value.Value) : defaultIfNull; } - public static string DateTime(this HtmlHelper htmlHelper, DateTime? value, string defaultIfNull, string customFormat) { + public static LocalizedString DateTime(this HtmlHelper htmlHelper, DateTime? value, LocalizedString defaultIfNull, LocalizedString customFormat) { return value.HasValue ? htmlHelper.DateTime(value.Value, customFormat) : defaultIfNull; } - public static string DateTime(this HtmlHelper htmlHelper, DateTime value) { + public static LocalizedString DateTime(this HtmlHelper htmlHelper, DateTime value) { //TODO: (erikpo) This default format should come from a site setting - return htmlHelper.DateTime(value, "MMM d yyyy h:mm tt"); + return htmlHelper.DateTime(value, new LocalizedString("MMM d yyyy h:mm tt")); //todo: above comment and get rid of just wrapping this as a localized string } - public static string DateTime(this HtmlHelper htmlHelper, DateTime value, string customFormat) { + public static LocalizedString DateTime(this HtmlHelper htmlHelper, DateTime value, LocalizedString customFormat) { //TODO: (erikpo) In the future, convert this to "local" time before calling ToString - return value.ToString(customFormat); + return value.ToString(customFormat.Text); } #endregion From e250b036fd7eb1d6db494763e9bef97488fcca76 Mon Sep 17 00:00:00 2001 From: Nathan Heskew Date: Thu, 10 Jun 2010 13:21:28 -0700 Subject: [PATCH 5/8] A couple of minor tweaks to the site culter management UI --HG-- branch : dev --- src/Orchard.Web/Core/Settings/Views/Admin/Culture.ascx | 2 +- .../Core/Settings/Views/DisplayTemplates/RemovableCulture.ascx | 2 +- src/Orchard/Mvc/Html/HtmlHelperExtensions.cs | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/Orchard.Web/Core/Settings/Views/Admin/Culture.ascx b/src/Orchard.Web/Core/Settings/Views/Admin/Culture.ascx index 452c8091e..dfc855c5c 100644 --- a/src/Orchard.Web/Core/Settings/Views/Admin/Culture.ascx +++ b/src/Orchard.Web/Core/Settings/Views/Admin/Culture.ascx @@ -10,7 +10,7 @@ <% using (Html.BeginFormAntiForgeryPost("AddCulture")) { %> <%:Html.ValidationSummary() %>
    - <%:T("Add a culture...") %> + <%:Html.DropDownList("CultureName", new SelectList(Model.AvailableSystemCultures.OrderBy(s => s), Model.CurrentCulture)) %>
    diff --git a/src/Orchard.Web/Core/Settings/Views/DisplayTemplates/RemovableCulture.ascx b/src/Orchard.Web/Core/Settings/Views/DisplayTemplates/RemovableCulture.ascx index 3abc6bfdf..7de8fff75 100644 --- a/src/Orchard.Web/Core/Settings/Views/DisplayTemplates/RemovableCulture.ascx +++ b/src/Orchard.Web/Core/Settings/Views/DisplayTemplates/RemovableCulture.ascx @@ -2,5 +2,5 @@
    <%:Model %>
    <% using (Html.BeginFormAntiForgeryPost(Url.Action("DeleteCulture", "Admin", new { area = "Settings" }), FormMethod.Post, new {@class = "inline link"})) { %> <%=Html.Hidden("cultureName", Model, new { id = "" }) %> - + <% } %> \ No newline at end of file diff --git a/src/Orchard/Mvc/Html/HtmlHelperExtensions.cs b/src/Orchard/Mvc/Html/HtmlHelperExtensions.cs index cdd150db4..bc38d3340 100644 --- a/src/Orchard/Mvc/Html/HtmlHelperExtensions.cs +++ b/src/Orchard/Mvc/Html/HtmlHelperExtensions.cs @@ -196,7 +196,7 @@ namespace Orchard.Mvc.Html { if (time.TotalSeconds > 60) return T.Plural("1 minute ago", "{0} minutes ago", time.Minutes); if (time.TotalSeconds > 10) - return T.Plural("1 second ago", "{0} seconds ago", time.Seconds); + return T.Plural("1 second ago", "{0} seconds ago", time.Seconds); //aware that the singular won't be used return T("a moment ago"); } From 1429574665a842d464ce0344fa0511326590c1b6 Mon Sep 17 00:00:00 2001 From: Suha Can Date: Thu, 10 Jun 2010 13:38:17 -0700 Subject: [PATCH 6/8] - Infrastructure work towards ContentFields. - Saving/Saved events - Some work on the content field definition, driver, driver handlers... --HG-- branch : dev --- src/Orchard/ContentManagement/ContentField.cs | 13 ++++- src/Orchard/ContentManagement/ContentPart.cs | 3 + .../Drivers/ContentFieldDriver.cs | 51 +++++++++++++++++ .../Drivers/ContentFieldDriverHandler.cs | 42 ++++++++++++++ .../Drivers/ContentFieldTemplateResult.cs | 56 +++++++++++++++++++ .../Drivers/ContentPartDriverHandler.cs | 1 - .../Handlers/ContentHandler.cs | 31 ++++++++++ .../Handlers/ContentHandlerBase.cs | 9 ++- .../Handlers/IContentHandler.cs | 6 +- .../Handlers/IContentStorageFilter.cs | 2 + .../Handlers/SaveContentContext.cs | 12 ++++ .../Handlers/StorageFilterBase.cs | 12 ++++ .../MetaData/Models/ContentPartDefinition.cs | 3 +- src/Orchard/Orchard.Framework.csproj | 4 ++ 14 files changed, 235 insertions(+), 10 deletions(-) create mode 100644 src/Orchard/ContentManagement/Drivers/ContentFieldDriver.cs create mode 100644 src/Orchard/ContentManagement/Drivers/ContentFieldDriverHandler.cs create mode 100644 src/Orchard/ContentManagement/Drivers/ContentFieldTemplateResult.cs create mode 100644 src/Orchard/ContentManagement/Handlers/SaveContentContext.cs diff --git a/src/Orchard/ContentManagement/ContentField.cs b/src/Orchard/ContentManagement/ContentField.cs index 671ac54fd..169119fdf 100644 --- a/src/Orchard/ContentManagement/ContentField.cs +++ b/src/Orchard/ContentManagement/ContentField.cs @@ -1,8 +1,17 @@ -using Orchard.ContentManagement.MetaData.Models; +using System.Collections.Generic; +using Orchard.ContentManagement.MetaData.Models; +using Orchard.ContentManagement.Utilities; namespace Orchard.ContentManagement { - public class ContentField { + public class ContentField : IContent { + public virtual ContentItem ContentItem { get; set;} public string Name { get; set; } public ContentFieldDefinition Definition { get; set; } + public IDictionary Settings { get; private set; } + } + + public class ContentField : ContentField { + public readonly LazyField _record = new LazyField(); + public TRecord Record { get { return _record.Value; } set { _record.Value = value; } } } } diff --git a/src/Orchard/ContentManagement/ContentPart.cs b/src/Orchard/ContentManagement/ContentPart.cs index 8f485aa9a..4ec9ad23d 100644 --- a/src/Orchard/ContentManagement/ContentPart.cs +++ b/src/Orchard/ContentManagement/ContentPart.cs @@ -1,3 +1,4 @@ +using System.Collections.Generic; using Orchard.ContentManagement.MetaData.Models; using Orchard.ContentManagement.Utilities; @@ -7,6 +8,8 @@ namespace Orchard.ContentManagement { public ContentTypeDefinition TypeDefinition { get { return ContentItem.TypeDefinition; } } public ContentTypeDefinition.Part TypePartDefinition { get; set; } public ContentPartDefinition PartDefinition { get { return TypePartDefinition.PartDefinition; } } + + public IEnumerable ContentFields { get; set; } } public class ContentPart : ContentPart { diff --git a/src/Orchard/ContentManagement/Drivers/ContentFieldDriver.cs b/src/Orchard/ContentManagement/Drivers/ContentFieldDriver.cs new file mode 100644 index 000000000..91d42a0be --- /dev/null +++ b/src/Orchard/ContentManagement/Drivers/ContentFieldDriver.cs @@ -0,0 +1,51 @@ +using Orchard.ContentManagement.Handlers; + +namespace Orchard.ContentManagement.Drivers { + + public interface IContentFieldDriver : IEvents { + DriverResult BuildDisplayModel(BuildDisplayModelContext context); + DriverResult BuildEditorModel(BuildEditorModelContext context); + DriverResult UpdateEditorModel(UpdateEditorModelContext context); + } + + public abstract class ContentFieldDriver : IContentFieldDriver where TContent : ContentField, new() { + protected virtual string Prefix { get { return ""; } } + protected virtual string Zone { get { return "body"; } } + + DriverResult IContentFieldDriver.BuildDisplayModel(BuildDisplayModelContext context) { + var field = context.ContentItem.As(); + return field == null ? null : Display(field, context.DisplayType); + } + + DriverResult IContentFieldDriver.BuildEditorModel(BuildEditorModelContext context) { + var field = context.ContentItem.As(); + return field == null ? null : Editor(field); + } + + DriverResult IContentFieldDriver.UpdateEditorModel(UpdateEditorModelContext context) { + var field = context.ContentItem.As(); + return field == null ? null : Editor(field, context.Updater); + } + + protected virtual DriverResult Display(TContent field, string displayType) { return null; } + protected virtual DriverResult Editor(TContent field) { return null; } + protected virtual DriverResult Editor(TContent field, IUpdateModel updater) { return null; } + + + public ContentFieldTemplateResult ContentPartTemplate(object model) { + return new ContentFieldTemplateResult(model, null, Prefix).Location(Zone); + } + + public ContentFieldTemplateResult ContentPartTemplate(object model, string template) { + return new ContentFieldTemplateResult(model, template, Prefix).Location(Zone); + } + + public ContentFieldTemplateResult ContentPartTemplate(object model, string template, string prefix) { + return new ContentFieldTemplateResult(model, template, prefix).Location(Zone); + } + + public CombinedResult Combined(params DriverResult[] results) { + return new CombinedResult(results); + } + } +} \ No newline at end of file diff --git a/src/Orchard/ContentManagement/Drivers/ContentFieldDriverHandler.cs b/src/Orchard/ContentManagement/Drivers/ContentFieldDriverHandler.cs new file mode 100644 index 000000000..89c1da793 --- /dev/null +++ b/src/Orchard/ContentManagement/Drivers/ContentFieldDriverHandler.cs @@ -0,0 +1,42 @@ +using System.Collections.Generic; +using JetBrains.Annotations; +using Orchard.ContentManagement.Handlers; +using Orchard.Logging; + +namespace Orchard.ContentManagement.Drivers { + [UsedImplicitly] + public class ContentFieldDriverHandler : ContentHandlerBase { + private readonly IEnumerable _drivers; + + public ContentFieldDriverHandler(IEnumerable drivers) { + _drivers = drivers; + Logger = NullLogger.Instance; + } + + public ILogger Logger { get; set; } + + public override void BuildDisplayModel(BuildDisplayModelContext context) { + _drivers.Invoke(driver => { + var result = driver.BuildDisplayModel(context); + if (result != null) + result.Apply(context); + }, Logger); + } + + public override void BuildEditorModel(BuildEditorModelContext context) { + _drivers.Invoke(driver => { + var result = driver.BuildEditorModel(context); + if (result != null) + result.Apply(context); + }, Logger); + } + + public override void UpdateEditorModel(UpdateEditorModelContext context) { + _drivers.Invoke(driver => { + var result = driver.UpdateEditorModel(context); + if (result != null) + result.Apply(context); + }, Logger); + } + } +} \ No newline at end of file diff --git a/src/Orchard/ContentManagement/Drivers/ContentFieldTemplateResult.cs b/src/Orchard/ContentManagement/Drivers/ContentFieldTemplateResult.cs new file mode 100644 index 000000000..e94241b5e --- /dev/null +++ b/src/Orchard/ContentManagement/Drivers/ContentFieldTemplateResult.cs @@ -0,0 +1,56 @@ +using System.Linq; +using Orchard.ContentManagement.Handlers; + +namespace Orchard.ContentManagement.Drivers { + public class ContentFieldTemplateResult : DriverResult { + public object Model { get; set; } + public string TemplateName { get; set; } + public string Prefix { get; set; } + public string Zone { get; set; } + public string Position { get; set; } + + public ContentFieldTemplateResult(object model, string templateName, string prefix) { + Model = model; + TemplateName = templateName; + Prefix = prefix; + } + + public override void Apply(BuildDisplayModelContext context) { + context.ViewModel.Zones.AddDisplayPart( + Zone + ":" + Position, Model, TemplateName, Prefix); + } + + public override void Apply(BuildEditorModelContext context) { + context.ViewModel.Zones.AddEditorPart( + Zone + ":" + Position, Model, TemplateName, Prefix); + } + + public ContentFieldTemplateResult Location(string zone) { + Zone = zone; + return this; + } + + public ContentFieldTemplateResult Location(string zone, string position) { + Zone = zone; + Position = position; + return this; + } + + public ContentFieldTemplateResult LongestMatch(string displayType, params string[] knownDisplayTypes) { + + if (string.IsNullOrEmpty(displayType)) + return this; + + var longest = knownDisplayTypes.Aggregate("", (best, x) => { + if (displayType.StartsWith(x) && x.Length > best.Length) return x; + return best; + }); + + if (string.IsNullOrEmpty(longest)) + return this; + + TemplateName += "." + longest; + return this; + } + } +} \ No newline at end of file diff --git a/src/Orchard/ContentManagement/Drivers/ContentPartDriverHandler.cs b/src/Orchard/ContentManagement/Drivers/ContentPartDriverHandler.cs index eb6cc6130..119ac4b48 100644 --- a/src/Orchard/ContentManagement/Drivers/ContentPartDriverHandler.cs +++ b/src/Orchard/ContentManagement/Drivers/ContentPartDriverHandler.cs @@ -1,5 +1,4 @@ using System.Collections.Generic; -using System.Linq; using JetBrains.Annotations; using Orchard.ContentManagement.Handlers; using Orchard.Logging; diff --git a/src/Orchard/ContentManagement/Handlers/ContentHandler.cs b/src/Orchard/ContentManagement/Handlers/ContentHandler.cs index 61264e60f..630c41f0d 100644 --- a/src/Orchard/ContentManagement/Handlers/ContentHandler.cs +++ b/src/Orchard/ContentManagement/Handlers/ContentHandler.cs @@ -25,6 +25,14 @@ namespace Orchard.ContentManagement.Handlers { Filters.Add(new InlineStorageFilter { OnCreated = handler }); } + protected void OnSaving(Action handler) where TPart : class, IContent { + Filters.Add(new InlineStorageFilter { OnSaving = handler }); + } + + protected void OnSaved(Action handler) where TPart : class, IContent { + Filters.Add(new InlineStorageFilter { OnSaved = handler }); + } + protected void OnLoading(Action handler) where TPart : class, IContent { Filters.Add(new InlineStorageFilter { OnLoading = handler }); } @@ -84,6 +92,8 @@ namespace Orchard.ContentManagement.Handlers { public Action OnActivated { get; set; } public Action OnCreating { get; set; } public Action OnCreated { get; set; } + public Action OnSaving { get; set; } + public Action OnSaved { get; set; } public Action OnLoading { get; set; } public Action OnLoaded { get; set; } public Action OnVersioning { get; set; } @@ -103,6 +113,12 @@ namespace Orchard.ContentManagement.Handlers { protected override void Created(CreateContentContext context, TPart instance) { if (OnCreated != null) OnCreated(context, instance); } + protected override void Saving(SaveContentContext context, TPart instance) { + if (OnSaving != null) OnSaving(context, instance); + } + protected override void Saved(SaveContentContext context, TPart instance) { + if (OnSaved != null) OnSaved(context, instance); + } protected override void Loading(LoadContentContext context, TPart instance) { if (OnLoading != null) OnLoading(context, instance); } @@ -185,6 +201,18 @@ namespace Orchard.ContentManagement.Handlers { Created(context); } + void IContentHandler.Saving(SaveContentContext context) { + foreach (var filter in Filters.OfType()) + filter.Saving(context); + Saving(context); + } + + void IContentHandler.Saved(SaveContentContext context) { + foreach (var filter in Filters.OfType()) + filter.Saved(context); + Saved(context); + } + void IContentHandler.Loading(LoadContentContext context) { foreach (var filter in Filters.OfType()) filter.Loading(context); @@ -272,6 +300,9 @@ namespace Orchard.ContentManagement.Handlers { protected virtual void Creating(CreateContentContext context) { } protected virtual void Created(CreateContentContext context) { } + protected virtual void Saving(SaveContentContext context) { } + protected virtual void Saved(SaveContentContext context) { } + protected virtual void Loading(LoadContentContext context) { } protected virtual void Loaded(LoadContentContext context) { } diff --git a/src/Orchard/ContentManagement/Handlers/ContentHandlerBase.cs b/src/Orchard/ContentManagement/Handlers/ContentHandlerBase.cs index f8026393a..a75ef9ed3 100644 --- a/src/Orchard/ContentManagement/Handlers/ContentHandlerBase.cs +++ b/src/Orchard/ContentManagement/Handlers/ContentHandlerBase.cs @@ -1,5 +1,4 @@ -using System; -using System.Collections.Generic; +using System.Collections.Generic; using System.Linq; namespace Orchard.ContentManagement.Handlers { @@ -20,6 +19,12 @@ namespace Orchard.ContentManagement.Handlers { public virtual void Created(CreateContentContext context) { } + public virtual void Saving(SaveContentContext context) { + } + + public virtual void Saved(SaveContentContext context) { + } + public virtual void Loading(LoadContentContext context) { } diff --git a/src/Orchard/ContentManagement/Handlers/IContentHandler.cs b/src/Orchard/ContentManagement/Handlers/IContentHandler.cs index 7dc37cfa7..03cc514b8 100644 --- a/src/Orchard/ContentManagement/Handlers/IContentHandler.cs +++ b/src/Orchard/ContentManagement/Handlers/IContentHandler.cs @@ -1,6 +1,4 @@ -using System; -using System.Collections.Generic; -using Orchard.Events; +using System.Collections.Generic; namespace Orchard.ContentManagement.Handlers { public interface IContentHandler : IEvents { @@ -10,6 +8,8 @@ namespace Orchard.ContentManagement.Handlers { void Activated(ActivatedContentContext context); void Creating(CreateContentContext context); void Created(CreateContentContext context); + void Saving(SaveContentContext context); + void Saved(SaveContentContext context); void Loading(LoadContentContext context); void Loaded(LoadContentContext context); void Versioning(VersionContentContext context); diff --git a/src/Orchard/ContentManagement/Handlers/IContentStorageFilter.cs b/src/Orchard/ContentManagement/Handlers/IContentStorageFilter.cs index a3bbe7b40..b4ddfbdef 100644 --- a/src/Orchard/ContentManagement/Handlers/IContentStorageFilter.cs +++ b/src/Orchard/ContentManagement/Handlers/IContentStorageFilter.cs @@ -3,6 +3,8 @@ namespace Orchard.ContentManagement.Handlers { void Activated(ActivatedContentContext context); void Creating(CreateContentContext context); void Created(CreateContentContext context); + void Saving(SaveContentContext context); + void Saved(SaveContentContext context); void Loading(LoadContentContext context); void Loaded(LoadContentContext context); void Versioning(VersionContentContext context); diff --git a/src/Orchard/ContentManagement/Handlers/SaveContentContext.cs b/src/Orchard/ContentManagement/Handlers/SaveContentContext.cs new file mode 100644 index 000000000..0cbe96598 --- /dev/null +++ b/src/Orchard/ContentManagement/Handlers/SaveContentContext.cs @@ -0,0 +1,12 @@ +using Orchard.ContentManagement.Records; + +namespace Orchard.ContentManagement.Handlers { + public class SaveContentContext : ContentContextBase { + public SaveContentContext(ContentItem contentItem) + : base(contentItem) { + ContentItemVersionRecord = contentItem.VersionRecord; + } + + public ContentItemVersionRecord ContentItemVersionRecord { get; set; } + } +} diff --git a/src/Orchard/ContentManagement/Handlers/StorageFilterBase.cs b/src/Orchard/ContentManagement/Handlers/StorageFilterBase.cs index d63e0e4a7..ae0884097 100644 --- a/src/Orchard/ContentManagement/Handlers/StorageFilterBase.cs +++ b/src/Orchard/ContentManagement/Handlers/StorageFilterBase.cs @@ -4,6 +4,8 @@ namespace Orchard.ContentManagement.Handlers { protected virtual void Activated(ActivatedContentContext context, TPart instance) { } protected virtual void Creating(CreateContentContext context, TPart instance) { } protected virtual void Created(CreateContentContext context, TPart instance) { } + protected virtual void Saving(SaveContentContext context, TPart instance) { } + protected virtual void Saved(SaveContentContext context, TPart instance) { } protected virtual void Loading(LoadContentContext context, TPart instance) { } protected virtual void Loaded(LoadContentContext context, TPart instance) { } protected virtual void Versioning(VersionContentContext context, TPart existing, TPart building) { } @@ -31,6 +33,16 @@ namespace Orchard.ContentManagement.Handlers { Created(context, context.ContentItem.As()); } + void IContentStorageFilter.Saving(SaveContentContext context) { + if (context.ContentItem.Is()) + Saving(context, context.ContentItem.As()); + } + + void IContentStorageFilter.Saved(SaveContentContext context) { + if (context.ContentItem.Is()) + Saved(context, context.ContentItem.As()); + } + void IContentStorageFilter.Loading(LoadContentContext context) { if (context.ContentItem.Is()) Loading(context, context.ContentItem.As()); diff --git a/src/Orchard/ContentManagement/MetaData/Models/ContentPartDefinition.cs b/src/Orchard/ContentManagement/MetaData/Models/ContentPartDefinition.cs index dd8bd4e9c..c49981ce2 100644 --- a/src/Orchard/ContentManagement/MetaData/Models/ContentPartDefinition.cs +++ b/src/Orchard/ContentManagement/MetaData/Models/ContentPartDefinition.cs @@ -1,5 +1,4 @@ -using System; -using System.Collections.Generic; +using System.Collections.Generic; using System.Linq; using Orchard.Utility.Extensions; diff --git a/src/Orchard/Orchard.Framework.csproj b/src/Orchard/Orchard.Framework.csproj index 4245c8db9..81057cf39 100644 --- a/src/Orchard/Orchard.Framework.csproj +++ b/src/Orchard/Orchard.Framework.csproj @@ -170,6 +170,9 @@ Code + + + Code @@ -255,6 +258,7 @@ Code + Code From 1b97fa04d03d5f2194039b1487de7aec6ca920b5 Mon Sep 17 00:00:00 2001 From: Nathan Heskew Date: Thu, 10 Jun 2010 13:58:12 -0700 Subject: [PATCH 7/8] Adding a breadcrumb on the site culture management page --HG-- branch : dev --- src/Orchard.Web/Core/Settings/Views/Admin/Culture.ascx | 3 ++- src/Orchard.Web/Themes/TheAdmin/Styles/site.css | 3 +++ 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/src/Orchard.Web/Core/Settings/Views/Admin/Culture.ascx b/src/Orchard.Web/Core/Settings/Views/Admin/Culture.ascx index dfc855c5c..2ffdd3fad 100644 --- a/src/Orchard.Web/Core/Settings/Views/Admin/Culture.ascx +++ b/src/Orchard.Web/Core/Settings/Views/Admin/Culture.ascx @@ -1,7 +1,8 @@ <%@ Control Language="C#" Inherits="Orchard.Mvc.ViewUserControl" %> <%@ Import Namespace="Orchard.Core.Settings.ViewModels" %><% Html.RegisterStyle("admin.css"); %> -

    <%:Html.TitleForPage(T("Manage Settings").ToString()) %>

    +

    <%:Html.TitleForPage(T("Supported Cultures").ToString()) %>

    +

    <%:T("Cultures this site supports") %>

    <%=Html.UnorderedList( Model.SiteCultures.OrderBy(s => s), diff --git a/src/Orchard.Web/Themes/TheAdmin/Styles/site.css b/src/Orchard.Web/Themes/TheAdmin/Styles/site.css index e692f8aeb..58829e83f 100644 --- a/src/Orchard.Web/Themes/TheAdmin/Styles/site.css +++ b/src/Orchard.Web/Themes/TheAdmin/Styles/site.css @@ -721,6 +721,9 @@ table .button { /* ---------- Generic ---------- */ +#main .breadcrumb { + margin-top:-1.5em; +} /* todo: needed? */ .clearBoth { clear:both; From 3aa7683e3aad5d8770e38bcc81632432f2cfe52d Mon Sep 17 00:00:00 2001 From: Suha Can Date: Thu, 10 Jun 2010 14:58:49 -0700 Subject: [PATCH 8/8] - Adding fields list to part, has/get/weld methods for ContentPart. - ContentPartDefinition.Field. --HG-- branch : dev --- src/Orchard/ContentManagement/ContentField.cs | 9 ++++--- src/Orchard/ContentManagement/ContentPart.cs | 26 ++++++++++++++++++- 2 files changed, 31 insertions(+), 4 deletions(-) diff --git a/src/Orchard/ContentManagement/ContentField.cs b/src/Orchard/ContentManagement/ContentField.cs index 169119fdf..e1edebb52 100644 --- a/src/Orchard/ContentManagement/ContentField.cs +++ b/src/Orchard/ContentManagement/ContentField.cs @@ -3,11 +3,14 @@ using Orchard.ContentManagement.MetaData.Models; using Orchard.ContentManagement.Utilities; namespace Orchard.ContentManagement { - public class ContentField : IContent { - public virtual ContentItem ContentItem { get; set;} + public class ContentField : ContentPart { + public virtual ContentPart ContentPart { get; set; } public string Name { get; set; } - public ContentFieldDefinition Definition { get; set; } public IDictionary Settings { get; private set; } + + public new ContentPartDefinition PartDefinition { get { return ContentPart.PartDefinition; } } + public ContentPartDefinition.Field PartFieldDefinition { get; set; } + public ContentFieldDefinition FieldDefinition { get { return PartFieldDefinition.FieldDefinition; } } } public class ContentField : ContentField { diff --git a/src/Orchard/ContentManagement/ContentPart.cs b/src/Orchard/ContentManagement/ContentPart.cs index 4ec9ad23d..5c3f35728 100644 --- a/src/Orchard/ContentManagement/ContentPart.cs +++ b/src/Orchard/ContentManagement/ContentPart.cs @@ -1,15 +1,39 @@ +using System; using System.Collections.Generic; +using System.Linq; using Orchard.ContentManagement.MetaData.Models; using Orchard.ContentManagement.Utilities; namespace Orchard.ContentManagement { public abstract class ContentPart : IContent { + private readonly IList _fields; + + public ContentPart() { + _fields = new List(); + } + public virtual ContentItem ContentItem { get; set; } public ContentTypeDefinition TypeDefinition { get { return ContentItem.TypeDefinition; } } public ContentTypeDefinition.Part TypePartDefinition { get; set; } public ContentPartDefinition PartDefinition { get { return TypePartDefinition.PartDefinition; } } - public IEnumerable ContentFields { get; set; } + public IEnumerable Fields { get { return _fields; } } + + + public bool Has(Type fieldType) { + return fieldType == typeof(ContentItem) || _fields.Any(field => fieldType.IsAssignableFrom(field.GetType())); + } + + public IContent Get(Type fieldType) { + if (fieldType == typeof(ContentItem)) + return this; + return _fields.FirstOrDefault(field => fieldType.IsAssignableFrom(field.GetType())); + } + + public void Weld(ContentField field) { + field.ContentPart = this; + _fields.Add(field); + } } public class ContentPart : ContentPart {